diff --git a/src/server/crx.ts b/src/server/crx.ts index 10d22ff5b..5023314b7 100644 --- a/src/server/crx.ts +++ b/src/server/crx.ts @@ -38,7 +38,7 @@ import { generateCode } from 'playwright-core/lib/server/codegen/language'; import { languageSet } from 'playwright-core/lib/server/codegen/languages'; import { deviceDescriptors } from 'playwright-core/lib/server/deviceDescriptors'; import type { DeviceDescriptor } from 'playwright-core/lib/server/types'; -import { RecorderApp } from 'playwright-core/lib/server/recorder/recorderApp'; +import { EmptyRecorderApp, RecorderApp } from 'playwright-core/lib/server/recorder/recorderApp'; import type { LanguageGeneratorOptions } from 'playwright-core/lib/server/codegen/types'; const kTabIdSymbol = Symbol('kTabIdSymbol'); @@ -120,7 +120,12 @@ export class Crx extends SdkObject { }); // override factory otherwise it will fail because the default factory tries to launch a new playwright app RecorderApp.factory = (): IRecorderAppFactory => { - return recorder => crxApp._createRecorderApp(recorder); + return async recorder => { + if (recorder instanceof Recorder && recorder._context === context) + return await crxApp._createRecorderApp(recorder); + else + return new EmptyRecorderApp(); + }; }; return crxApp; } @@ -363,6 +368,10 @@ export class CrxApplication extends SdkObject { return this._recorderApp; } + _recorder() { + return this._recorderApp?._recorder; + } + private onWindowRemoved = async () => { const windows = await chrome.windows.getAll(); if (this.isIncognito() && windows.every(w => !w.incognito)) diff --git a/src/server/recorder/crxPlayer.ts b/src/server/recorder/crxPlayer.ts index 9fea66d94..d94f2eac8 100644 --- a/src/server/recorder/crxPlayer.ts +++ b/src/server/recorder/crxPlayer.ts @@ -29,6 +29,7 @@ import { toClickOptions } from 'playwright-core/lib/server/recorder/recorderRunn import { parseAriaSnapshot } from 'playwright-core/lib/server/ariaSnapshot'; import { serverSideCallMetadata } from 'playwright-core/lib/server'; import type { Crx } from '../crx'; +import type { InstrumentationListener } from 'playwright-core/lib/server/instrumentation'; class Stopped extends Error {} @@ -53,10 +54,9 @@ export default class CrxPlayer extends EventEmitter { this._crx = crx; } - async pause(context?: BrowserContext) { + async pause() { if (!this._pause) { - if (!context) - context = (await this._crx.get({ incognito: false }))!._context; + const context = (await this._crx.get({ incognito: false }))!._context; const pauseAction = { action: { name: 'pause' }, frame: { pageAlias: 'page', framePath: [] }, @@ -84,6 +84,22 @@ export default class CrxPlayer extends EventEmitter { page = context.pages()[0] ?? await context.newPage(serverSideCallMetadata()); } + const crxApp = await this._crx.get({ incognito: false }); + const recorder = crxApp?._recorder(); + let instrumentationListener: InstrumentationListener | undefined; + + if (recorder && crxApp && crxApp._context !== context) { + // we intercept incognito call logs and forward them into the recorder + const instrumentationListener: InstrumentationListener = { + onBeforeCall: recorder.onBeforeCall.bind(recorder), + onBeforeInputAction: recorder.onBeforeInputAction.bind(recorder), + onCallLog: recorder.onCallLog.bind(recorder), + onAfterCall: recorder.onAfterCall.bind(recorder), + }; + if (instrumentationListener) + context.instrumentation.addListener(instrumentationListener, context); + } + this._pageAliases.clear(); this._pageAliases.set(page, 'page'); this.emit('start'); @@ -101,7 +117,9 @@ export default class CrxPlayer extends EventEmitter { throw e; } finally { this._currAction = undefined; - this.pause(context).catch(() => {}); + this.pause().catch(() => {}); + if (instrumentationListener) + context.instrumentation.removeListener(instrumentationListener); } } diff --git a/src/server/recorder/crxRecorderApp.ts b/src/server/recorder/crxRecorderApp.ts index 96a6b5e94..524f275c5 100644 --- a/src/server/recorder/crxRecorderApp.ts +++ b/src/server/recorder/crxRecorderApp.ts @@ -74,10 +74,6 @@ export class CrxRecorderApp extends EventEmitter implements IRecorderApp { }); } - setPlayInIncognito(playInIncognito: boolean) { - this._playInIncognito = playInIncognito; - } - async open(options?: channels.CrxApplicationShowRecorderParams) { const mode = options?.mode ?? 'none'; const language = options?.language ?? 'playwright-test';