diff --git a/playwriter/src/executor.ts b/playwriter/src/executor.ts index 00c3643..d2add02 100644 --- a/playwriter/src/executor.ts +++ b/playwriter/src/executor.ts @@ -219,6 +219,7 @@ export class PlaywrightExecutor { private browserLogs: Map = new Map() private lastSnapshots: WeakMap = new WeakMap() private lastRefToLocator: WeakMap> = new WeakMap() + private popupWarnings: string[] = [] private scopedFs: ScopedFS private sandboxedRequire: NodeRequire @@ -305,6 +306,28 @@ export class PlaywrightExecutor { } } + private setupPageListeners(page: Page) { + this.setupPageConsoleListener(page) + this.setupPopupDetection(page) + } + + private setupPopupDetection(page: Page) { + // Check if this page was opened by window.open() (has an opener) + const opener = page.opener() + if (!opener) { + return + } + const context = page.context() + const pages = context.pages() + const pageIndex = pages.indexOf(page) + const url = page.url() + this.popupWarnings.push( + `Popup window detected (page index ${pageIndex}, url: ${url}). ` + + `Popup windows cannot be controlled by playwriter. ` + + `Repeat the interaction in a way that does not open a popup, or navigate to the URL directly in a new tab.`, + ) + } + private setupPageConsoleListener(page: Page) { // Use targetId() if available, fallback to internal _guid for CDP connections const targetId = page.targetId() || (page as any)._guid as string | undefined @@ -410,7 +433,7 @@ export class PlaywrightExecutor { const context = contexts.length > 0 ? contexts[0] : await browser.newContext() context.on('page', (page) => { - this.setupPageConsoleListener(page) + this.setupPageListeners(page) }) context.pages().forEach((p) => this.setupPageConsoleListener(p)) @@ -485,7 +508,7 @@ export class PlaywrightExecutor { const context = contexts.length > 0 ? contexts[0] : await browser.newContext() context.on('page', (page) => { - this.setupPageConsoleListener(page) + this.setupPageListeners(page) }) context.pages().forEach((p) => this.setupPageConsoleListener(p)) @@ -861,6 +884,12 @@ export class PlaywrightExecutor { } } + // Drain any popup warnings that fired during execution + if (this.popupWarnings.length > 0) { + responseText += this.popupWarnings.map((w) => `[WARNING] ${w}`).join('\n') + '\n' + this.popupWarnings = [] + } + if (!responseText.trim()) { responseText = 'Code executed successfully (no output)' }