diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index a7aad29c90..b4fef0d2c1 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -590,6 +590,10 @@ scheme.BrowserCloseParams = tOptional(tObject({})); scheme.BrowserCloseResult = tOptional(tObject({})); scheme.BrowserKillForTestsParams = tOptional(tObject({})); scheme.BrowserKillForTestsResult = tOptional(tObject({})); +scheme.BrowserDefaultUserAgentForTestParams = tOptional(tObject({})); +scheme.BrowserDefaultUserAgentForTestResult = tObject({ + userAgent: tString, +}); scheme.BrowserNewContextParams = tObject({ noDefaultViewport: tOptional(tBoolean), viewport: tOptional(tObject({ diff --git a/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts b/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts index 43fdab9e48..3d3dcd8213 100644 --- a/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts @@ -59,6 +59,10 @@ export class BrowserDispatcher extends Dispatcher { + return { userAgent: this._object.userAgent() }; + } + async newBrowserCDPSession(): Promise { if (!this._object.options.isChromium) throw new Error(`CDP session is only available in Chromium`); @@ -116,6 +120,10 @@ export class ConnectedBrowserDispatcher extends Dispatcher { + throw new Error('Client should not send us Browser.defaultUserAgentForTest'); + } + async newBrowserCDPSession(): Promise { if (!this._object.options.isChromium) throw new Error(`CDP session is only available in Chromium`); diff --git a/packages/playwright-core/src/server/webkit/wkBrowser.ts b/packages/playwright-core/src/server/webkit/wkBrowser.ts index d62752aece..84ff6ac30f 100644 --- a/packages/playwright-core/src/server/webkit/wkBrowser.ts +++ b/packages/playwright-core/src/server/webkit/wkBrowser.ts @@ -50,6 +50,7 @@ export class WKBrowser extends Browser { browser._browserSession.send('Playwright.enable'), ]; if (options.persistent) { + options.persistent.userAgent ||= DEFAULT_USER_AGENT; browser._defaultContext = new WKBrowserContext(browser, undefined, options.persistent); promises.push((browser._defaultContext as WKBrowserContext)._initialize()); } diff --git a/packages/protocol/src/channels.ts b/packages/protocol/src/channels.ts index 32c287d289..7e968288b7 100644 --- a/packages/protocol/src/channels.ts +++ b/packages/protocol/src/channels.ts @@ -1083,6 +1083,7 @@ export interface BrowserChannel extends BrowserEventTarget, Channel { _type_Browser: boolean; close(params?: BrowserCloseParams, metadata?: CallMetadata): Promise; killForTests(params?: BrowserKillForTestsParams, metadata?: CallMetadata): Promise; + defaultUserAgentForTest(params?: BrowserDefaultUserAgentForTestParams, metadata?: CallMetadata): Promise; newContext(params: BrowserNewContextParams, metadata?: CallMetadata): Promise; newContextForReuse(params: BrowserNewContextForReuseParams, metadata?: CallMetadata): Promise; newBrowserCDPSession(params?: BrowserNewBrowserCDPSessionParams, metadata?: CallMetadata): Promise; @@ -1096,6 +1097,11 @@ export type BrowserCloseResult = void; export type BrowserKillForTestsParams = {}; export type BrowserKillForTestsOptions = {}; export type BrowserKillForTestsResult = void; +export type BrowserDefaultUserAgentForTestParams = {}; +export type BrowserDefaultUserAgentForTestOptions = {}; +export type BrowserDefaultUserAgentForTestResult = { + userAgent: string, +}; export type BrowserNewContextParams = { noDefaultViewport?: boolean, viewport?: { diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index 005b67458b..1ced5dbf89 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -897,6 +897,10 @@ Browser: killForTests: + defaultUserAgentForTest: + returns: + userAgent: string + newContext: parameters: $mixin: ContextOptions diff --git a/tests/library/browsercontext-basic.spec.ts b/tests/library/browsercontext-basic.spec.ts index 53a1afbf86..07f026123e 100644 --- a/tests/library/browsercontext-basic.spec.ts +++ b/tests/library/browsercontext-basic.spec.ts @@ -288,3 +288,8 @@ it('should emulate media in cross-process iframe', async ({ browser, server }) = expect(await frame.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true); await page.close(); }); + +it('default user agent', async ({ launchPersistent, browser, page }) => { + const { userAgent } = await (browser as any)._channel.defaultUserAgentForTest(); + expect(await page.evaluate(() => navigator.userAgent)).toBe(userAgent); +}); diff --git a/tests/library/defaultbrowsercontext-2.spec.ts b/tests/library/defaultbrowsercontext-2.spec.ts index 4babd8e278..99d46d1f43 100644 --- a/tests/library/defaultbrowsercontext-2.spec.ts +++ b/tests/library/defaultbrowsercontext-2.spec.ts @@ -233,3 +233,9 @@ it('should support har option', async ({ launchPersistent, asset }) => { await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(255, 0, 0)'); }); +it('user agent is up to date', async ({ launchPersistent, browser }) => { + const { userAgent } = await (browser as any)._channel.defaultUserAgentForTest(); + const { context, page } = await launchPersistent(); + expect(await page.evaluate(() => navigator.userAgent)).toBe(userAgent); + await context.close(); +});