1/** 2 * Copyright 2020 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import { EventEmitter } from '../lib/cjs/puppeteer/common/EventEmitter.js'; 18import sinon from 'sinon'; 19import expect from 'expect'; 20 21describe('EventEmitter', () => { 22 let emitter; 23 24 beforeEach(() => { 25 emitter = new EventEmitter(); 26 }); 27 28 describe('on', () => { 29 const onTests = (methodName: 'on' | 'addListener'): void => { 30 it(`${methodName}: adds an event listener that is fired when the event is emitted`, () => { 31 const listener = sinon.spy(); 32 emitter[methodName]('foo', listener); 33 emitter.emit('foo'); 34 expect(listener.callCount).toEqual(1); 35 }); 36 37 it(`${methodName} sends the event data to the handler`, () => { 38 const listener = sinon.spy(); 39 const data = {}; 40 emitter[methodName]('foo', listener); 41 emitter.emit('foo', data); 42 expect(listener.callCount).toEqual(1); 43 expect(listener.firstCall.args[0]).toBe(data); 44 }); 45 46 it(`${methodName}: supports chaining`, () => { 47 const listener = sinon.spy(); 48 const returnValue = emitter[methodName]('foo', listener); 49 expect(returnValue).toBe(emitter); 50 }); 51 }; 52 onTests('on'); 53 // we support addListener for legacy reasons 54 onTests('addListener'); 55 }); 56 57 describe('off', () => { 58 const offTests = (methodName: 'off' | 'removeListener'): void => { 59 it(`${methodName}: removes the listener so it is no longer called`, () => { 60 const listener = sinon.spy(); 61 emitter.on('foo', listener); 62 emitter.emit('foo'); 63 expect(listener.callCount).toEqual(1); 64 emitter.off('foo', listener); 65 emitter.emit('foo'); 66 expect(listener.callCount).toEqual(1); 67 }); 68 69 it(`${methodName}: supports chaining`, () => { 70 const listener = sinon.spy(); 71 emitter.on('foo', listener); 72 const returnValue = emitter.off('foo', listener); 73 expect(returnValue).toBe(emitter); 74 }); 75 }; 76 offTests('off'); 77 // we support removeListener for legacy reasons 78 offTests('removeListener'); 79 }); 80 81 describe('once', () => { 82 it('only calls the listener once and then removes it', () => { 83 const listener = sinon.spy(); 84 emitter.once('foo', listener); 85 emitter.emit('foo'); 86 expect(listener.callCount).toEqual(1); 87 emitter.emit('foo'); 88 expect(listener.callCount).toEqual(1); 89 }); 90 91 it('supports chaining', () => { 92 const listener = sinon.spy(); 93 const returnValue = emitter.once('foo', listener); 94 expect(returnValue).toBe(emitter); 95 }); 96 }); 97 98 describe('emit', () => { 99 it('calls all the listeners for an event', () => { 100 const listener1 = sinon.spy(); 101 const listener2 = sinon.spy(); 102 const listener3 = sinon.spy(); 103 emitter.on('foo', listener1).on('foo', listener2).on('bar', listener3); 104 105 emitter.emit('foo'); 106 107 expect(listener1.callCount).toEqual(1); 108 expect(listener2.callCount).toEqual(1); 109 expect(listener3.callCount).toEqual(0); 110 }); 111 112 it('passes data through to the listener', () => { 113 const listener = sinon.spy(); 114 emitter.on('foo', listener); 115 const data = {}; 116 117 emitter.emit('foo', data); 118 expect(listener.callCount).toEqual(1); 119 expect(listener.firstCall.args[0]).toBe(data); 120 }); 121 122 it('returns true if the event has listeners', () => { 123 const listener = sinon.spy(); 124 emitter.on('foo', listener); 125 expect(emitter.emit('foo')).toBe(true); 126 }); 127 128 it('returns false if the event has listeners', () => { 129 const listener = sinon.spy(); 130 emitter.on('foo', listener); 131 expect(emitter.emit('notFoo')).toBe(false); 132 }); 133 }); 134 135 describe('listenerCount', () => { 136 it('returns the number of listeners for the given event', () => { 137 emitter.on('foo', () => {}); 138 emitter.on('foo', () => {}); 139 emitter.on('bar', () => {}); 140 expect(emitter.listenerCount('foo')).toEqual(2); 141 expect(emitter.listenerCount('bar')).toEqual(1); 142 expect(emitter.listenerCount('noListeners')).toEqual(0); 143 }); 144 }); 145 146 describe('removeAllListeners', () => { 147 it('removes every listener from all events by default', () => { 148 emitter.on('foo', () => {}).on('bar', () => {}); 149 150 emitter.removeAllListeners(); 151 expect(emitter.emit('foo')).toBe(false); 152 expect(emitter.emit('bar')).toBe(false); 153 }); 154 155 it('returns the emitter for chaining', () => { 156 expect(emitter.removeAllListeners()).toBe(emitter); 157 }); 158 159 it('can filter to remove only listeners for a given event name', () => { 160 emitter 161 .on('foo', () => {}) 162 .on('bar', () => {}) 163 .on('bar', () => {}); 164 165 emitter.removeAllListeners('bar'); 166 expect(emitter.emit('foo')).toBe(true); 167 expect(emitter.emit('bar')).toBe(false); 168 }); 169 }); 170}); 171