simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

events-once.js (6115B)


      1 'use strict';
      2 
      3 var common = require('./common');
      4 var EventEmitter = require('../').EventEmitter;
      5 var once = require('../').once;
      6 var has = require('has');
      7 var assert = require('assert');
      8 
      9 function Event(type) {
     10   this.type = type;
     11 }
     12 
     13 function EventTargetMock() {
     14   this.events = {};
     15 
     16   this.addEventListener = common.mustCall(this.addEventListener);
     17   this.removeEventListener = common.mustCall(this.removeEventListener);
     18 }
     19 
     20 EventTargetMock.prototype.addEventListener = function addEventListener(name, listener, options) {
     21   if (!(name in this.events)) {
     22     this.events[name] = { listeners: [], options: options || {} }
     23   }
     24   this.events[name].listeners.push(listener);
     25 };
     26 
     27 EventTargetMock.prototype.removeEventListener = function removeEventListener(name, callback) {
     28   if (!(name in this.events)) {
     29     return;
     30   }
     31   var event = this.events[name];
     32   var stack = event.listeners;
     33 
     34   for (var i = 0, l = stack.length; i < l; i++) {
     35     if (stack[i] === callback) {
     36       stack.splice(i, 1);
     37       if (stack.length === 0) {
     38         delete this.events[name];
     39       }
     40       return;
     41     }
     42   }
     43 };
     44 
     45 EventTargetMock.prototype.dispatchEvent = function dispatchEvent(arg) {
     46   if (!(arg.type in this.events)) {
     47     return true;
     48   }
     49 
     50   var event = this.events[arg.type];
     51   var stack = event.listeners.slice();
     52 
     53   for (var i = 0, l = stack.length; i < l; i++) {
     54     stack[i].call(null, arg);
     55     if (event.options.once) {
     56       this.removeEventListener(arg.type, stack[i]);
     57     }
     58   }
     59   return !arg.defaultPrevented;
     60 };
     61 
     62 function onceAnEvent() {
     63   var ee = new EventEmitter();
     64 
     65   process.nextTick(function () {
     66     ee.emit('myevent', 42);
     67   });
     68 
     69   return once(ee, 'myevent').then(function (args) {
     70     var value = args[0]
     71     assert.strictEqual(value, 42);
     72     assert.strictEqual(ee.listenerCount('error'), 0);
     73     assert.strictEqual(ee.listenerCount('myevent'), 0);
     74   });
     75 }
     76 
     77 function onceAnEventWithTwoArgs() {
     78   var ee = new EventEmitter();
     79 
     80   process.nextTick(function () {
     81     ee.emit('myevent', 42, 24);
     82   });
     83 
     84   return once(ee, 'myevent').then(function (value) {
     85     assert.strictEqual(value.length, 2);
     86     assert.strictEqual(value[0], 42);
     87     assert.strictEqual(value[1], 24);
     88   });
     89 }
     90 
     91 function catchesErrors() {
     92   var ee = new EventEmitter();
     93 
     94   var expected = new Error('kaboom');
     95   var err;
     96   process.nextTick(function () {
     97     ee.emit('error', expected);
     98   });
     99 
    100   return once(ee, 'myevent').then(function () {
    101     throw new Error('should reject')
    102   }, function (err) {
    103     assert.strictEqual(err, expected);
    104     assert.strictEqual(ee.listenerCount('error'), 0);
    105     assert.strictEqual(ee.listenerCount('myevent'), 0);
    106   });
    107 }
    108 
    109 function stopListeningAfterCatchingError() {
    110   var ee = new EventEmitter();
    111 
    112   var expected = new Error('kaboom');
    113   var err;
    114   process.nextTick(function () {
    115     ee.emit('error', expected);
    116     ee.emit('myevent', 42, 24);
    117   });
    118 
    119   // process.on('multipleResolves', common.mustNotCall());
    120 
    121   return once(ee, 'myevent').then(common.mustNotCall, function (err) {
    122     // process.removeAllListeners('multipleResolves');
    123     assert.strictEqual(err, expected);
    124     assert.strictEqual(ee.listenerCount('error'), 0);
    125     assert.strictEqual(ee.listenerCount('myevent'), 0);
    126   });
    127 }
    128 
    129 function onceError() {
    130   var ee = new EventEmitter();
    131 
    132   var expected = new Error('kaboom');
    133   process.nextTick(function () {
    134     ee.emit('error', expected);
    135   });
    136 
    137   var promise = once(ee, 'error');
    138   assert.strictEqual(ee.listenerCount('error'), 1);
    139   return promise.then(function (args) {
    140     var err = args[0]
    141     assert.strictEqual(err, expected);
    142     assert.strictEqual(ee.listenerCount('error'), 0);
    143     assert.strictEqual(ee.listenerCount('myevent'), 0);
    144   });
    145 }
    146 
    147 function onceWithEventTarget() {
    148   var et = new EventTargetMock();
    149   var event = new Event('myevent');
    150   process.nextTick(function () {
    151     et.dispatchEvent(event);
    152   });
    153   return once(et, 'myevent').then(function (args) {
    154     var value = args[0];
    155     assert.strictEqual(value, event);
    156     assert.strictEqual(has(et.events, 'myevent'), false);
    157   });
    158 }
    159 
    160 function onceWithEventTargetError() {
    161   var et = new EventTargetMock();
    162   var error = new Event('error');
    163   process.nextTick(function () {
    164     et.dispatchEvent(error);
    165   });
    166   return once(et, 'error').then(function (args) {
    167     var err = args[0];
    168     assert.strictEqual(err, error);
    169     assert.strictEqual(has(et.events, 'error'), false);
    170   });
    171 }
    172 
    173 function prioritizesEventEmitter() {
    174   var ee = new EventEmitter();
    175   ee.addEventListener = assert.fail;
    176   ee.removeAllListeners = assert.fail;
    177   process.nextTick(function () {
    178     ee.emit('foo');
    179   });
    180   return once(ee, 'foo');
    181 }
    182 
    183 var allTests = [
    184   onceAnEvent(),
    185   onceAnEventWithTwoArgs(),
    186   catchesErrors(),
    187   stopListeningAfterCatchingError(),
    188   onceError(),
    189   onceWithEventTarget(),
    190   onceWithEventTargetError(),
    191   prioritizesEventEmitter()
    192 ];
    193 
    194 var hasBrowserEventTarget = false;
    195 try {
    196   hasBrowserEventTarget = typeof (new window.EventTarget().addEventListener) === 'function' &&
    197     new window.Event('xyz').type === 'xyz';
    198 } catch (err) {}
    199 
    200 if (hasBrowserEventTarget) {
    201   var onceWithBrowserEventTarget = function onceWithBrowserEventTarget() {
    202     var et = new window.EventTarget();
    203     var event = new window.Event('myevent');
    204     process.nextTick(function () {
    205       et.dispatchEvent(event);
    206     });
    207     return once(et, 'myevent').then(function (args) {
    208       var value = args[0];
    209       assert.strictEqual(value, event);
    210       assert.strictEqual(has(et.events, 'myevent'), false);
    211     });
    212   }
    213 
    214   var onceWithBrowserEventTargetError = function onceWithBrowserEventTargetError() {
    215     var et = new window.EventTarget();
    216     var error = new window.Event('error');
    217     process.nextTick(function () {
    218       et.dispatchEvent(error);
    219     });
    220     return once(et, 'error').then(function (args) {
    221       var err = args[0];
    222       assert.strictEqual(err, error);
    223       assert.strictEqual(has(et.events, 'error'), false);
    224     });
    225   }
    226 
    227   common.test.comment('Testing with browser built-in EventTarget');
    228   allTests.push([
    229     onceWithBrowserEventTarget(),
    230     onceWithBrowserEventTargetError()
    231   ]);
    232 }
    233 
    234 module.exports = Promise.all(allTests);