tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

EventEmitter.test.ts (5473B)


      1 /**
      2 * @license
      3 * Copyright 2023 Google Inc.
      4 * SPDX-License-Identifier: Apache-2.0
      5 */
      6 
      7 import {describe, it, beforeEach} from 'node:test';
      8 
      9 import expect from 'expect';
     10 import sinon from 'sinon';
     11 
     12 import {EventEmitter} from './EventEmitter.js';
     13 
     14 describe('EventEmitter', () => {
     15  let emitter: EventEmitter<Record<string, unknown>>;
     16 
     17  beforeEach(() => {
     18    emitter = new EventEmitter();
     19  });
     20 
     21  describe('on', () => {
     22    const onTests = (methodName: 'on'): void => {
     23      it(`${methodName}: adds an event listener that is fired when the event is emitted`, () => {
     24        const listener = sinon.spy();
     25        emitter[methodName]('foo', listener);
     26        emitter.emit('foo', undefined);
     27        expect(listener.callCount).toEqual(1);
     28      });
     29 
     30      it(`${methodName} sends the event data to the handler`, () => {
     31        const listener = sinon.spy();
     32        const data = {};
     33        emitter[methodName]('foo', listener);
     34        emitter.emit('foo', data);
     35        expect(listener.callCount).toEqual(1);
     36        expect(listener.firstCall.args[0]).toBe(data);
     37      });
     38 
     39      it(`${methodName}: supports chaining`, () => {
     40        const listener = sinon.spy();
     41        const returnValue = emitter[methodName]('foo', listener);
     42        expect(returnValue).toBe(emitter);
     43      });
     44    };
     45    onTests('on');
     46  });
     47 
     48  describe('off', () => {
     49    const offTests = (methodName: 'off'): void => {
     50      it(`${methodName}: removes the listener so it is no longer called`, () => {
     51        const listener = sinon.spy();
     52        emitter.on('foo', listener);
     53        emitter.emit('foo', undefined);
     54        expect(listener.callCount).toEqual(1);
     55        emitter.off('foo', listener);
     56        emitter.emit('foo', undefined);
     57        expect(listener.callCount).toEqual(1);
     58      });
     59 
     60      it(`${methodName}: supports chaining`, () => {
     61        const listener = sinon.spy();
     62        emitter.on('foo', listener);
     63        const returnValue = emitter.off('foo', listener);
     64        expect(returnValue).toBe(emitter);
     65      });
     66    };
     67    offTests('off');
     68  });
     69 
     70  describe('once', () => {
     71    it('only calls the listener once and then removes it', () => {
     72      const listener = sinon.spy();
     73      emitter.once('foo', listener);
     74      emitter.emit('foo', undefined);
     75      expect(listener.callCount).toEqual(1);
     76      emitter.emit('foo', undefined);
     77      expect(listener.callCount).toEqual(1);
     78    });
     79 
     80    it('supports chaining', () => {
     81      const listener = sinon.spy();
     82      const returnValue = emitter.once('foo', listener);
     83      expect(returnValue).toBe(emitter);
     84    });
     85  });
     86 
     87  describe('emit', () => {
     88    it('calls all the listeners for an event', () => {
     89      const listener1 = sinon.spy();
     90      const listener2 = sinon.spy();
     91      const listener3 = sinon.spy();
     92      emitter.on('foo', listener1).on('foo', listener2).on('bar', listener3);
     93 
     94      emitter.emit('foo', undefined);
     95 
     96      expect(listener1.callCount).toEqual(1);
     97      expect(listener2.callCount).toEqual(1);
     98      expect(listener3.callCount).toEqual(0);
     99    });
    100 
    101    it('passes data through to the listener', () => {
    102      const listener = sinon.spy();
    103      emitter.on('foo', listener);
    104      const data = {};
    105 
    106      emitter.emit('foo', data);
    107      expect(listener.callCount).toEqual(1);
    108      expect(listener.firstCall.args[0]).toBe(data);
    109    });
    110 
    111    it('returns true if the event has listeners', () => {
    112      const listener = sinon.spy();
    113      emitter.on('foo', listener);
    114      expect(emitter.emit('foo', undefined)).toBe(true);
    115    });
    116 
    117    it('returns false if the event has listeners', () => {
    118      const listener = sinon.spy();
    119      emitter.on('foo', listener);
    120      expect(emitter.emit('notFoo', undefined)).toBe(false);
    121    });
    122  });
    123 
    124  describe('listenerCount', () => {
    125    it('returns the number of listeners for the given event', () => {
    126      emitter.on('foo', () => {});
    127      emitter.on('foo', () => {});
    128      emitter.on('bar', () => {});
    129      expect(emitter.listenerCount('foo')).toEqual(2);
    130      expect(emitter.listenerCount('bar')).toEqual(1);
    131      expect(emitter.listenerCount('noListeners')).toEqual(0);
    132    });
    133  });
    134 
    135  describe('removeAllListeners', () => {
    136    it('removes every listener from all events by default', () => {
    137      emitter.on('foo', () => {}).on('bar', () => {});
    138 
    139      emitter.removeAllListeners();
    140      expect(emitter.emit('foo', undefined)).toBe(false);
    141      expect(emitter.emit('bar', undefined)).toBe(false);
    142    });
    143 
    144    it('returns the emitter for chaining', () => {
    145      expect(emitter.removeAllListeners()).toBe(emitter);
    146    });
    147 
    148    it('can filter to remove only listeners for a given event name', () => {
    149      emitter
    150        .on('foo', () => {})
    151        .on('bar', () => {})
    152        .on('bar', () => {});
    153 
    154      emitter.removeAllListeners('bar');
    155      expect(emitter.emit('foo', undefined)).toBe(true);
    156      expect(emitter.emit('bar', undefined)).toBe(false);
    157    });
    158  });
    159 
    160  describe('dispose', () => {
    161    it('should dispose higher order emitters properly', () => {
    162      let values = '';
    163      emitter.on('foo', () => {
    164        values += '1';
    165      });
    166      const higherOrderEmitter = new EventEmitter(emitter);
    167 
    168      higherOrderEmitter.on('foo', () => {
    169        values += '2';
    170      });
    171      higherOrderEmitter.emit('foo', undefined);
    172 
    173      expect(values).toMatch('12');
    174 
    175      higherOrderEmitter.off('foo');
    176      higherOrderEmitter.emit('foo', undefined);
    177 
    178      expect(values).toMatch('121');
    179    });
    180  });
    181 });