chore: init eventEmitter w/ platform (#34809)

This commit is contained in:
Pavel Feldman 2025-02-14 17:06:11 -08:00 committed by GitHub
parent 145b6bf4fe
commit 024a52821a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 48 additions and 51 deletions

View File

@ -393,7 +393,7 @@ export class AndroidWebView extends EventEmitter implements api.AndroidWebView {
private _pagePromise: Promise<Page> | undefined;
constructor(device: AndroidDevice, data: channels.AndroidWebView) {
super();
super(device._platform);
this._device = device;
this._data = data;
}

View File

@ -38,21 +38,20 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
readonly _channel: T;
readonly _initializer: channels.InitializerTraits<T>;
_logger: Logger | undefined;
readonly _platform: Platform;
readonly _instrumentation: ClientInstrumentation;
private _eventToSubscriptionMapping: Map<string, string> = new Map();
private _isInternalType = false;
_wasCollected: boolean = false;
constructor(parent: ChannelOwner | Connection, type: string, guid: string, initializer: channels.InitializerTraits<T>) {
super();
const connection = parent instanceof ChannelOwner ? parent._connection : parent;
super(connection._platform);
this.setMaxListeners(0);
this._connection = parent instanceof ChannelOwner ? parent._connection : parent;
this._connection = connection;
this._type = type;
this._guid = guid;
this._parent = parent instanceof ChannelOwner ? parent : undefined;
this._instrumentation = this._connection._instrumentation;
this._platform = this._connection.platform;
this._connection._objects.set(guid, this);
if (this._parent) {
@ -60,7 +59,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
this._logger = this._parent._logger;
}
this._channel = this._createChannel(new EventEmitter());
this._channel = this._createChannel(new EventEmitter(connection._platform));
this._initializer = initializer;
}

View File

@ -16,14 +16,12 @@
import { Connection } from './connection';
import { setPlatformForSelectors } from './selectors';
import { setPlatformForEventEmitter } from './eventEmitter';
import { setIsUnderTestForValidator } from '../protocol/validatorPrimitives';
import type { Platform } from './platform';
export function createConnectionFactory(platform: Platform): () => Connection {
setPlatformForSelectors(platform);
setPlatformForEventEmitter(platform);
setIsUnderTestForValidator(() => platform.isUnderTest());
return () => new Connection(platform);
}

View File

@ -78,15 +78,13 @@ export class Connection extends EventEmitter {
toImpl: ((client: ChannelOwner) => any) | undefined;
private _tracingCount = 0;
readonly _instrumentation: ClientInstrumentation;
readonly platform: Platform;
// Used from @playwright/test fixtures -> TODO remove?
readonly headers: HeadersArray;
constructor(platform: Platform, localUtils?: LocalUtils, instrumentation?: ClientInstrumentation, headers: HeadersArray = []) {
super();
super(platform);
this._instrumentation = instrumentation || createInstrumentation();
this._localUtils = localUtils;
this.platform = platform;
this._rootObject = new Root(this);
this.headers = headers;
}
@ -136,9 +134,9 @@ export class Connection extends EventEmitter {
const type = object._type;
const id = ++this._lastId;
const message = { id, guid, method, params };
if (this.platform.isLogEnabled('channel')) {
if (this._platform.isLogEnabled('channel')) {
// Do not include metadata in debug logs to avoid noise.
this.platform.log('channel', 'SEND> ' + JSON.stringify(message));
this._platform.log('channel', 'SEND> ' + JSON.stringify(message));
}
const location = frames[0] ? { file: frames[0].file, line: frames[0].line, column: frames[0].column } : undefined;
const metadata: channels.Metadata = { apiName, location, internal: !apiName, stepId };
@ -146,7 +144,7 @@ export class Connection extends EventEmitter {
this._localUtils?.addStackToTracingNoReply({ callData: { stack: frames, id } }).catch(() => {});
// We need to exit zones before calling into the server, otherwise
// when we receive events from the server, we would be in an API zone.
this.platform.zones.empty.run(() => this.onmessage({ ...message, metadata }));
this._platform.zones.empty.run(() => this.onmessage({ ...message, metadata }));
return await new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject, apiName, type, method }));
}
@ -156,15 +154,15 @@ export class Connection extends EventEmitter {
const { id, guid, method, params, result, error, log } = message as any;
if (id) {
if (this.platform.isLogEnabled('channel'))
this.platform.log('channel', '<RECV ' + JSON.stringify(message));
if (this._platform.isLogEnabled('channel'))
this._platform.log('channel', '<RECV ' + JSON.stringify(message));
const callback = this._callbacks.get(id);
if (!callback)
throw new Error(`Cannot find command to respond: ${id}`);
this._callbacks.delete(id);
if (error && !result) {
const parsedError = parseError(error);
rewriteErrorMessage(parsedError, parsedError.message + formatCallLog(this.platform, log));
rewriteErrorMessage(parsedError, parsedError.message + formatCallLog(this._platform, log));
callback.reject(parsedError);
} else {
const validator = findValidator(callback.type, callback.method, 'Result');
@ -173,8 +171,8 @@ export class Connection extends EventEmitter {
return;
}
if (this.platform.isLogEnabled('channel'))
this.platform.log('channel', '<EVENT ' + JSON.stringify(message));
if (this._platform.isLogEnabled('channel'))
this._platform.log('channel', '<EVENT ' + JSON.stringify(message));
if (method === '__create__') {
this._createRemoteObject(guid, params.type, params.guid, params.initializer);
return;

View File

@ -22,8 +22,6 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import { emptyPlatform } from './platform';
import type { EventEmitter as EventEmitterType } from 'events';
import type { Platform } from './platform';
@ -31,12 +29,6 @@ type EventType = string | symbol;
type Listener = (...args: any[]) => any;
type EventMap = Record<EventType, Listener | Listener[]>;
let platform = emptyPlatform;
export function setPlatformForEventEmitter(p: Platform) {
platform = p;
}
export class EventEmitter implements EventEmitterType {
private _events: EventMap | undefined = undefined;
@ -44,8 +36,10 @@ export class EventEmitter implements EventEmitterType {
private _maxListeners: number | undefined = undefined;
readonly _pendingHandlers = new Map<EventType, Set<Promise<void>>>();
private _rejectionHandler: ((error: Error) => void) | undefined;
readonly _platform: Platform;
constructor() {
constructor(platform: Platform) {
this._platform = platform;
if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) {
this._events = Object.create(null);
this._eventsCount = 0;
@ -63,7 +57,7 @@ export class EventEmitter implements EventEmitterType {
}
getMaxListeners(): number {
return this._maxListeners === undefined ? platform.defaultMaxListeners() : this._maxListeners;
return this._maxListeners === undefined ? this._platform.defaultMaxListeners() : this._maxListeners;
}
emit(type: EventType, ...args: any[]): boolean {
@ -161,7 +155,7 @@ export class EventEmitter implements EventEmitterType {
w.emitter = this;
w.type = type;
w.count = existing.length;
if (!platform.isUnderTest()) {
if (!this._platform.isUnderTest()) {
// eslint-disable-next-line no-console
console.warn(w);
}

View File

@ -64,7 +64,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.FrameInitializer) {
super(parent, type, guid, initializer);
this._eventEmitter = new EventEmitter();
this._eventEmitter = new EventEmitter(parent._platform);
this._eventEmitter.setMaxListeners(0);
this._parentFrame = Frame.fromNullable(initializer.parentFrame);
if (this._parentFrame)

View File

@ -24,7 +24,7 @@ export async function connectOverWebSocket(parentConnection: Connection, params:
const localUtils = parentConnection.localUtils();
const transport = localUtils ? new JsonPipeTransport(localUtils) : new WebSocketTransport();
const connectHeaders = await transport.connect(params);
const connection = new Connection(parentConnection.platform, localUtils, parentConnection._instrumentation, connectHeaders);
const connection = new Connection(parentConnection._platform, localUtils, parentConnection._instrumentation, connectHeaders);
connection.markAsRemote();
connection.on('close', () => transport.close());

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test.describe('EventEmitter tests', () => {

View File

@ -21,7 +21,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import events from 'events';
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
import { EventEmitter } from './utils';
import { setUnderTest } from '../../../packages/playwright-core/lib/server/utils/debug';
import { test, expect } from '@playwright/test';
import * as common from './utils';

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test.describe('EventEmitter', () => {

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test('Listener count test', () => {

View File

@ -21,7 +21,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { test, expect } from '@playwright/test';
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
import { EventEmitter } from './utils';
test('listeners empty check', () => {
const e = new EventEmitter();

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
const listener = () => {};

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test('emit maxListeners on e', () => {

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test('EventEmitter prototype test', () => {

View File

@ -21,7 +21,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { test, expect } from '@playwright/test';
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
import { EventEmitter } from './utils';
let callbacks_called = [];
const e = new EventEmitter();

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test('should work', () => {

View File

@ -21,7 +21,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { test, expect } from '@playwright/test';
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
import { EventEmitter } from './utils';
import * as common from './utils';
test('should work', () => {

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test('EventEmitter functionality', () => {

View File

@ -16,7 +16,7 @@
*/
import { ManualPromise } from '../../../packages/playwright-core/lib/utils/isomorphic/manualPromise';
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
import { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test('should not throw with ignoreErrors', async () => {

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
import * as common from './utils';

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
import * as common from './utils';

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test('set max listeners test', () => {

View File

@ -21,7 +21,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { test, expect } from '@playwright/test';
import { EventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
import { EventEmitter } from './utils';
test('should support special event names', () => {

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
class MyEE extends EventEmitter {

View File

@ -20,7 +20,7 @@
// 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 { EventEmitter } from './utils';
import { test, expect } from '@playwright/test';
test('should support symbols', () => {

View File

@ -20,6 +20,8 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { expect } from '@playwright/test';
import { EventEmitter as OriginalEventEmitter } from '../../../packages/playwright-core/lib/client/eventEmitter';
import { nodePlatform } from '../../../packages/playwright-core/lib/server/utils/nodePlatform';
export const mustNotCall = (msg?: string) => {
return function mustNotCall() {
@ -44,3 +46,9 @@ export const mustCall = (fn?: Function, exact?: number) => {
--count;
};
};
export class EventEmitter extends OriginalEventEmitter {
constructor() {
super(nodePlatform);
}
}