diff --git a/src/browserContext.ts b/src/browserContext.ts index ca56d75520..2c6768a159 100644 --- a/src/browserContext.ts +++ b/src/browserContext.ts @@ -44,6 +44,7 @@ export type BrowserContextOptions = { javaScriptEnabled?: boolean, bypassCSP?: boolean, userAgent?: string, + language?: string, timezoneId?: string, geolocation?: types.Geolocation, permissions?: { [key: string]: string[] }; diff --git a/src/chromium/crNetworkManager.ts b/src/chromium/crNetworkManager.ts index 608ca460e7..abc8b18137 100644 --- a/src/chromium/crNetworkManager.ts +++ b/src/chromium/crNetworkManager.ts @@ -79,10 +79,6 @@ export class CRNetworkManager { }); } - async setUserAgent(userAgent: string) { - await this._client.send('Network.setUserAgentOverride', { userAgent }); - } - async setCacheEnabled(enabled: boolean) { this._userCacheDisabled = !enabled; await this._updateProtocolCacheDisabled(); diff --git a/src/chromium/crPage.ts b/src/chromium/crPage.ts index 9a43187c85..a032329098 100644 --- a/src/chromium/crPage.ts +++ b/src/chromium/crPage.ts @@ -110,8 +110,8 @@ export class CRPage implements PageDelegate { promises.push(this._updateViewport(true /* updateTouch */)); if (options.javaScriptEnabled === false) promises.push(this._client.send('Emulation.setScriptExecutionDisabled', { value: true })); - if (options.userAgent) - this._networkManager.setUserAgent(options.userAgent); + if (options.userAgent || options.language) + promises.push(this._client.send('Emulation.setUserAgentOverride', { userAgent: options.userAgent || '', acceptLanguage: options.language })); if (options.timezoneId) promises.push(emulateTimezone(this._client, options.timezoneId)); if (options.geolocation) diff --git a/src/frames.ts b/src/frames.ts index b0abddf51b..adc5b17dc2 100644 --- a/src/frames.ts +++ b/src/frames.ts @@ -323,7 +323,8 @@ export class Frame { } async goto(url: string, options: GotoOptions = {}): Promise { - let referer = (this._page._state.extraHTTPHeaders || {})['referer']; + const headers = (this._page._state.extraHTTPHeaders || {}); + let referer = headers['referer'] || headers['Referer']; if (options.referer !== undefined) { if (referer !== undefined && referer !== options.referer) throw new Error('"referer" is already specified as extra HTTP header'); diff --git a/src/page.ts b/src/page.ts index f0f6bfbb24..9ca1ad129b 100644 --- a/src/page.ts +++ b/src/page.ts @@ -272,7 +272,7 @@ export class Page extends platform.EventEmitter { for (const key of Object.keys(headers)) { const value = headers[key]; assert(helper.isString(value), `Expected value of header "${key}" to be String, but "${typeof value}" is found.`); - this._state.extraHTTPHeaders[key.toLowerCase()] = value; + this._state.extraHTTPHeaders[key] = value; } return this._delegate.setExtraHTTPHeaders(headers); } diff --git a/src/webkit/wkBrowser.ts b/src/webkit/wkBrowser.ts index 26b66d55cb..2615debc5a 100644 --- a/src/webkit/wkBrowser.ts +++ b/src/webkit/wkBrowser.ts @@ -78,6 +78,8 @@ export class WKBrowser extends platform.EventEmitter implements Browser { const context = this._createBrowserContext(browserContextId, options); if (options.ignoreHTTPSErrors) await this._browserSession.send('Browser.setIgnoreCertificateErrors', { browserContextId, ignore: true }); + if (options.language) + await this._browserSession.send('Browser.setLanguages', { browserContextId, languages: [options.language] }); await context._initialize(); this._contexts.set(browserContextId, context); return context; diff --git a/src/webkit/wkPage.ts b/src/webkit/wkPage.ts index 2e517a4c00..e093f01e3c 100644 --- a/src/webkit/wkPage.ts +++ b/src/webkit/wkPage.ts @@ -142,8 +142,12 @@ export class WKPage implements PageDelegate { } if (contextOptions.bypassCSP) promises.push(session.send('Page.setBypassCSP', { enabled: true })); - if (this._page._state.extraHTTPHeaders !== null) - promises.push(session.send('Network.setExtraHTTPHeaders', { headers: this._page._state.extraHTTPHeaders })); + if (this._page._state.extraHTTPHeaders || contextOptions.language) { + const headers = this._page._state.extraHTTPHeaders || {}; + if (contextOptions.language) + headers['Accept-Language'] = contextOptions.language; + promises.push(session.send('Network.setExtraHTTPHeaders', { headers })); + } if (this._page._state.hasTouch) promises.push(session.send('Page.setTouchEmulationEnabled', { enabled: true })); if (contextOptions.timezoneId) { @@ -375,7 +379,11 @@ export class WKPage implements PageDelegate { } async setExtraHTTPHeaders(headers: network.Headers): Promise { - await this._updateState('Network.setExtraHTTPHeaders', { headers }); + const copy = { ...headers }; + const language = this._page.context()._options.language; + if (language) + copy['Accept-Language'] = language; + await this._updateState('Network.setExtraHTTPHeaders', { headers: copy }); } async setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise { diff --git a/test/browsercontext.spec.js b/test/browsercontext.spec.js index afc2bef868..5d24c3650f 100644 --- a/test/browsercontext.spec.js +++ b/test/browsercontext.spec.js @@ -107,7 +107,7 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE }); }); - describe('BrowserContext({setUserAgent})', function() { + describe('BrowserContext({userAgent})', function() { it('should work', async({newPage, server}) => { { const page = await newPage(); diff --git a/test/emulation.spec.js b/test/emulation.spec.js index c7d49c2ab7..fe49c59f10 100644 --- a/test/emulation.spec.js +++ b/test/emulation.spec.js @@ -223,6 +223,44 @@ module.exports.describe = function({testRunner, expect, playwright, headless, FF }); }); + describe.skip(CHROMIUM || FFOX)('BrowserContext({language})', function() { + it('should affect accept-language header', async({newPage, server}) => { + const page = await newPage({ language: 'fr-CH' }); + const [request] = await Promise.all([ + server.waitForRequest('/empty.html'), + page.goto(server.EMPTY_PAGE), + ]); + expect(request.headers['accept-language']).toBe('fr-CH'); + expect(await page.evaluate(() => navigator.language)).toBe('fr-CH'); + }); + it('should format number', async({newPage, server}) => { + { + const page = await newPage(); + await page.goto(server.EMPTY_PAGE); + expect(await page.evaluate(() => (1000000.50).toLocaleString())).toBe('1,000,000.5'); + } + { + const page = await newPage({ language: 'fr-CH' }); + await page.goto(server.EMPTY_PAGE); + expect(await page.evaluate(() => (1000000.50).toLocaleString())).toBe('1 000 000,5'); + } + }); + it('should format date', async({newPage, server}) => { + { + const page = await newPage(); + await page.goto(server.EMPTY_PAGE); + expect(await page.evaluate(() => new Date(1479579154987).toString())).toBe( + 'Sat Nov 19 2016 10:12:34 GMT-0800 (PST)'); + } + { + const page = await newPage({ language: 'de-de', timezoneId: 'Europe/Berlin' }); + await page.goto(server.EMPTY_PAGE); + expect(await page.evaluate(() => new Date(1479579154987).toString())).toBe( + 'Sat Nov 19 2016 19:12:34 GMT+0100 (Mitteleuropäische Normalzeit)'); + } + }); + }); + describe('focus', function() { it.skip(!headless)('should think that it is focused by default', async({page}) => { expect(await page.evaluate('document.hasFocus()')).toBe(true);