diff --git a/packages/playwright-core/src/client/waiter.ts b/packages/playwright-core/src/client/waiter.ts index 7c239baa2f..7b57fe8960 100644 --- a/packages/playwright-core/src/client/waiter.ts +++ b/packages/playwright-core/src/client/waiter.ts @@ -30,7 +30,7 @@ export class Waiter { private _channelOwner: ChannelOwner; private _waitId: string; private _error: string | undefined; - private _savedZone: Zone | undefined; + private _savedZone: Zone; constructor(channelOwner: ChannelOwner, event: string) { this._waitId = createGuid(); @@ -107,12 +107,11 @@ export class Waiter { } } -function waitForEvent(emitter: EventEmitter, event: string, savedZone: Zone | undefined, predicate?: (arg: T) => boolean | Promise): { promise: Promise, dispose: () => void } { +function waitForEvent(emitter: EventEmitter, event: string, savedZone: Zone, predicate?: (arg: T) => boolean | Promise): { promise: Promise, dispose: () => void } { let listener: (eventArg: any) => void; const promise = new Promise((resolve, reject) => { listener = async (eventArg: any) => { - // Reset apiZone and expectZone, but restore step data. - await zones.runInZone(savedZone?.copyWithoutTypes(['apiZone', 'expectZone']), async () => { + await savedZone.run(async () => { try { if (predicate && !(await predicate(eventArg))) return; diff --git a/packages/playwright-core/src/utils/zones.ts b/packages/playwright-core/src/utils/zones.ts index 8dfa6404fc..dbd3d54f6f 100644 --- a/packages/playwright-core/src/utils/zones.ts +++ b/packages/playwright-core/src/utils/zones.ts @@ -22,12 +22,7 @@ class ZoneManager { private readonly _asyncLocalStorage = new AsyncLocalStorage(); run(type: ZoneType, data: T, func: () => R): R { - const current = this._asyncLocalStorage.getStore(); - const zone = Zone.createWithData(current, type, data); - return this.runInZone(zone, func); - } - - runInZone(zone: Zone | undefined, func: () => R): R { + const zone = Zone.createWithData(this._asyncLocalStorage, type, data); return this._asyncLocalStorage.run(zone, func); } @@ -36,8 +31,8 @@ class ZoneManager { return zone?.get(type); } - currentZone(): Zone | undefined { - return this._asyncLocalStorage.getStore(); + currentZone(): Zone { + return this._asyncLocalStorage.getStore() ?? Zone.createEmpty(this._asyncLocalStorage); } exitZones(func: () => R): R { @@ -46,25 +41,33 @@ class ZoneManager { } export class Zone { - private readonly store: Map; + private readonly _asyncLocalStorage: AsyncLocalStorage; + private readonly _data: Map; - static createWithData(currentZone: Zone | undefined, type: ZoneType, data: unknown) { - const store = new Map(currentZone?.store.entries() ?? []); + static createWithData(asyncLocalStorage: AsyncLocalStorage, type: ZoneType, data: unknown) { + const store = new Map(asyncLocalStorage.getStore()?._data); store.set(type, data); - return new Zone(store); + return new Zone(asyncLocalStorage, store); } - private constructor(store: Map) { - this.store = store; + static createEmpty(asyncLocalStorage: AsyncLocalStorage) { + return new Zone(asyncLocalStorage, new Map()); } - copyWithoutTypes(types: ZoneType[]): Zone { - const store = new Map(this.store.entries().filter(([type]) => !types.includes(type))); - return new Zone(store); + private constructor(asyncLocalStorage: AsyncLocalStorage, store: Map) { + this._asyncLocalStorage = asyncLocalStorage; + this._data = store; + } + + run(func: () => R): R { + // Reset apiZone and expectZone, but restore stepZone. + const entries = [...this._data.entries()].filter(([type]) => (type !== 'apiZone' && type !== 'expectZone')); + const resetZone = new Zone(this._asyncLocalStorage, new Map(entries)); + return this._asyncLocalStorage.run(resetZone, func); } get(type: ZoneType): T | undefined { - return this.store.get(type) as T | undefined; + return this._data.get(type) as T | undefined; } }