From 9dd823462c5abffd87101bbfb3704392b95406a2 Mon Sep 17 00:00:00 2001 From: Harsh Mathur Date: Mon, 6 Jul 2026 16:18:21 +0000 Subject: [PATCH 1/4] fix(mcp): await init page before screenshot Fixes: https://github.com/microsoft/playwright-mcp/issues/1671 --- .../src/tools/backend/screenshot.ts | 2 ++ .../playwright-core/src/tools/backend/tab.ts | 4 ++++ tests/mcp/init-page.spec.ts | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/packages/playwright-core/src/tools/backend/screenshot.ts b/packages/playwright-core/src/tools/backend/screenshot.ts index 0f83b638ace85..642fde2d76c40 100644 --- a/packages/playwright-core/src/tools/backend/screenshot.ts +++ b/packages/playwright-core/src/tools/backend/screenshot.ts @@ -57,6 +57,8 @@ const screenshot = defineTabTool({ const screenshotTargetLabel = params.target ? params.element || 'element' : (params.fullPage ? 'full page' : 'viewport'); const target = params.target ? await tab.targetLocator({ element: params.element, target: params.target }) : null; + if (!target) + await tab.waitForInitialized(); const data = target ? await target.locator.screenshot(options) : await tab.page.screenshot(options); const resolvedFile = await response.resolveClientFile({ prefix: target ? 'element' : 'page', ext: fileType, suggestedFilename: params.filename }, `Screenshot of ${screenshotTargetLabel}`); diff --git a/packages/playwright-core/src/tools/backend/tab.ts b/packages/playwright-core/src/tools/backend/tab.ts index 676f5da4e9040..441f8a9f75b00 100644 --- a/packages/playwright-core/src/tools/backend/tab.ts +++ b/packages/playwright-core/src/tools/backend/tab.ts @@ -148,6 +148,10 @@ export class Tab extends EventEmitter { this._consoleLog.stop(); } + async waitForInitialized() { + await this._initializedPromise; + } + static forPage(page: playwright.Page): Tab | undefined { // eslint-disable-next-line no-restricted-syntax return (page as any)[tabSymbol]; diff --git a/tests/mcp/init-page.spec.ts b/tests/mcp/init-page.spec.ts index c2ea53aaafc59..6e708116a0f36 100644 --- a/tests/mcp/init-page.spec.ts +++ b/tests/mcp/init-page.spec.ts @@ -94,6 +94,27 @@ test('init-page surfaces load errors instead of silently dropping them', async ( expect(JSON.stringify(response.content)).toContain('boom from initPage'); }); +test('init-page is applied before the first page screenshot', async ({ startClient }) => { + const initPagePath = test.info().outputPath('screenshotInitPage.ts'); + await fs.promises.writeFile(initPagePath, ` + export default async ({ page }) => { + page.screenshot = async () => { + throw new Error('initPage screenshot hook applied'); + }; + }; + `); + + const { client } = await startClient({ + args: [`--init-page=${initPagePath}`], + }); + const response: any = await client.callTool({ + name: 'browser_take_screenshot', + arguments: {}, + }); + expect(response.isError).toBe(true); + expect(JSON.stringify(response.content)).toContain('initPage screenshot hook applied'); +}); + test('--init-page w/ --init-script', async ({ startClient, server }) => { server.setContent('/', `
Hello world
From 60bd1c8848ba2c3c8edbd60f3cc3fdb8e3210b98 Mon Sep 17 00:00:00 2001 From: Harsh Mathur Date: Tue, 7 Jul 2026 08:55:51 +0000 Subject: [PATCH 2/4] fix(mcp): move init-page wait from screenshot to ensureTab Per review feedback, await tab.waitForInitialized() in context.ensureTab() so all tools benefit from waiting for init-page scripts to complete, not just screenshot. Keep waitForInitialized() on Tab for direct use when needed. --- packages/playwright-core/src/tools/backend/context.ts | 1 + packages/playwright-core/src/tools/backend/screenshot.ts | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/playwright-core/src/tools/backend/context.ts b/packages/playwright-core/src/tools/backend/context.ts index 8d0c7399dcc9b..c8f96c13a731e 100644 --- a/packages/playwright-core/src/tools/backend/context.ts +++ b/packages/playwright-core/src/tools/backend/context.ts @@ -190,6 +190,7 @@ export class Context { await this.newTab(); if (crashed) this._currentTab!.logErrorMessage('Page crashed and was reset to about:blank.'); + await this._currentTab!.waitForInitialized(); return this._currentTab!; } diff --git a/packages/playwright-core/src/tools/backend/screenshot.ts b/packages/playwright-core/src/tools/backend/screenshot.ts index 642fde2d76c40..0f83b638ace85 100644 --- a/packages/playwright-core/src/tools/backend/screenshot.ts +++ b/packages/playwright-core/src/tools/backend/screenshot.ts @@ -57,8 +57,6 @@ const screenshot = defineTabTool({ const screenshotTargetLabel = params.target ? params.element || 'element' : (params.fullPage ? 'full page' : 'viewport'); const target = params.target ? await tab.targetLocator({ element: params.element, target: params.target }) : null; - if (!target) - await tab.waitForInitialized(); const data = target ? await target.locator.screenshot(options) : await tab.page.screenshot(options); const resolvedFile = await response.resolveClientFile({ prefix: target ? 'element' : 'page', ext: fileType, suggestedFilename: params.filename }, `Screenshot of ${screenshotTargetLabel}`); From 406ae34e0b347f9bef3ab9e9b5f15dddd2e4575e Mon Sep 17 00:00:00 2001 From: Harsh Mathur Date: Wed, 8 Jul 2026 06:46:20 +0000 Subject: [PATCH 3/4] chore: retrigger ci From f2f3124a284603497533babb31c38bef4c2b31d5 Mon Sep 17 00:00:00 2001 From: Harsh Mathur Date: Wed, 8 Jul 2026 17:21:36 +0000 Subject: [PATCH 4/4] chore: retrigger ci