mirror of
https://github.com/microsoft/playwright.git
synced 2024-09-11 20:37:54 +03:00
chore: use soft event emitter (#31868)
This commit is contained in:
parent
7e7319da7d
commit
58b0c76f20
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import { EventEmitter } from './eventEmitter';
|
||||
import type * as channels from '@protocol/channels';
|
||||
import { maybeFindValidator, ValidationError, type ValidatorContext } from '../protocol/validator';
|
||||
import { debugLogger } from '../utils/debugLogger';
|
||||
|
345
packages/playwright-core/src/client/eventEmitter.ts
Normal file
345
packages/playwright-core/src/client/eventEmitter.ts
Normal file
@ -0,0 +1,345 @@
|
||||
/**
|
||||
* Copyright Joyent, Inc. and other Node contributors.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
* persons to whom the Software is furnished to do so, subject to the
|
||||
* following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
type EventType = string | symbol;
|
||||
type Listener = (...args: any[]) => void;
|
||||
type EventMap = Record<EventType, Listener | Listener[]>;
|
||||
import { EventEmitter as OriginalEventEmitter } from 'events';
|
||||
import type { EventEmitter as EventEmitterType } from 'events';
|
||||
import { isUnderTest } from '../utils';
|
||||
|
||||
export class EventEmitter implements EventEmitterType {
|
||||
|
||||
private _events: EventMap | undefined = undefined;
|
||||
private _eventsCount = 0;
|
||||
private _maxListeners: number | undefined = undefined;
|
||||
|
||||
constructor() {
|
||||
if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) {
|
||||
this._events = Object.create(null);
|
||||
this._eventsCount = 0;
|
||||
}
|
||||
this._maxListeners = this._maxListeners || undefined;
|
||||
this.on = this.addListener;
|
||||
this.off = this.removeListener;
|
||||
}
|
||||
|
||||
setMaxListeners(n: number): this {
|
||||
if (typeof n !== 'number' || n < 0 || Number.isNaN(n))
|
||||
throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
|
||||
this._maxListeners = n;
|
||||
return this;
|
||||
}
|
||||
|
||||
getMaxListeners(): number {
|
||||
return this._maxListeners === undefined ? OriginalEventEmitter.defaultMaxListeners : this._maxListeners;
|
||||
}
|
||||
|
||||
emit(type: EventType, ...args: any[]): boolean {
|
||||
const events = this._events;
|
||||
if (events === undefined)
|
||||
return false;
|
||||
|
||||
const handler = events?.[type];
|
||||
if (handler === undefined)
|
||||
return false;
|
||||
|
||||
if (typeof handler === 'function') {
|
||||
Reflect.apply(handler, this, args);
|
||||
} else {
|
||||
const len = handler.length;
|
||||
const listeners = handler.slice();
|
||||
for (let i = 0; i < len; ++i)
|
||||
Reflect.apply(listeners[i], this, args);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
addListener(type: EventType, listener: Listener): this {
|
||||
return this._addListener(type, listener, false);
|
||||
}
|
||||
|
||||
on(type: EventType, listener: Listener): this {
|
||||
return this._addListener(type, listener, false);
|
||||
}
|
||||
|
||||
private _addListener(type: EventType, listener: Listener, prepend: boolean): this {
|
||||
checkListener(listener);
|
||||
let events = this._events;
|
||||
let existing;
|
||||
if (events === undefined) {
|
||||
events = this._events = Object.create(null);
|
||||
this._eventsCount = 0;
|
||||
} else {
|
||||
// To avoid recursion in the case that type === "newListener"! Before
|
||||
// adding it to the listeners, first emit "newListener".
|
||||
if (events.newListener !== undefined) {
|
||||
this.emit('newListener', type, unwrapListener(listener));
|
||||
|
||||
// Re-assign `events` because a newListener handler could have caused the
|
||||
// this._events to be assigned to a new object
|
||||
events = this._events!;
|
||||
}
|
||||
existing = events[type];
|
||||
}
|
||||
|
||||
if (existing === undefined) {
|
||||
// Optimize the case of one listener. Don't need the extra array object.
|
||||
existing = events![type] = listener;
|
||||
++this._eventsCount;
|
||||
} else {
|
||||
if (typeof existing === 'function') {
|
||||
// Adding the second element, need to change to array.
|
||||
existing = events![type] =
|
||||
prepend ? [listener, existing] : [existing, listener];
|
||||
// If we've already got an array, just append.
|
||||
} else if (prepend) {
|
||||
existing.unshift(listener);
|
||||
} else {
|
||||
existing.push(listener);
|
||||
}
|
||||
|
||||
// Check for listener leak
|
||||
const m = this.getMaxListeners();
|
||||
if (m > 0 && existing.length > m && !(existing as any).warned) {
|
||||
(existing as any).warned = true;
|
||||
// No error code for this since it is a Warning
|
||||
const w = new Error('Possible EventEmitter memory leak detected. ' +
|
||||
existing.length + ' ' + String(type) + ' listeners ' +
|
||||
'added. Use emitter.setMaxListeners() to ' +
|
||||
'increase limit') as any;
|
||||
w.name = 'MaxListenersExceededWarning';
|
||||
w.emitter = this;
|
||||
w.type = type;
|
||||
w.count = existing.length;
|
||||
if (!isUnderTest()) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
prependListener(type: EventType, listener: Listener): this {
|
||||
return this._addListener(type, listener, true);
|
||||
}
|
||||
|
||||
once(type: EventType, listener: Listener): this {
|
||||
checkListener(listener);
|
||||
this.on(type, new OnceWrapper(this, type, listener).wrapperFunction);
|
||||
return this;
|
||||
}
|
||||
|
||||
prependOnceListener(type: EventType, listener: Listener): this {
|
||||
checkListener(listener);
|
||||
this.prependListener(type, new OnceWrapper(this, type, listener).wrapperFunction);
|
||||
return this;
|
||||
}
|
||||
|
||||
removeListener(type: EventType, listener: Listener): this {
|
||||
checkListener(listener);
|
||||
|
||||
const events = this._events;
|
||||
if (events === undefined)
|
||||
return this;
|
||||
|
||||
const list = events[type];
|
||||
if (list === undefined)
|
||||
return this;
|
||||
|
||||
if (list === listener || (list as any).listener === listener) {
|
||||
if (--this._eventsCount === 0) {
|
||||
this._events = Object.create(null);
|
||||
} else {
|
||||
delete events[type];
|
||||
if (events.removeListener)
|
||||
this.emit('removeListener', type, (list as any).listener ?? listener);
|
||||
}
|
||||
} else if (typeof list !== 'function') {
|
||||
let position = -1;
|
||||
let originalListener;
|
||||
|
||||
for (let i = list.length - 1; i >= 0; i--) {
|
||||
if (list[i] === listener || wrappedListener(list[i]) === listener) {
|
||||
originalListener = wrappedListener(list[i]);
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (position < 0)
|
||||
return this;
|
||||
|
||||
if (position === 0)
|
||||
list.shift();
|
||||
else
|
||||
list.splice(position, 1);
|
||||
|
||||
if (list.length === 1)
|
||||
events[type] = list[0];
|
||||
|
||||
if (events.removeListener !== undefined)
|
||||
this.emit('removeListener', type, originalListener || listener);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
off(type: EventType, listener: Listener): this {
|
||||
return this.removeListener(type, listener);
|
||||
}
|
||||
|
||||
removeAllListeners(type?: string): this {
|
||||
const events = this._events;
|
||||
if (!events)
|
||||
return this;
|
||||
|
||||
// not listening for removeListener, no need to emit
|
||||
if (!events.removeListener) {
|
||||
if (type === undefined) {
|
||||
this._events = Object.create(null);
|
||||
this._eventsCount = 0;
|
||||
} else if (events[type] !== undefined) {
|
||||
if (--this._eventsCount === 0)
|
||||
this._events = Object.create(null);
|
||||
else
|
||||
delete events[type];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// emit removeListener for all listeners on all events
|
||||
if (type === undefined) {
|
||||
const keys = Object.keys(events);
|
||||
let key;
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
key = keys[i];
|
||||
if (key === 'removeListener')
|
||||
continue;
|
||||
this.removeAllListeners(key);
|
||||
}
|
||||
this.removeAllListeners('removeListener');
|
||||
this._events = Object.create(null);
|
||||
this._eventsCount = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
const listeners = events[type];
|
||||
|
||||
if (typeof listeners === 'function') {
|
||||
this.removeListener(type, listeners);
|
||||
} else if (listeners !== undefined) {
|
||||
// LIFO order
|
||||
for (let i = listeners.length - 1; i >= 0; i--)
|
||||
this.removeListener(type, listeners[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
listeners(type: EventType): Listener[] {
|
||||
return this._listeners(this, type, true);
|
||||
}
|
||||
|
||||
rawListeners(type: EventType): Listener[] {
|
||||
return this._listeners(this, type, false);
|
||||
}
|
||||
|
||||
listenerCount(type: EventType): number {
|
||||
const events = this._events;
|
||||
if (events !== undefined) {
|
||||
const listener = events[type];
|
||||
if (typeof listener === 'function')
|
||||
return 1;
|
||||
if (listener !== undefined)
|
||||
return listener.length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
eventNames(): Array<string | symbol> {
|
||||
return this._eventsCount > 0 && this._events ? Reflect.ownKeys(this._events) : [];
|
||||
}
|
||||
|
||||
private _listeners(target: EventEmitter, type: EventType, unwrap: boolean): Listener[] {
|
||||
const events = target._events;
|
||||
|
||||
if (events === undefined)
|
||||
return [];
|
||||
|
||||
const listener = events[type];
|
||||
if (listener === undefined)
|
||||
return [];
|
||||
|
||||
if (typeof listener === 'function')
|
||||
return unwrap ? [unwrapListener(listener)] : [listener];
|
||||
|
||||
return unwrap ? unwrapListeners(listener) : listener.slice();
|
||||
}
|
||||
}
|
||||
|
||||
function checkListener(listener: any) {
|
||||
if (typeof listener !== 'function')
|
||||
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
|
||||
}
|
||||
|
||||
class OnceWrapper {
|
||||
private _fired = false;
|
||||
readonly wrapperFunction: (...args: any[]) => void;
|
||||
readonly _listener: Listener;
|
||||
private _eventEmitter: EventEmitter;
|
||||
private _eventType: EventType;
|
||||
|
||||
constructor(eventEmitter: EventEmitter, eventType: EventType, listener: Listener) {
|
||||
this._eventEmitter = eventEmitter;
|
||||
this._eventType = eventType;
|
||||
this._listener = listener;
|
||||
this.wrapperFunction = this._handle.bind(this);
|
||||
(this.wrapperFunction as any).listener = listener;
|
||||
}
|
||||
|
||||
private _handle(...args: any[]) {
|
||||
if (this._fired)
|
||||
return;
|
||||
this._fired = true;
|
||||
this._eventEmitter.removeListener(this._eventType, this.wrapperFunction);
|
||||
return this._listener.apply(this._eventEmitter, args);
|
||||
}
|
||||
}
|
||||
|
||||
function unwrapListener(l: Listener): Listener {
|
||||
return wrappedListener(l) ?? l;
|
||||
}
|
||||
|
||||
function unwrapListeners(arr: Listener[]): Listener[] {
|
||||
return arr.map(l => wrappedListener(l) ?? l);
|
||||
}
|
||||
|
||||
function wrappedListener(l: Listener): Listener {
|
||||
return (l as any).listener;
|
||||
}
|
103
tests/library/events/add-listeners.spec.ts
Normal file
103
tests/library/events/add-listeners.spec.ts
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('EventEmitter tests', () => {
|
||||
test('should work', () => {
|
||||
const events_new_listener_emitted = [];
|
||||
const listeners_new_listener_emitted = [];
|
||||
|
||||
const ee = new EventEmitter();
|
||||
|
||||
ee.on('newListener', function(event, listener) {
|
||||
if (event !== 'newListener') {
|
||||
events_new_listener_emitted.push(event);
|
||||
listeners_new_listener_emitted.push(listener);
|
||||
}
|
||||
});
|
||||
|
||||
const hello = (a, b) => {
|
||||
expect(a).toEqual('a');
|
||||
expect(b).toEqual('b');
|
||||
};
|
||||
|
||||
ee.once('newListener', (name, listener) => {
|
||||
expect(name).toEqual('hello');
|
||||
expect(listener).toEqual(hello);
|
||||
|
||||
const listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
});
|
||||
|
||||
ee.on('hello', hello);
|
||||
ee.once('foo', () => { throw new Error('foo error'); });
|
||||
|
||||
expect(Array.isArray(events_new_listener_emitted)).toBeTruthy();
|
||||
expect(events_new_listener_emitted).toHaveLength(2);
|
||||
expect(events_new_listener_emitted[0]).toEqual('hello');
|
||||
expect(events_new_listener_emitted[1]).toEqual('foo');
|
||||
|
||||
expect(Array.isArray(listeners_new_listener_emitted)).toBeTruthy();
|
||||
expect(listeners_new_listener_emitted).toHaveLength(2);
|
||||
expect(listeners_new_listener_emitted[0]).toEqual(hello);
|
||||
expect(listeners_new_listener_emitted[1]).toThrow();
|
||||
|
||||
ee.emit('hello', 'a', 'b');
|
||||
});
|
||||
|
||||
test('set max listeners test', () => {
|
||||
const f = new EventEmitter();
|
||||
f.setMaxListeners(0);
|
||||
});
|
||||
|
||||
test('Listener order', () => {
|
||||
const listen1 = function() {};
|
||||
const listen2 = function() {};
|
||||
const ee = new EventEmitter();
|
||||
|
||||
ee.once('newListener', function() {
|
||||
const listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
ee.once('newListener', function() {
|
||||
const listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
});
|
||||
ee.on('hello', listen2);
|
||||
});
|
||||
ee.on('hello', listen1);
|
||||
const listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(2);
|
||||
expect(listeners[0]).toEqual(listen2);
|
||||
expect(listeners[1]).toEqual(listen1);
|
||||
});
|
||||
|
||||
test('listener type check', () => {
|
||||
const ee = new EventEmitter();
|
||||
expect(() => ee.on('foo', null)).toThrow('The "listener" argument must be of type Function. Received type object');
|
||||
});
|
||||
});
|
92
tests/library/events/check-listener-leaks.spec.ts
Normal file
92
tests/library/events/check-listener-leaks.spec.ts
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import events from 'events';
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { setUnderTest } from '../../../packages/playwright-core/lib/utils/debug';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import * as common from './utils';
|
||||
|
||||
setUnderTest();
|
||||
|
||||
test('defaultMaxListeners', () => {
|
||||
const e = new EventEmitter();
|
||||
|
||||
for (let i = 0; i < 10; i++)
|
||||
e.on('default', common.mustNotCall());
|
||||
|
||||
|
||||
expect(e._events['default']).not.toHaveProperty('warned');
|
||||
e.on('default', common.mustNotCall());
|
||||
expect(e._events['default'].hasOwnProperty('warned')).toBeTruthy();
|
||||
|
||||
e.setMaxListeners(5);
|
||||
for (let i = 0; i < 5; i++)
|
||||
e.on('specific', common.mustNotCall());
|
||||
|
||||
expect(e._events['specific']).not.toHaveProperty('warned');
|
||||
e.on('specific', common.mustNotCall());
|
||||
expect(e._events['specific'].hasOwnProperty('warned')).toBeTruthy();
|
||||
|
||||
// only one
|
||||
e.setMaxListeners(1);
|
||||
e.on('only one', common.mustNotCall());
|
||||
expect(e._events['only one']).not.toHaveProperty('warned');
|
||||
e.on('only one', common.mustNotCall());
|
||||
expect(e._events['only one'].hasOwnProperty('warned')).toBeTruthy();
|
||||
|
||||
// unlimited
|
||||
e.setMaxListeners(0);
|
||||
for (let i = 0; i < 1000; i++)
|
||||
e.on('unlimited', common.mustNotCall());
|
||||
|
||||
expect(e._events['unlimited']).not.toHaveProperty('warned');
|
||||
});
|
||||
|
||||
test('process-wide', () => {
|
||||
events.EventEmitter.defaultMaxListeners = 42;
|
||||
const e = new EventEmitter();
|
||||
|
||||
for (let i = 0; i < 42; ++i)
|
||||
e.on('fortytwo', common.mustNotCall());
|
||||
|
||||
expect(e._events['fortytwo']).not.toHaveProperty('warned');
|
||||
e.on('fortytwo', common.mustNotCall());
|
||||
expect(e._events['fortytwo'].hasOwnProperty('warned')).toBeTruthy();
|
||||
delete e._events['fortytwo'].warned;
|
||||
|
||||
events.EventEmitter.defaultMaxListeners = 44;
|
||||
e.on('fortytwo', common.mustNotCall());
|
||||
expect(e._events['fortytwo']).not.toHaveProperty('warned');
|
||||
e.on('fortytwo', common.mustNotCall());
|
||||
expect(e._events['fortytwo'].hasOwnProperty('warned')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('_maxListeners still has precedence over defaultMaxListeners', () => {
|
||||
events.EventEmitter.defaultMaxListeners = 42;
|
||||
const e = new EventEmitter();
|
||||
e.setMaxListeners(1);
|
||||
e.on('uno', common.mustNotCall());
|
||||
expect(e._events['uno']).not.toHaveProperty('warned');
|
||||
e.on('uno', common.mustNotCall());
|
||||
expect(e._events['uno'].hasOwnProperty('warned')).toBeTruthy();
|
||||
});
|
55
tests/library/events/events-list.spec.ts
Normal file
55
tests/library/events/events-list.spec.ts
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('EventEmitter', () => {
|
||||
test('should maintain event names correctly', () => {
|
||||
const e = new EventEmitter();
|
||||
const m = () => {};
|
||||
e.on('foo', function() {});
|
||||
expect(e.eventNames().length).toBe(1);
|
||||
expect(e.eventNames()[0]).toBe('foo');
|
||||
|
||||
e.on('bar', m);
|
||||
expect(e.eventNames().length).toBe(2);
|
||||
expect(e.eventNames()[0]).toBe('foo');
|
||||
expect(e.eventNames()[1]).toBe('bar');
|
||||
|
||||
e.removeListener('bar', m);
|
||||
expect(e.eventNames().length).toBe(1);
|
||||
expect(e.eventNames()[0]).toBe('foo');
|
||||
|
||||
if (typeof Symbol !== 'undefined') {
|
||||
const s = Symbol('s');
|
||||
e.on(s, m);
|
||||
expect(e.eventNames().length).toBe(2);
|
||||
expect(e.eventNames()[0]).toBe('foo');
|
||||
expect(e.eventNames()[1]).toBe(s);
|
||||
|
||||
e.removeListener(s, m);
|
||||
expect(e.eventNames().length).toBe(1);
|
||||
expect(e.eventNames()[0]).toBe('foo');
|
||||
}
|
||||
});
|
||||
});
|
40
tests/library/events/listener-count.spec.ts
Normal file
40
tests/library/events/listener-count.spec.ts
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import events from 'events';
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('Listener count test', () => {
|
||||
const emitter = new EventEmitter();
|
||||
emitter.on('foo', () => {});
|
||||
emitter.on('foo', () => {});
|
||||
emitter.on('baz', () => {});
|
||||
// Allow any type
|
||||
emitter.on(123, () => {});
|
||||
|
||||
expect(events.listenerCount(emitter, 'foo')).toEqual(2);
|
||||
expect(emitter.listenerCount('foo')).toEqual(2);
|
||||
expect(emitter.listenerCount('bar')).toEqual(0);
|
||||
expect(emitter.listenerCount('baz')).toEqual(1);
|
||||
expect(emitter.listenerCount(123)).toEqual(1);
|
||||
});
|
61
tests/library/events/listeners-side-effects.spec.ts
Normal file
61
tests/library/events/listeners-side-effects.spec.ts
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
|
||||
test('listeners empty check', () => {
|
||||
const e = new EventEmitter();
|
||||
let fl; // foo listeners
|
||||
|
||||
fl = e.listeners('foo');
|
||||
|
||||
expect(Array.isArray(fl)).toBeTruthy();
|
||||
expect(fl).toHaveLength(0);
|
||||
expect(e._events instanceof Object).toBeFalsy();
|
||||
expect(Object.keys(e._events)).toHaveLength(0);
|
||||
|
||||
const fail = () => expect(true).toBe(false);
|
||||
e.on('foo', fail);
|
||||
fl = e.listeners('foo');
|
||||
|
||||
expect(e._events.foo).toBe(fail);
|
||||
expect(Array.isArray(fl)).toBeTruthy();
|
||||
expect(fl).toHaveLength(1);
|
||||
expect(fl[0]).toBe(fail);
|
||||
|
||||
e.listeners('bar');
|
||||
|
||||
const pass = () => expect(true).toBe(true);
|
||||
e.on('foo', pass);
|
||||
fl = e.listeners('foo');
|
||||
|
||||
expect(Array.isArray(e._events.foo)).toBeTruthy();
|
||||
expect(e._events.foo).toHaveLength(2);
|
||||
expect(e._events.foo[0]).toBe(fail);
|
||||
expect(e._events.foo[1]).toBe(pass);
|
||||
|
||||
expect(Array.isArray(fl)).toBeTruthy();
|
||||
expect(fl).toHaveLength(2);
|
||||
expect(fl[0]).toBe(fail);
|
||||
expect(fl[1]).toBe(pass);
|
||||
});
|
154
tests/library/events/listeners.spec.ts
Normal file
154
tests/library/events/listeners.spec.ts
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
const listener = () => {};
|
||||
const listener2 = () => {};
|
||||
const listener3 = () => { return 0; };
|
||||
const listener4 = () => { return 1; };
|
||||
|
||||
class TestStream extends EventEmitter {}
|
||||
|
||||
test('EventEmitter listeners with one listener', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('foo', listener);
|
||||
const fooListeners = ee.listeners('foo');
|
||||
|
||||
const listeners = ee.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(1);
|
||||
expect(listeners[0]).toEqual(listener);
|
||||
|
||||
ee.removeAllListeners('foo');
|
||||
expect<Array<any>>(ee.listeners('foo')).toHaveLength(0);
|
||||
|
||||
expect(Array.isArray(fooListeners)).toBeTruthy();
|
||||
expect(fooListeners).toHaveLength(1);
|
||||
expect(fooListeners[0]).toEqual(listener);
|
||||
});
|
||||
|
||||
test('Array copy modification does not modify orig', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('foo', listener);
|
||||
|
||||
const eeListenersCopy = ee.listeners('foo');
|
||||
expect(Array.isArray(eeListenersCopy)).toBeTruthy();
|
||||
expect(eeListenersCopy).toHaveLength(1);
|
||||
expect(eeListenersCopy[0]).toEqual(listener);
|
||||
|
||||
eeListenersCopy.push(listener2);
|
||||
const listeners = ee.listeners('foo');
|
||||
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(1);
|
||||
expect(listeners[0]).toEqual(listener);
|
||||
|
||||
expect(eeListenersCopy).toHaveLength(2);
|
||||
expect(eeListenersCopy[0]).toEqual(listener);
|
||||
expect(eeListenersCopy[1]).toEqual(listener2);
|
||||
});
|
||||
|
||||
test('Modify array copy after multiple adds', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('foo', listener);
|
||||
const eeListenersCopy = ee.listeners('foo');
|
||||
ee.on('foo', listener2);
|
||||
|
||||
const listeners = ee.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(2);
|
||||
expect(listeners[0]).toEqual(listener);
|
||||
expect(listeners[1]).toEqual(listener2);
|
||||
|
||||
expect(Array.isArray(eeListenersCopy)).toBeTruthy();
|
||||
expect(eeListenersCopy).toHaveLength(1);
|
||||
expect(eeListenersCopy[0]).toEqual(listener);
|
||||
});
|
||||
|
||||
test('listeners and once', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.once('foo', listener);
|
||||
const listeners = ee.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(1);
|
||||
expect(listeners[0]).toEqual(listener);
|
||||
});
|
||||
|
||||
test('listeners with conflicting types', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('foo', listener);
|
||||
ee.once('foo', listener2);
|
||||
|
||||
const listeners = ee.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(2);
|
||||
expect(listeners[0]).toEqual(listener);
|
||||
expect(listeners[1]).toEqual(listener2);
|
||||
});
|
||||
|
||||
test('EventEmitter with no members', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee._events = undefined;
|
||||
const listeners = ee.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('listeners on prototype', () => {
|
||||
const s = new TestStream();
|
||||
const listeners = s.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('raw listeners', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('foo', listener);
|
||||
const wrappedListener = ee.rawListeners('foo');
|
||||
expect(wrappedListener).toHaveLength(1);
|
||||
expect(wrappedListener[0]).toEqual(listener);
|
||||
|
||||
ee.once('foo', listener);
|
||||
const wrappedListeners = ee.rawListeners('foo');
|
||||
expect(wrappedListeners).toHaveLength(2);
|
||||
expect(wrappedListeners[0]).toEqual(listener);
|
||||
expect(wrappedListeners[1].listener).toEqual(listener);
|
||||
|
||||
ee.emit('foo');
|
||||
expect(wrappedListeners).toHaveLength(2);
|
||||
expect(wrappedListeners[1].listener).toEqual(listener);
|
||||
});
|
||||
|
||||
test('raw listeners order', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.once('foo', listener3);
|
||||
ee.on('foo', listener4);
|
||||
const rawListeners = ee.rawListeners('foo');
|
||||
expect(rawListeners).toHaveLength(2);
|
||||
expect(rawListeners[0]()).toEqual(0);
|
||||
|
||||
const rawListener = ee.rawListeners('foo');
|
||||
expect(rawListener).toHaveLength(1);
|
||||
expect(rawListener[0]()).toEqual(1);
|
||||
});
|
43
tests/library/events/max-listeners.spec.ts
Normal file
43
tests/library/events/max-listeners.spec.ts
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH the SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('emit maxListeners on e', () => {
|
||||
const e = new EventEmitter();
|
||||
e.on('maxListeners', () => {});
|
||||
|
||||
// Should not corrupt the 'maxListeners' queue.
|
||||
e.setMaxListeners(42);
|
||||
|
||||
const throwsObjs = [NaN, -1, 'and even this'];
|
||||
const maxError = /^The value of \"n\" is out of range. It must be a non-negative number./;
|
||||
|
||||
for (const obj of throwsObjs) {
|
||||
expect(() => {
|
||||
e.setMaxListeners(obj);
|
||||
}).toThrow(maxError);
|
||||
}
|
||||
|
||||
e.emit('maxListeners');
|
||||
});
|
40
tests/library/events/method-names.spec.ts
Normal file
40
tests/library/events/method-names.spec.ts
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('EventEmitter prototype test', () => {
|
||||
const ee = new EventEmitter();
|
||||
// eslint-disable-next-line no-proto
|
||||
expect((ee as any).__proto__.constructor.name).toEqual('EventEmitter');
|
||||
expect(ee.on).toEqual(ee.addListener); // Same method.
|
||||
expect(ee.off).toEqual(ee.removeListener); // Same method.
|
||||
|
||||
Object.getOwnPropertyNames(ee).forEach(name => {
|
||||
if (name === 'constructor' || name === 'on' || name === 'off')
|
||||
return;
|
||||
if (typeof ee[name] !== 'function')
|
||||
return;
|
||||
expect(ee[name].name).toEqual(name);
|
||||
});
|
||||
});
|
93
tests/library/events/modify-in-emit.spec.ts
Normal file
93
tests/library/events/modify-in-emit.spec.ts
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
|
||||
let callbacks_called = [];
|
||||
const e = new EventEmitter();
|
||||
|
||||
const callback1 = () => {
|
||||
callbacks_called.push('callback1');
|
||||
e.on('foo', callback2);
|
||||
e.on('foo', callback3);
|
||||
e.removeListener('foo', callback1);
|
||||
};
|
||||
|
||||
const callback2 = () => {
|
||||
callbacks_called.push('callback2');
|
||||
e.removeListener('foo', callback2);
|
||||
};
|
||||
|
||||
const callback3 = () => {
|
||||
callbacks_called.push('callback3');
|
||||
e.removeListener('foo', callback3);
|
||||
};
|
||||
|
||||
test('add and remove listeners', () => {
|
||||
e.on('foo', callback1);
|
||||
expect(e.listeners('foo')).toHaveLength(1);
|
||||
|
||||
e.emit('foo');
|
||||
expect(e.listeners('foo')).toHaveLength(2);
|
||||
expect(Array.isArray(callbacks_called)).toBeTruthy();
|
||||
expect(callbacks_called).toHaveLength(1);
|
||||
expect(callbacks_called[0]).toEqual('callback1');
|
||||
|
||||
e.emit('foo');
|
||||
expect(e.listeners('foo')).toHaveLength(0);
|
||||
expect(Array.isArray(callbacks_called)).toBeTruthy();
|
||||
expect(callbacks_called).toHaveLength(3);
|
||||
expect(callbacks_called[0]).toEqual('callback1');
|
||||
expect(callbacks_called[1]).toEqual('callback2');
|
||||
expect(callbacks_called[2]).toEqual('callback3');
|
||||
|
||||
e.emit('foo');
|
||||
expect(e.listeners('foo')).toHaveLength(0);
|
||||
expect(Array.isArray(callbacks_called)).toBeTruthy();
|
||||
expect(callbacks_called).toHaveLength(3);
|
||||
expect(callbacks_called[0]).toEqual('callback1');
|
||||
expect(callbacks_called[1]).toEqual('callback2');
|
||||
expect(callbacks_called[2]).toEqual('callback3');
|
||||
|
||||
e.on('foo', callback1);
|
||||
e.on('foo', callback2);
|
||||
expect(e.listeners('foo')).toHaveLength(2);
|
||||
e.removeAllListeners('foo');
|
||||
expect(e.listeners('foo')).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('removing callbacks in emit', () => {
|
||||
// Verify that removing callbacks while in emit allows emits to propagate to
|
||||
// all listeners
|
||||
callbacks_called = [];
|
||||
|
||||
e.on('foo', callback2);
|
||||
e.on('foo', callback3);
|
||||
expect(e.listeners('foo')).toHaveLength(2);
|
||||
e.emit('foo');
|
||||
expect(Array.isArray(callbacks_called)).toBeTruthy();
|
||||
expect(callbacks_called).toHaveLength(2);
|
||||
expect(callbacks_called[0]).toEqual('callback2');
|
||||
expect(callbacks_called[1]).toEqual('callback3');
|
||||
expect(e.listeners('foo')).toHaveLength(0);
|
||||
});
|
62
tests/library/events/num-args.spec.ts
Normal file
62
tests/library/events/num-args.spec.ts
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('should work', () => {
|
||||
const e = new EventEmitter();
|
||||
const num_args_emitted = [];
|
||||
|
||||
e.on('numArgs', (...args) => {
|
||||
const numArgs = args.length;
|
||||
num_args_emitted.push(numArgs);
|
||||
});
|
||||
|
||||
e.on('foo', function() {
|
||||
num_args_emitted.push(arguments.length);
|
||||
});
|
||||
|
||||
e.on('foo', function() {
|
||||
num_args_emitted.push(arguments.length);
|
||||
});
|
||||
|
||||
e.emit('numArgs');
|
||||
e.emit('numArgs', null);
|
||||
e.emit('numArgs', null, null);
|
||||
e.emit('numArgs', null, null, null);
|
||||
e.emit('numArgs', null, null, null, null);
|
||||
e.emit('numArgs', null, null, null, null, null);
|
||||
|
||||
e.emit('foo', null, null, null, null);
|
||||
|
||||
expect(Array.isArray(num_args_emitted)).toBeTruthy();
|
||||
expect(num_args_emitted).toHaveLength(8);
|
||||
expect(num_args_emitted[0]).toEqual(0);
|
||||
expect(num_args_emitted[1]).toEqual(1);
|
||||
expect(num_args_emitted[2]).toEqual(2);
|
||||
expect(num_args_emitted[3]).toEqual(3);
|
||||
expect(num_args_emitted[4]).toEqual(4);
|
||||
expect(num_args_emitted[5]).toEqual(5);
|
||||
expect(num_args_emitted[6]).toEqual(4);
|
||||
expect(num_args_emitted[6]).toEqual(4);
|
||||
});
|
84
tests/library/events/once.spec.ts
Normal file
84
tests/library/events/once.spec.ts
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import * as common from './utils';
|
||||
|
||||
test('should work', () => {
|
||||
const e = new EventEmitter();
|
||||
|
||||
e.once('hello', common.mustCall());
|
||||
|
||||
e.emit('hello', 'a', 'b');
|
||||
e.emit('hello', 'a', 'b');
|
||||
e.emit('hello', 'a', 'b');
|
||||
e.emit('hello', 'a', 'b');
|
||||
|
||||
const remove = () => {
|
||||
expect(false).toBe(true);
|
||||
};
|
||||
|
||||
e.once('foo', remove);
|
||||
e.removeListener('foo', remove);
|
||||
e.emit('foo');
|
||||
|
||||
e.once('e', common.mustCall(() => {
|
||||
e.emit('e');
|
||||
}));
|
||||
|
||||
e.once('e', common.mustCall());
|
||||
|
||||
e.emit('e');
|
||||
|
||||
// Verify that the listener must be a function
|
||||
expect(() => {
|
||||
const ee = new EventEmitter();
|
||||
|
||||
ee.once('foo', null);
|
||||
}).toThrow(TypeError);
|
||||
});
|
||||
|
||||
test('once() has different code paths based on the number of arguments being emitted', () => {
|
||||
// Verify that all of the cases are covered.
|
||||
const maxArgs = 4;
|
||||
|
||||
for (let i = 0; i <= maxArgs; i++) {
|
||||
const ee = new EventEmitter();
|
||||
const args: any[] = ['foo'];
|
||||
|
||||
for (let j = 0; j < i; j++)
|
||||
args.push(j);
|
||||
|
||||
ee.once('foo', common.mustCall((...params) => {
|
||||
const restArgs = args.slice(1);
|
||||
expect(Array.isArray(params)).toBeTruthy();
|
||||
expect(params).toHaveLength(restArgs.length);
|
||||
for (let index = 0; index < params.length; index++) {
|
||||
const param = params[index];
|
||||
expect(param).toEqual(restArgs[index]);
|
||||
}
|
||||
}));
|
||||
|
||||
EventEmitter.prototype.emit.apply(ee, args);
|
||||
}
|
||||
});
|
52
tests/library/events/prepend.spec.ts
Normal file
52
tests/library/events/prepend.spec.ts
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('EventEmitter functionality', () => {
|
||||
const myEE = new EventEmitter();
|
||||
let m = 0;
|
||||
// This one comes last.
|
||||
myEE.on('foo', () => {
|
||||
expect(m).toEqual(2);
|
||||
});
|
||||
|
||||
// This one comes second.
|
||||
myEE.prependListener('foo', () => {
|
||||
expect(m++).toEqual(1);
|
||||
});
|
||||
|
||||
// This one comes first.
|
||||
myEE.prependOnceListener('foo', () => {
|
||||
expect(m++).toEqual(0);
|
||||
});
|
||||
|
||||
myEE.emit('foo');
|
||||
});
|
||||
|
||||
test('Verify that the listener must be a function', () => {
|
||||
expect(() => {
|
||||
const ee = new EventEmitter();
|
||||
ee.prependOnceListener('foo', null);
|
||||
}).toThrow(TypeError);
|
||||
});
|
136
tests/library/events/remove-all-listeners.spec.ts
Normal file
136
tests/library/events/remove-all-listeners.spec.ts
Normal file
@ -0,0 +1,136 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import * as common from './utils';
|
||||
|
||||
let wrappers: any[];
|
||||
|
||||
const expectWrapper = expected => {
|
||||
const entry: any = { expected };
|
||||
wrappers.push(entry);
|
||||
return name => {
|
||||
entry.actual = entry.actual || [];
|
||||
entry.actual.push(name);
|
||||
};
|
||||
};
|
||||
|
||||
test.beforeEach(() => {
|
||||
wrappers = [];
|
||||
});
|
||||
|
||||
test.afterEach(() => {
|
||||
for (const wrapper of wrappers) {
|
||||
const sortedActual = wrapper.actual.sort();
|
||||
const sortedExpected = wrapper.expected.sort();
|
||||
expect(sortedActual).toEqual(sortedExpected);
|
||||
}
|
||||
});
|
||||
|
||||
test('listeners', () => {
|
||||
const ee = new EventEmitter();
|
||||
const noop = () => { };
|
||||
ee.on('foo', noop);
|
||||
ee.on('bar', noop);
|
||||
ee.on('baz', noop);
|
||||
ee.on('baz', noop);
|
||||
const fooListeners = ee.listeners('foo');
|
||||
const barListeners = ee.listeners('bar');
|
||||
const bazListeners = ee.listeners('baz');
|
||||
ee.on('removeListener', expectWrapper(['bar', 'baz', 'baz']));
|
||||
ee.removeAllListeners('bar');
|
||||
ee.removeAllListeners('baz');
|
||||
|
||||
let listeners = ee.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(1);
|
||||
expect(listeners[0]).toEqual(noop);
|
||||
|
||||
listeners = ee.listeners('bar');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
listeners = ee.listeners('baz');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
|
||||
expect(fooListeners.length).toEqual(1);
|
||||
expect(fooListeners[0]).toEqual(noop);
|
||||
expect(barListeners.length).toEqual(1);
|
||||
expect(barListeners[0]).toEqual(noop);
|
||||
expect(bazListeners.length).toEqual(2);
|
||||
expect(bazListeners[0]).toEqual(noop);
|
||||
expect(bazListeners[1]).toEqual(noop);
|
||||
|
||||
expect(ee.listeners('bar')).not.toEqual(barListeners);
|
||||
expect(ee.listeners('baz')).not.toEqual(bazListeners);
|
||||
});
|
||||
|
||||
test('removeAllListeners removes all listeners', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('foo', () => { });
|
||||
ee.on('bar', () => { });
|
||||
ee.on('removeListener', expectWrapper(['foo', 'bar', 'removeListener']));
|
||||
ee.on('removeListener', expectWrapper(['foo', 'bar']));
|
||||
ee.removeAllListeners();
|
||||
|
||||
let listeners = ee.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
listeners = ee.listeners('bar');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('removeAllListeners with no event type', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('removeListener', common.mustNotCall());
|
||||
// Check for regression where removeAllListeners() throws when
|
||||
// there exists a 'removeListener' listener, but there exists
|
||||
// no listeners for the provided event type.
|
||||
(ee as any).removeAllListeners(ee, 'foo');
|
||||
});
|
||||
|
||||
test('listener count after removeAllListeners', () => {
|
||||
const ee = new EventEmitter();
|
||||
let expectLength = 2;
|
||||
ee.on('removeListener', () => {
|
||||
expect(expectLength--).toEqual(ee.listeners('baz').length);
|
||||
});
|
||||
ee.on('baz', () => { });
|
||||
ee.on('baz', () => { });
|
||||
ee.on('baz', () => { });
|
||||
expect(ee.listeners('baz').length).toEqual(expectLength + 1);
|
||||
ee.removeAllListeners('baz');
|
||||
expect(ee.listeners('baz').length).toEqual(0);
|
||||
});
|
||||
|
||||
test('removeAllListeners returns EventEmitter', () => {
|
||||
const ee = new EventEmitter();
|
||||
expect(ee).toEqual(ee.removeAllListeners());
|
||||
});
|
||||
|
||||
test('removeAllListeners on undefined _events', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee._events = undefined;
|
||||
expect(ee).toEqual(ee.removeAllListeners());
|
||||
});
|
188
tests/library/events/remove-listeners.spec.ts
Normal file
188
tests/library/events/remove-listeners.spec.ts
Normal file
@ -0,0 +1,188 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import * as common from './utils';
|
||||
|
||||
const listener1 = () => {};
|
||||
const listener2 = () => {};
|
||||
|
||||
test.beforeEach(() => common.beforeEach());
|
||||
test.afterEach(() => common.afterEach());
|
||||
|
||||
test('First test', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('hello', listener1);
|
||||
ee.on('removeListener', common.mustCall((name, cb) => {
|
||||
expect(name).toEqual('hello');
|
||||
expect(cb).toEqual(listener1);
|
||||
}));
|
||||
ee.removeListener('hello', listener1);
|
||||
const listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('Second test', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('hello', listener1);
|
||||
ee.on('removeListener', common.mustNotCall());
|
||||
ee.removeListener('hello', listener2);
|
||||
|
||||
const listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners.length).toEqual(1);
|
||||
expect(listeners[0]).toEqual(listener1);
|
||||
});
|
||||
|
||||
test('Third test', () => {
|
||||
const ee = new EventEmitter();
|
||||
ee.on('hello', listener1);
|
||||
ee.on('hello', listener2);
|
||||
|
||||
let listeners;
|
||||
ee.once('removeListener', common.mustCall((name, cb) => {
|
||||
expect(name).toEqual('hello');
|
||||
expect(cb).toEqual(listener1);
|
||||
listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners.length).toEqual(1);
|
||||
expect(listeners[0]).toEqual(listener2);
|
||||
}));
|
||||
ee.removeListener('hello', listener1);
|
||||
listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners.length).toEqual(1);
|
||||
expect(listeners[0]).toEqual(listener2);
|
||||
ee.once('removeListener', common.mustCall((name, cb) => {
|
||||
expect(name).toEqual('hello');
|
||||
expect(cb).toEqual(listener2);
|
||||
listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners.length).toEqual(0);
|
||||
}));
|
||||
ee.removeListener('hello', listener2);
|
||||
listeners = ee.listeners('hello');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners.length).toEqual(0);
|
||||
});
|
||||
|
||||
test('Fourth test', () => {
|
||||
const ee = new EventEmitter();
|
||||
|
||||
const remove1 = () => {
|
||||
throw new Error('remove1 should not have been called');
|
||||
};
|
||||
|
||||
const remove2 = () => {
|
||||
throw new Error('remove2 should not have been called');
|
||||
};
|
||||
|
||||
ee.on('removeListener', common.mustCall((name, cb) => {
|
||||
if (cb !== remove1)
|
||||
return;
|
||||
ee.removeListener('quux', remove2);
|
||||
ee.emit('quux');
|
||||
}, 2));
|
||||
ee.on('quux', remove1);
|
||||
ee.on('quux', remove2);
|
||||
ee.removeListener('quux', remove1);
|
||||
});
|
||||
|
||||
test('Fifth test', () => {
|
||||
const ee = new EventEmitter();
|
||||
const listener3 = common.mustCall(() => {
|
||||
ee.removeListener('hello', listener4);
|
||||
}, 2);
|
||||
const listener4 = common.mustCall();
|
||||
|
||||
ee.on('hello', listener3);
|
||||
ee.on('hello', listener4);
|
||||
|
||||
// listener4 will still be called although it is removed by listener 3.
|
||||
ee.emit('hello');
|
||||
// This is so because the interal listener array at time of emit
|
||||
// was [listener3,listener4]
|
||||
|
||||
// Interal listener array [listener3]
|
||||
ee.emit('hello');
|
||||
});
|
||||
|
||||
test('Sixth test', () => {
|
||||
const ee = new EventEmitter();
|
||||
|
||||
ee.once('hello', listener1);
|
||||
ee.on('removeListener', common.mustCall((eventName, listener) => {
|
||||
expect(eventName).toEqual('hello');
|
||||
expect(listener).toEqual(listener1);
|
||||
}));
|
||||
ee.emit('hello');
|
||||
});
|
||||
|
||||
test('Seventh test', () => {
|
||||
const ee = new EventEmitter();
|
||||
|
||||
expect(ee).toEqual(ee.removeListener('foo', () => {}));
|
||||
});
|
||||
|
||||
// Verify that the removed listener must be a function
|
||||
test('Eighth test', () => {
|
||||
expect(() => {
|
||||
const ee = new EventEmitter();
|
||||
|
||||
ee.removeListener('foo', null);
|
||||
}).toThrow(/^The "listener" argument must be of type Function\. Received type object$/);
|
||||
});
|
||||
|
||||
test('Ninth test', () => {
|
||||
const ee = new EventEmitter();
|
||||
const listener = () => {};
|
||||
ee._events = undefined;
|
||||
const e = ee.removeListener('foo', listener);
|
||||
expect(e).toEqual(ee);
|
||||
});
|
||||
|
||||
test('Tenth test', () => {
|
||||
const ee = new EventEmitter();
|
||||
|
||||
ee.on('foo', listener1);
|
||||
ee.on('foo', listener2);
|
||||
let listeners = ee.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners.length).toEqual(2);
|
||||
expect(listeners[0]).toEqual(listener1);
|
||||
expect(listeners[1]).toEqual(listener2);
|
||||
|
||||
ee.removeListener('foo', listener1);
|
||||
expect(ee._events.foo).toEqual(listener2);
|
||||
|
||||
ee.on('foo', listener1);
|
||||
listeners = ee.listeners('foo');
|
||||
expect(Array.isArray(listeners)).toBeTruthy();
|
||||
expect(listeners.length).toEqual(2);
|
||||
expect(listeners[0]).toEqual(listener2);
|
||||
expect(listeners[1]).toEqual(listener1);
|
||||
|
||||
ee.removeListener('foo', listener1);
|
||||
expect(ee._events.foo).toEqual(listener2);
|
||||
});
|
34
tests/library/events/set-max-listeners-side-effects.spec.ts
Normal file
34
tests/library/events/set-max-listeners-side-effects.spec.ts
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('set max listeners test', () => {
|
||||
const e = new EventEmitter();
|
||||
|
||||
expect(!(e._events instanceof Object)).toBeTruthy();
|
||||
expect(Object.keys(e._events)).toHaveLength(0);
|
||||
|
||||
e.setMaxListeners(5);
|
||||
expect(Object.keys(e._events)).toHaveLength(0);
|
||||
});
|
46
tests/library/events/special-event-names.spec.ts
Normal file
46
tests/library/events/special-event-names.spec.ts
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
|
||||
|
||||
test('should support special event names', () => {
|
||||
const ee = new EventEmitter();
|
||||
const handler = () => {};
|
||||
|
||||
expect(ee.eventNames().length).toEqual(0);
|
||||
expect(ee._events.hasOwnProperty).toEqual(undefined);
|
||||
expect(ee._events.toString).toEqual(undefined);
|
||||
|
||||
ee.on('__defineGetter__', handler);
|
||||
ee.on('toString', handler);
|
||||
ee.on('__proto__', handler);
|
||||
|
||||
expect(ee.eventNames()[0]).toEqual('__defineGetter__');
|
||||
expect(ee.eventNames()[1]).toEqual('toString');
|
||||
|
||||
expect(ee.listeners('__defineGetter__').length).toEqual(1);
|
||||
expect(ee.listeners('__defineGetter__')[0]).toEqual(handler);
|
||||
expect(ee.listeners('toString').length).toEqual(1);
|
||||
expect(ee.listeners('toString')[0]).toEqual(handler);
|
||||
});
|
54
tests/library/events/subclass.spec.ts
Normal file
54
tests/library/events/subclass.spec.ts
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
class MyEE extends EventEmitter {
|
||||
constructor(cb) {
|
||||
super();
|
||||
this.once(1, cb);
|
||||
this.emit(1);
|
||||
this.removeAllListeners();
|
||||
}
|
||||
}
|
||||
|
||||
test('myee instance', () => {
|
||||
const myee = new MyEE(() => {});
|
||||
expect(myee._events).not.toBeInstanceOf(Object);
|
||||
expect(Object.keys(myee._events).length).toBe(0);
|
||||
});
|
||||
|
||||
class MyEE2 {
|
||||
ee: EventEmitter;
|
||||
constructor() {
|
||||
this.ee = new EventEmitter();
|
||||
}
|
||||
}
|
||||
|
||||
test('MyEE2 instance', () => {
|
||||
const ee1 = new MyEE2();
|
||||
const ee2 = new MyEE2();
|
||||
|
||||
ee1.ee.on('x', function() {});
|
||||
expect(ee2.ee.listenerCount('x')).toBe(0);
|
||||
});
|
46
tests/library/events/symbols.spec.ts
Normal file
46
tests/library/events/symbols.spec.ts
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
// Modifications copyright (c) by Microsoft Corporation
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('should support symbols', () => {
|
||||
const ee = new EventEmitter();
|
||||
const foo = Symbol('foo');
|
||||
const listener = () => {};
|
||||
|
||||
ee.on(foo, listener);
|
||||
expect(ee.listeners(foo).length).toEqual(1);
|
||||
expect(ee.listeners(foo)[0]).toEqual(listener);
|
||||
|
||||
ee.emit(foo);
|
||||
|
||||
ee.removeAllListeners();
|
||||
expect(ee.listeners(foo).length).toEqual(0);
|
||||
|
||||
ee.on(foo, listener);
|
||||
expect(ee.listeners(foo).length).toEqual(1);
|
||||
expect(ee.listeners(foo)[0]).toEqual(listener);
|
||||
|
||||
ee.removeListener(foo, listener);
|
||||
expect(ee.listeners(foo).length).toEqual(0);
|
||||
});
|
46
tests/library/events/utils.ts
Normal file
46
tests/library/events/utils.ts
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
export const mustNotCall = (msg?: string) => {
|
||||
return function mustNotCall() {
|
||||
expect(false, msg || 'function should not have been called').toBeTruthy();
|
||||
};
|
||||
};
|
||||
|
||||
let count;
|
||||
|
||||
export const beforeEach = () => {
|
||||
count = 0;
|
||||
};
|
||||
|
||||
export const afterEach = () => {
|
||||
expect(count).toBe(0);
|
||||
};
|
||||
|
||||
export const mustCall = (fn?: Function, exact?: number) => {
|
||||
count += exact || 1;
|
||||
return (...args: any[]) => {
|
||||
fn?.(...args);
|
||||
--count;
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user