diff --git a/packages/playwright-core/src/server/chromium/crPage.ts b/packages/playwright-core/src/server/chromium/crPage.ts index 05beba882c0c6..904ed5a479155 100644 --- a/packages/playwright-core/src/server/chromium/crPage.ts +++ b/packages/playwright-core/src/server/chromium/crPage.ts @@ -690,16 +690,15 @@ class FrameSession { if (!frame || this._eventBelongsToStaleFrame(frame._id)) return; const delegate = new CRExecutionContext(this._client, contextPayload); - let worldName: types.World; + let worldName: types.World|null = null; if (contextPayload.auxData && !!contextPayload.auxData.isDefault) worldName = 'main'; else if (contextPayload.name === UTILITY_WORLD_NAME) worldName = 'utility'; - else - return; const context = new dom.FrameExecutionContext(delegate, frame, worldName); (context as any)[contextDelegateSymbol] = delegate; - frame._contextCreated(worldName, context); + if (worldName) + frame._contextCreated(worldName, context); this._contextIdToContext.set(contextPayload.id, context); } diff --git a/packages/playwright-core/src/server/dom.ts b/packages/playwright-core/src/server/dom.ts index 55105bd50c3fc..05a8b4fda28e1 100644 --- a/packages/playwright-core/src/server/dom.ts +++ b/packages/playwright-core/src/server/dom.ts @@ -50,9 +50,9 @@ export function isNonRecoverableDOMError(error: Error) { export class FrameExecutionContext extends js.ExecutionContext { readonly frame: frames.Frame; private _injectedScriptPromise?: Promise; - readonly world: types.World; + readonly world: types.World | null; - constructor(delegate: js.ExecutionContextDelegate, frame: frames.Frame, world: types.World) { + constructor(delegate: js.ExecutionContextDelegate, frame: frames.Frame, world: types.World|null) { super(frame, delegate, world || 'content-script'); this.frame = frame; this.world = world; diff --git a/packages/playwright-core/src/server/firefox/ffPage.ts b/packages/playwright-core/src/server/firefox/ffPage.ts index d1066876ebd5a..6778a777f236e 100644 --- a/packages/playwright-core/src/server/firefox/ffPage.ts +++ b/packages/playwright-core/src/server/firefox/ffPage.ts @@ -163,16 +163,15 @@ export class FFPage implements PageDelegate { if (!frame) return; const delegate = new FFExecutionContext(this._session, executionContextId); - let worldName: types.World; + let worldName: types.World|null = null; if (auxData.name === UTILITY_WORLD_NAME) worldName = 'utility'; else if (!auxData.name) worldName = 'main'; - else - return; const context = new dom.FrameExecutionContext(delegate, frame, worldName); (context as any)[contextDelegateSymbol] = delegate; - frame._contextCreated(worldName, context); + if (worldName) + frame._contextCreated(worldName, context); this._contextIdToContext.set(executionContextId, context); } diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index c3954b48821a7..26ffd2dbab95a 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -502,16 +502,15 @@ export class WKPage implements PageDelegate { if (!frame) return; const delegate = new WKExecutionContext(this._session, contextPayload.id); - let worldName: types.World; + let worldName: types.World|null = null; if (contextPayload.type === 'normal') worldName = 'main'; else if (contextPayload.type === 'user' && contextPayload.name === UTILITY_WORLD_NAME) worldName = 'utility'; - else - return; const context = new dom.FrameExecutionContext(delegate, frame, worldName); (context as any)[contextDelegateSymbol] = delegate; - frame._contextCreated(worldName, context); + if (worldName) + frame._contextCreated(worldName, context); this._contextIdToContext.set(contextPayload.id, context); } diff --git a/tests/assets/extension-with-logging/background.js b/tests/assets/extension-with-logging/background.js new file mode 100644 index 0000000000000..3780fa3f212d2 --- /dev/null +++ b/tests/assets/extension-with-logging/background.js @@ -0,0 +1,5 @@ +console.log("Service worker script loaded"); + +chrome.runtime.onInstalled.addListener(() => { + console.log("Extension installed"); +}); \ No newline at end of file diff --git a/tests/assets/extension-with-logging/content.js b/tests/assets/extension-with-logging/content.js new file mode 100644 index 0000000000000..e718206c2a9c3 --- /dev/null +++ b/tests/assets/extension-with-logging/content.js @@ -0,0 +1 @@ +console.log("Test console log from a third-party execution context"); diff --git a/tests/assets/extension-with-logging/manifest.json b/tests/assets/extension-with-logging/manifest.json new file mode 100644 index 0000000000000..429dc77980182 --- /dev/null +++ b/tests/assets/extension-with-logging/manifest.json @@ -0,0 +1,17 @@ +{ + "manifest_version": 3, + "name": "Console Log Extension", + "version": "1.0", + "background": { + "service_worker": "background.js" + }, + "permissions": [ + "tabs" + ], + "content_scripts": [ + { + "matches": [""], + "js": ["content.js"] + } + ] + } \ No newline at end of file diff --git a/tests/library/chromium/launcher.spec.ts b/tests/library/chromium/launcher.spec.ts index eb0fc997adce5..f36a089fa7115 100644 --- a/tests/library/chromium/launcher.spec.ts +++ b/tests/library/chromium/launcher.spec.ts @@ -146,6 +146,27 @@ it('should support request/response events when using backgroundPage()', async ( await context.close(); }); +it('should report console messages from content script', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/32762' } +}, async ({ browserType, createUserDataDir, asset, server }) => { + const userDataDir = await createUserDataDir(); + const extensionPath = asset('extension-with-logging'); + const extensionOptions = { + headless: false, + args: [ + `--disable-extensions-except=${extensionPath}`, + `--load-extension=${extensionPath}`, + ], + }; + const context = await browserType.launchPersistentContext(userDataDir, extensionOptions); + const page = await context.newPage(); + const consolePromise = page.waitForEvent('console', e => e.text().includes('Test console log from a third-party execution context')); + await page.goto(server.EMPTY_PAGE); + const message = await consolePromise; + expect(message.text()).toContain('Test console log from a third-party execution context'); + await context.close(); +}); + it('should not create pages automatically', async ({ browserType }) => { const browser = await browserType.launch(); const browserSession = await browser.newBrowserCDPSession();