Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ Indicates that the browser is connected.
- `httpCredentials` <[Object]> Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication).
- `username` <[string]>
- `password` <[string]>
- `colorScheme` <"dark"|"light"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'.
- returns: <[Promise]<[BrowserContext]>>

Creates a new browser context. It won't share cookies/cache with other browser contexts.
Expand Down Expand Up @@ -255,6 +256,7 @@ Creates a new browser context. It won't share cookies/cache with other browser c
- `httpCredentials` <[Object]> Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication).
- `username` <[string]>
- `password` <[string]>
- `colorScheme` <"dark"|"light"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'.
- returns: <[Promise]<[Page]>>

Creates a new page in a new browser context. Closing this page will close the context as well.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"main": "index.js",
"playwright": {
"chromium_revision": "754895",
"firefox_revision": "1071",
"firefox_revision": "1072",
"webkit_revision": "1188"
},
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions src/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type BrowserContextOptions = {
deviceScaleFactor?: number,
isMobile?: boolean,
hasTouch?: boolean,
colorScheme?: types.ColorScheme,
acceptDownloads?: boolean
};

Expand Down
10 changes: 6 additions & 4 deletions src/chromium/crPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ export class CRPage implements PageDelegate {
await this._mainFrameSession._updateViewport();
}

async setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void> {
await this._forAllFrameSessions(frame => frame._setEmulateMedia(mediaType, colorScheme));
async updateEmulateMedia(): Promise<void> {
await this._forAllFrameSessions(frame => frame._updateEmulateMedia());
}

async updateRequestInterception(): Promise<void> {
Expand Down Expand Up @@ -422,6 +422,7 @@ class FrameSession {
promises.push(this._updateRequestInterception());
promises.push(this._updateOffline());
promises.push(this._updateHttpCredentials());
promises.push(this._updateEmulateMedia());
for (const binding of this._crPage._browserContext._pageBindings.values())
promises.push(this._initBinding(binding));
for (const source of this._crPage._browserContext._evaluateOnNewDocumentSources)
Expand Down Expand Up @@ -687,9 +688,10 @@ class FrameSession {
await Promise.all(promises);
}

async _setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void> {
async _updateEmulateMedia(): Promise<void> {
const colorScheme = this._page._state.colorScheme || this._crPage._browserContext._options.colorScheme || 'light';
const features = colorScheme ? [{ name: 'prefers-color-scheme', value: colorScheme }] : [];
await this._client.send('Emulation.setEmulatedMedia', { media: mediaType || '', features });
await this._client.send('Emulation.setEmulatedMedia', { media: this._page._state.mediaType || '', features });
}

async _updateRequestInterception(): Promise<void> {
Expand Down
6 changes: 6 additions & 0 deletions src/firefox/ffBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ export class FFBrowserContext extends BrowserContextBase {
await this.setGeolocation(this._options.geolocation);
if (this._options.offline)
await this.setOffline(this._options.offline);
if (this._options.colorScheme)
await this._setColorScheme(this._options.colorScheme);
}

_ffPages(): FFPage[] {
Expand Down Expand Up @@ -259,6 +261,10 @@ export class FFBrowserContext extends BrowserContextBase {
await this._browser._connection.send('Browser.setOnlineOverride', { browserContextId: this._browserContextId || undefined, override: offline ? 'offline' : 'online' });
}

async _setColorScheme(colorScheme?: types.ColorScheme): Promise<void> {
await this._browser._connection.send('Browser.setColorScheme', { browserContextId: this._browserContextId || undefined, colorScheme });
}

async setHTTPCredentials(httpCredentials: types.Credentials | null): Promise<void> {
this._options.httpCredentials = httpCredentials || undefined;
await this._browser._connection.send('Browser.setHTTPCredentials', { browserContextId: this._browserContextId || undefined, credentials: httpCredentials });
Expand Down
7 changes: 4 additions & 3 deletions src/firefox/ffPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,11 @@ export class FFPage implements PageDelegate {
});
}

async setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void> {
async updateEmulateMedia(): Promise<void> {
const colorScheme = this._page._state.colorScheme || this._browserContext._options.colorScheme || 'light';
await this._session.send('Page.setEmulatedMedia', {
type: mediaType === null ? undefined : mediaType,
colorScheme: colorScheme === null ? undefined : colorScheme
type: this._page._state.mediaType === null ? undefined : this._page._state.mediaType,
colorScheme
});
}

Expand Down
4 changes: 2 additions & 2 deletions src/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export interface PageDelegate {

updateExtraHTTPHeaders(): Promise<void>;
setViewportSize(viewportSize: types.Size): Promise<void>;
setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void>;
updateEmulateMedia(): Promise<void>;
updateRequestInterception(): Promise<void>;
setFileChooserIntercepted(enabled: boolean): Promise<void>;

Expand Down Expand Up @@ -357,7 +357,7 @@ export class Page extends ExtendedEventEmitter {
this._state.mediaType = options.media;
if (options.colorScheme !== undefined)
this._state.colorScheme = options.colorScheme;
await this._delegate.setEmulateMedia(this._state.mediaType, this._state.colorScheme);
await this._delegate.updateEmulateMedia();
}

async setViewportSize(viewportSize: types.Size) {
Expand Down
7 changes: 4 additions & 3 deletions src/webkit/wkPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export class WKPage implements PageDelegate {
height: this._page._state.viewportSize.height,
}));
}

promises.push(this.updateEmulateMedia());
promises.push(session.send('Network.setExtraHTTPHeaders', { headers: this._calculateExtraHTTPHeaders() }));
if (contextOptions.offline)
promises.push(session.send('Network.setEmulateOfflineState', { offline: true }));
Expand Down Expand Up @@ -492,8 +492,9 @@ export class WKPage implements PageDelegate {
return headers;
}

async setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void> {
await this._forAllSessions(session => WKPage._setEmulateMedia(session, mediaType, colorScheme));
async updateEmulateMedia(): Promise<void> {
const colorScheme = this._page._state.colorScheme || this._browserContext._options.colorScheme || 'light';
await this._forAllSessions(session => WKPage._setEmulateMedia(session, this._page._state.mediaType, colorScheme));
}

async setViewportSize(viewportSize: types.Size): Promise<void> {
Expand Down
50 changes: 50 additions & 0 deletions test/emulation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* limitations under the License.
*/

const utils = require('./utils');

/**
* @type {PageTestSuite}
*/
Expand Down Expand Up @@ -236,6 +238,21 @@ module.exports.describe = function({testRunner, expect, playwright, headless, FF
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(true);
}
});
it('should default to light', async({page, server}) => {
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);

await page.emulateMedia({ colorScheme: 'dark' });
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(false);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);

await page.emulateMedia({ colorScheme: null });
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);
});
it('should throw in case of bad argument', async({page, server}) => {
let error = null;
await page.emulateMedia({ colorScheme: 'bad' }).catch(e => error = e);
Expand All @@ -253,6 +270,39 @@ module.exports.describe = function({testRunner, expect, playwright, headless, FF
await navigated;
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
});
it('should work in popup', async({browser, server}) => {
{
const context = await browser.newContext({ colorScheme: 'dark' });
const page = await context.newPage();
await page.goto(server.EMPTY_PAGE);
const [popup] = await Promise.all([
page.waitForEvent('popup'),
page.evaluate(url => { window.open(url); }, server.EMPTY_PAGE),
]);
expect(await popup.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(false);
expect(await popup.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
await context.close();
}
{
const page = await browser.newPage({ colorScheme: 'light' });
await page.goto(server.EMPTY_PAGE);
const [popup] = await Promise.all([
page.waitForEvent('popup'),
page.evaluate(url => { window.open(url); }, server.EMPTY_PAGE),
]);
expect(await popup.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(true);
expect(await popup.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
await page.close();
}
});
it('should work in cross-process iframe', async({browser, server}) => {
const page = await browser.newPage({ colorScheme: 'dark' });
await page.goto(server.EMPTY_PAGE);
await utils.attachFrame(page, 'frame1', server.CROSS_PROCESS_PREFIX + '/empty.html');
const frame = page.frames()[1];
expect(await frame.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
await page.close();
});
});

describe('BrowserContext({timezoneId})', function() {
Expand Down