diff --git a/docs/api.md b/docs/api.md index 34ef02d644e9a..d80daf316ffc5 100644 --- a/docs/api.md +++ b/docs/api.md @@ -180,7 +180,7 @@ * [page.setJavaScriptEnabled(enabled)](#pagesetjavascriptenabledenabled) * [page.setOfflineMode(enabled)](#pagesetofflinemodeenabled) * [page.setRequestInterception(value)](#pagesetrequestinterceptionvalue) - * [page.setUserAgent(userAgent)](#pagesetuseragentuseragent) + * [page.setUserAgent(userAgent[, userAgentMetadata])](#pagesetuseragentuseragent-useragentmetadata) * [page.setViewport(viewport)](#pagesetviewportviewport) * [page.tap(selector)](#pagetapselector) * [page.target()](#pagetarget) @@ -942,7 +942,7 @@ the method will return an array with all the targets in all browser contexts. - returns: <[Promise]<[string]>> Promise which resolves to the browser's original user agent. -> **NOTE** Pages can override browser user agent with [page.setUserAgent](#pagesetuseragentuseragent) +> **NOTE** Pages can override browser user agent with [page.setUserAgent](#pagesetuseragentuseragent-useragentdata) #### browser.version() @@ -1558,7 +1558,7 @@ const puppeteer = require('puppeteer'); Emulates given device metrics and user agent. This method is a shortcut for calling two methods: -- [page.setUserAgent(userAgent)](#pagesetuseragentuseragent) +- [page.setUserAgent(userAgent)](#pagesetuseragentuseragent-useragentdata) - [page.setViewport(viewport)](#pagesetviewportviewport) To aid emulation, Puppeteer provides a list of device descriptors that can be obtained via the [`puppeteer.devices`](#puppeteerdevices). @@ -2344,11 +2344,39 @@ const puppeteer = require('puppeteer'); })(); ``` -#### page.setUserAgent(userAgent) +#### page.setUserAgent(userAgent[, userAgentMetadata]) - `userAgent` <[string]> Specific user agent to use in this page +- `userAgentMetadata` <[Object]> Optional user agent data to use in this page. Any + values not provided will use the client's default. + - `brands` <[Array]<[Object]>> Optional brand information + - `brand` <[string]> Browser or client brand name. + - `version` <[string]> Browser or client major version. + - `fullVersion` <[string]> Optional browser or client full version. + - `platform` <[string]> Operating system name. + - `platformVersion` <[string]> Operating system version. + - `architecture` <[string]> CPU architecture. + - `model` <[string]> Device model. + - `mobile` <[boolean]> Indicate if this is a mobile device. - returns: <[Promise]> Promise which resolves when the user agent is set. +> **NOTE** support for `userAgentMetadata` is experimental in the DevTools +> protocol and more properties will be added. + +Providing the optional `userAgentMetadata` header will update the related +entries in `navigator.userAgentData` and associated `Sec-CH-UA`* headers. + +```js +const page = await browser.newPage(); +await page.setUserAgent('MyBrowser', { + architecture: 'My1', + mobile: false, + model: 'Mybook', + platform: 'MyOS', + platformVersion: '3.1', +}); +``` + #### page.setViewport(viewport) - `viewport` <[Object]> diff --git a/src/common/NetworkManager.ts b/src/common/NetworkManager.ts index 0fdb778d4d54e..ab4e6fe13aee3 100644 --- a/src/common/NetworkManager.ts +++ b/src/common/NetworkManager.ts @@ -218,8 +218,14 @@ export class NetworkManager extends EventEmitter { }); } - async setUserAgent(userAgent: string): Promise { - await this._client.send('Network.setUserAgentOverride', { userAgent }); + async setUserAgent( + userAgent: string, + userAgentMetadata?: Protocol.Emulation.UserAgentMetadata + ): Promise { + await this._client.send('Network.setUserAgentOverride', { + userAgent: userAgent, + userAgentMetadata: userAgentMetadata, + }); } async setCacheEnabled(enabled: boolean): Promise { diff --git a/src/common/Page.ts b/src/common/Page.ts index 23082a8a5f647..e0648c1fd5fe0 100644 --- a/src/common/Page.ts +++ b/src/common/Page.ts @@ -1383,10 +1383,17 @@ export class Page extends EventEmitter { /** * @param userAgent - Specific user agent to use in this page + * @param userAgentData - Specific user agent client hint data to use in this + * page * @returns Promise which resolves when the user agent is set. */ - async setUserAgent(userAgent: string): Promise { - return this._frameManager.networkManager().setUserAgent(userAgent); + async setUserAgent( + userAgent: string, + userAgentMetadata?: Protocol.Emulation.UserAgentMetadata + ): Promise { + return this._frameManager + .networkManager() + .setUserAgent(userAgent, userAgentMetadata); } /** diff --git a/test/page.spec.ts b/test/page.spec.ts index de8b56f370d6f..f81851c5fad4b 100644 --- a/test/page.spec.ts +++ b/test/page.spec.ts @@ -998,6 +998,44 @@ describe('Page', function () { 'iPhone' ); }); + itFailsFirefox('should work with additional userAgentMetdata', async () => { + const { page, server } = getTestState(); + + await page.setUserAgent('MockBrowser', { + architecture: 'Mock1', + mobile: false, + model: 'Mockbook', + platform: 'MockOS', + platformVersion: '3.1', + }); + const [request] = await Promise.all([ + server.waitForRequest('/empty.html'), + page.goto(server.EMPTY_PAGE), + ]); + expect( + await page.evaluate(() => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore: userAgentData not yet in TypeScript DOM API + return navigator.userAgentData.mobile; + }) + ).toBe(false); + + const uaData = await page.evaluate(() => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore: userAgentData not yet in TypeScript DOM API + return navigator.userAgentData.getHighEntropyValues([ + 'architecture', + 'model', + 'platform', + 'platformVersion', + ]); + }); + expect(uaData['architecture']).toBe('Mock1'); + expect(uaData['model']).toBe('Mockbook'); + expect(uaData['platform']).toBe('MockOS'); + expect(uaData['platformVersion']).toBe('3.1'); + expect(request.headers['user-agent']).toBe('MockBrowser'); + }); }); describe('Page.setContent', function () { diff --git a/utils/doclint/check_public_api/index.js b/utils/doclint/check_public_api/index.js index cafd0cfd87772..9d96fa276077e 100644 --- a/utils/doclint/check_public_api/index.js +++ b/utils/doclint/check_public_api/index.js @@ -697,6 +697,13 @@ function compareDocumentations(actual, expected) { expectedName: 'NetworkConditions', }, ], + [ + 'Method Page.setUserAgent() userAgentMetadata', + { + actualName: 'Object', + expectedName: 'UserAgentMetadata', + }, + ], [ 'Method Page.setViewport() options.viewport', {