diff --git a/docs/src/api/params.md b/docs/src/api/params.md index 7066b53dd6..c555008e47 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -523,22 +523,42 @@ Whether to emulate network being offline. Defaults to `false`. Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication). ## context-option-colorscheme -- `colorScheme` <[ColorScheme]<"light"|"dark"|"no-preference">> +* langs: js, python, java +- `colorScheme` > Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See -[`method: Page.emulateMedia`] for more details. Defaults to `'light'`. +[`method: Page.emulateMedia`] for more details. Passing `null` resets emulation to system defaults. Defaults to `'light'`. + +## context-option-colorscheme-csharp +* langs: csharp +- `colorScheme` <[ColorScheme]<"light"|"dark"|"no-preference"|"null">> + +Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See +[`method: Page.emulateMedia`] for more details. Passing `'null'` resets emulation to system defaults. Defaults to `'light'`. ## context-option-reducedMotion -- `reducedMotion` <[ReducedMotion]<"reduce"|"no-preference">> +* langs: js, python, java +- `reducedMotion` > -Emulates `'prefers-reduced-motion'` media feature, supported values are `'reduce'`, `'no-preference'`. See [`method: Page.emulateMedia`] for more details. Defaults -to `'no-preference'`. +Emulates `'prefers-reduced-motion'` media feature, supported values are `'reduce'`, `'no-preference'`. See [`method: Page.emulateMedia`] for more details. Passing `null` resets emulation to system defaults. Defaults to `'no-preference'`. + +## context-option-reducedMotion-csharp +* langs: csharp +- `reducedMotion` <[ReducedMotion]<"reduce"|"no-preference"|"null">> + +Emulates `'prefers-reduced-motion'` media feature, supported values are `'reduce'`, `'no-preference'`. See [`method: Page.emulateMedia`] for more details. Passing `'null'` resets emulation to system defaults. Defaults to `'no-preference'`. ## context-option-forcedColors -- `forcedColors` <[ForcedColors]<"active"|"none">> +* langs: js, python, java +- `forcedColors` > -Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See [`method: Page.emulateMedia`] for more details. Defaults -to `'none'`. +Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See [`method: Page.emulateMedia`] for more details. Passing `null` resets emulation to system defaults. Defaults to `'none'`. + +## context-option-forcedColors-csharp +* langs: csharp +- `forcedColors` <[ForcedColors]<"active"|"none"|"null">> + +Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See [`method: Page.emulateMedia`] for more details. Passing `'null'` resets emulation to system defaults. Defaults to `'none'`. ## context-option-logger * langs: js @@ -817,8 +837,11 @@ An acceptable perceived color difference in the [YIQ color space](https://en.wik - %%-context-option-offline-%% - %%-context-option-httpcredentials-%% - %%-context-option-colorscheme-%% +- %%-context-option-colorscheme-csharp-%% - %%-context-option-reducedMotion-%% +- %%-context-option-reducedMotion-csharp-%% - %%-context-option-forcedColors-%% +- %%-context-option-forcedColors-csharp-%% - %%-context-option-logger-%% - %%-context-option-videospath-%% - %%-context-option-videosize-%% diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index 8e0693aa2a..2f2ffbb35d 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -416,6 +416,9 @@ export async function prepareBrowserContextParams(options: BrowserContextOptions storageState: await prepareStorageState(options), serviceWorkers: options.serviceWorkers, recordHar: prepareRecordHarOptions(options.recordHar), + colorScheme: options.colorScheme === null ? 'no-override' : options.colorScheme, + reducedMotion: options.reducedMotion === null ? 'no-override' : options.reducedMotion, + forcedColors: options.forcedColors === null ? 'no-override' : options.forcedColors, }; if (!contextParams.recordVideo && options.videosPath) { contextParams.recordVideo = { diff --git a/packages/playwright-core/src/client/electron.ts b/packages/playwright-core/src/client/electron.ts index 106558f727..8f41404a8f 100644 --- a/packages/playwright-core/src/client/electron.ts +++ b/packages/playwright-core/src/client/electron.ts @@ -29,10 +29,11 @@ import type { Page } from './page'; import type { Env, WaitForEventOptions, Headers, BrowserContextOptions } from './types'; import { Waiter } from './waiter'; -type ElectronOptions = Omit & { +type ElectronOptions = Omit & { env?: Env, extraHTTPHeaders?: Headers, recordHar?: BrowserContextOptions['recordHar'], + colorScheme?: 'dark' | 'light' | 'no-preference' | null, }; type ElectronAppType = typeof import('electron'); diff --git a/packages/playwright-core/src/client/page.ts b/packages/playwright-core/src/client/page.ts index f42e8a92f0..1092be9b90 100644 --- a/packages/playwright-core/src/client/page.ts +++ b/packages/playwright-core/src/client/page.ts @@ -424,10 +424,10 @@ export class Page extends ChannelOwner implements api.Page async emulateMedia(options: { media?: 'screen' | 'print' | null, colorScheme?: 'dark' | 'light' | 'no-preference' | null, reducedMotion?: 'reduce' | 'no-preference' | null, forcedColors?: 'active' | 'none' | null } = {}) { await this._channel.emulateMedia({ - media: options.media === null ? 'null' : options.media, - colorScheme: options.colorScheme === null ? 'null' : options.colorScheme, - reducedMotion: options.reducedMotion === null ? 'null' : options.reducedMotion, - forcedColors: options.forcedColors === null ? 'null' : options.forcedColors, + media: options.media === null ? 'no-override' : options.media, + colorScheme: options.colorScheme === null ? 'no-override' : options.colorScheme, + reducedMotion: options.reducedMotion === null ? 'no-override' : options.reducedMotion, + forcedColors: options.forcedColors === null ? 'no-override' : options.forcedColors, }); } diff --git a/packages/playwright-core/src/client/types.ts b/packages/playwright-core/src/client/types.ts index 517c52c683..3852d00c7f 100644 --- a/packages/playwright-core/src/client/types.ts +++ b/packages/playwright-core/src/client/types.ts @@ -47,32 +47,36 @@ export type SetStorageState = { export type LifecycleEvent = channels.LifecycleEvent; export const kLifecycleEvents: Set = new Set(['load', 'domcontentloaded', 'networkidle', 'commit']); -export type BrowserContextOptions = Omit & { - viewport?: Size | null, - extraHTTPHeaders?: Headers, - logger?: Logger, - videosPath?: string, - videoSize?: Size, - storageState?: string | SetStorageState, +export type BrowserContextOptions = Omit & { + viewport?: Size | null; + extraHTTPHeaders?: Headers; + logger?: Logger; + videosPath?: string; + videoSize?: Size; + storageState?: string | SetStorageState; har?: { path: string; fallback?: 'abort'|'continue'; urlFilter?: string|RegExp; - }, + }; recordHar?: { path: string, omitContent?: boolean, content?: 'omit' | 'embed' | 'attach', mode?: 'full' | 'minimal', urlFilter?: string | RegExp, - }, + }; + colorScheme?: 'dark' | 'light' | 'no-preference' | null; + reducedMotion?: 'reduce' | 'no-preference' | null; + forcedColors?: 'active' | 'none' | null; }; type LaunchOverrides = { - ignoreDefaultArgs?: boolean | string[], - env?: Env, - logger?: Logger, + ignoreDefaultArgs?: boolean | string[]; + env?: Env; + logger?: Logger; }; + type FirefoxUserPrefs = { firefoxUserPrefs?: { [key: string]: string | number | boolean }, }; diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index 25c3432a34..4b4333c334 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -506,9 +506,9 @@ scheme.BrowserTypeLaunchPersistentContextParams = tObject({ deviceScaleFactor: tOptional(tNumber), isMobile: tOptional(tBoolean), hasTouch: tOptional(tBoolean), - colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), - reducedMotion: tOptional(tEnum(['reduce', 'no-preference'])), - forcedColors: tOptional(tEnum(['active', 'none'])), + colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference', 'no-override'])), + reducedMotion: tOptional(tEnum(['reduce', 'no-preference', 'no-override'])), + forcedColors: tOptional(tEnum(['active', 'none', 'no-override'])), acceptDownloads: tOptional(tBoolean), baseURL: tOptional(tString), recordVideo: tOptional(tObject({ @@ -577,9 +577,9 @@ scheme.BrowserNewContextParams = tObject({ deviceScaleFactor: tOptional(tNumber), isMobile: tOptional(tBoolean), hasTouch: tOptional(tBoolean), - colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), - reducedMotion: tOptional(tEnum(['reduce', 'no-preference'])), - forcedColors: tOptional(tEnum(['active', 'none'])), + colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference', 'no-override'])), + reducedMotion: tOptional(tEnum(['reduce', 'no-preference', 'no-override'])), + forcedColors: tOptional(tEnum(['active', 'none', 'no-override'])), acceptDownloads: tOptional(tBoolean), baseURL: tOptional(tString), recordVideo: tOptional(tObject({ @@ -637,9 +637,9 @@ scheme.BrowserNewContextForReuseParams = tObject({ deviceScaleFactor: tOptional(tNumber), isMobile: tOptional(tBoolean), hasTouch: tOptional(tBoolean), - colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), - reducedMotion: tOptional(tEnum(['reduce', 'no-preference'])), - forcedColors: tOptional(tEnum(['active', 'none'])), + colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference', 'no-override'])), + reducedMotion: tOptional(tEnum(['reduce', 'no-preference', 'no-override'])), + forcedColors: tOptional(tEnum(['active', 'none', 'no-override'])), acceptDownloads: tOptional(tBoolean), baseURL: tOptional(tString), recordVideo: tOptional(tObject({ @@ -932,10 +932,10 @@ scheme.PageCloseParams = tObject({ }); scheme.PageCloseResult = tOptional(tObject({})); scheme.PageEmulateMediaParams = tObject({ - media: tOptional(tEnum(['screen', 'print', 'null'])), - colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference', 'null'])), - reducedMotion: tOptional(tEnum(['reduce', 'no-preference', 'null'])), - forcedColors: tOptional(tEnum(['active', 'none', 'null'])), + media: tOptional(tEnum(['screen', 'print', 'no-override'])), + colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference', 'no-override'])), + reducedMotion: tOptional(tEnum(['reduce', 'no-preference', 'no-override'])), + forcedColors: tOptional(tEnum(['active', 'none', 'no-override'])), }); scheme.PageEmulateMediaResult = tOptional(tObject({})); scheme.PageExposeBindingParams = tObject({ @@ -2125,7 +2125,7 @@ scheme.ElectronLaunchParams = tObject({ timeout: tOptional(tNumber), acceptDownloads: tOptional(tBoolean), bypassCSP: tOptional(tBoolean), - colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), + colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference', 'no-override'])), extraHTTPHeaders: tOptional(tArray(tType('NameValue'))), geolocation: tOptional(tObject({ longitude: tNumber, @@ -2347,9 +2347,9 @@ scheme.AndroidDeviceLaunchBrowserParams = tObject({ deviceScaleFactor: tOptional(tNumber), isMobile: tOptional(tBoolean), hasTouch: tOptional(tBoolean), - colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), - reducedMotion: tOptional(tEnum(['reduce', 'no-preference'])), - forcedColors: tOptional(tEnum(['active', 'none'])), + colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference', 'no-override'])), + reducedMotion: tOptional(tEnum(['reduce', 'no-preference', 'no-override'])), + forcedColors: tOptional(tEnum(['active', 'none', 'no-override'])), acceptDownloads: tOptional(tBoolean), baseURL: tOptional(tString), recordVideo: tOptional(tObject({ diff --git a/packages/playwright-core/src/server/chromium/crPage.ts b/packages/playwright-core/src/server/chromium/crPage.ts index 60890a2200..e66868b2cd 100644 --- a/packages/playwright-core/src/server/chromium/crPage.ts +++ b/packages/playwright-core/src/server/chromium/crPage.ts @@ -1064,16 +1064,17 @@ class FrameSession { async _updateEmulateMedia(): Promise { const emulatedMedia = this._page.emulatedMedia(); - const colorScheme = emulatedMedia.colorScheme === null ? '' : emulatedMedia.colorScheme; - const reducedMotion = emulatedMedia.reducedMotion === null ? '' : emulatedMedia.reducedMotion; - const forcedColors = emulatedMedia.forcedColors === null ? '' : emulatedMedia.forcedColors; + // Empty string disables the override. + const media = emulatedMedia.media === 'no-override' ? '' : emulatedMedia.media; + const colorScheme = emulatedMedia.colorScheme === 'no-override' ? '' : emulatedMedia.colorScheme; + const reducedMotion = emulatedMedia.reducedMotion === 'no-override' ? '' : emulatedMedia.reducedMotion; + const forcedColors = emulatedMedia.forcedColors === 'no-override' ? '' : emulatedMedia.forcedColors; const features = [ { name: 'prefers-color-scheme', value: colorScheme }, { name: 'prefers-reduced-motion', value: reducedMotion }, { name: 'forced-colors', value: forcedColors }, ]; - // Empty string disables the override. - await this._client.send('Emulation.setEmulatedMedia', { media: emulatedMedia.media || '', features }); + await this._client.send('Emulation.setEmulatedMedia', { media, features }); } async _updateUserAgent(): Promise { diff --git a/packages/playwright-core/src/server/dispatchers/pageDispatcher.ts b/packages/playwright-core/src/server/dispatchers/pageDispatcher.ts index 20a390c351..651920e38d 100644 --- a/packages/playwright-core/src/server/dispatchers/pageDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/pageDispatcher.ts @@ -138,10 +138,10 @@ export class PageDispatcher extends Dispatcher { await this._page.emulateMedia({ - media: params.media === 'null' ? null : params.media, - colorScheme: params.colorScheme === 'null' ? null : params.colorScheme, - reducedMotion: params.reducedMotion === 'null' ? null : params.reducedMotion, - forcedColors: params.forcedColors === 'null' ? null : params.forcedColors, + media: params.media, + colorScheme: params.colorScheme, + reducedMotion: params.reducedMotion, + forcedColors: params.forcedColors, }); } diff --git a/packages/playwright-core/src/server/firefox/ffBrowser.ts b/packages/playwright-core/src/server/firefox/ffBrowser.ts index 3d454ca935..5a65732d8d 100644 --- a/packages/playwright-core/src/server/firefox/ffBrowser.ts +++ b/packages/playwright-core/src/server/firefox/ffBrowser.ts @@ -204,18 +204,24 @@ export class FFBrowserContext extends BrowserContext { promises.push(this.setGeolocation(this._options.geolocation)); if (this._options.offline) promises.push(this.setOffline(this._options.offline)); - promises.push(this._browser._connection.send('Browser.setColorScheme', { - browserContextId, - colorScheme: this._options.colorScheme !== undefined ? this._options.colorScheme : 'light', - })); - promises.push(this._browser._connection.send('Browser.setReducedMotion', { - browserContextId, - reducedMotion: this._options.reducedMotion !== undefined ? this._options.reducedMotion : 'no-preference', - })); - promises.push(this._browser._connection.send('Browser.setForcedColors', { - browserContextId, - forcedColors: this._options.forcedColors !== undefined ? this._options.forcedColors : 'none', - })); + if (this._options.colorScheme !== 'no-override') { + promises.push(this._browser._connection.send('Browser.setColorScheme', { + browserContextId, + colorScheme: this._options.colorScheme !== undefined ? this._options.colorScheme : 'light', + })); + } + if (this._options.reducedMotion !== 'no-override') { + promises.push(this._browser._connection.send('Browser.setReducedMotion', { + browserContextId, + reducedMotion: this._options.reducedMotion !== undefined ? this._options.reducedMotion : 'no-preference', + })); + } + if (this._options.forcedColors !== 'no-override') { + promises.push(this._browser._connection.send('Browser.setForcedColors', { + browserContextId, + forcedColors: this._options.forcedColors !== undefined ? this._options.forcedColors : 'none', + })); + } if (this._options.recordVideo) { promises.push(this._ensureVideosPath().then(() => { return this._browser._connection.send('Browser.setVideoRecordingOptions', { diff --git a/packages/playwright-core/src/server/firefox/ffPage.ts b/packages/playwright-core/src/server/firefox/ffPage.ts index b3d67e2bcc..ae03182af8 100644 --- a/packages/playwright-core/src/server/firefox/ffPage.ts +++ b/packages/playwright-core/src/server/firefox/ffPage.ts @@ -371,12 +371,12 @@ export class FFPage implements PageDelegate { async updateEmulateMedia(): Promise { const emulatedMedia = this._page.emulatedMedia(); - const colorScheme = emulatedMedia.colorScheme ?? undefined; - const reducedMotion = emulatedMedia.reducedMotion ?? undefined; - const forcedColors = emulatedMedia.forcedColors ?? undefined; + const colorScheme = emulatedMedia.colorScheme === 'no-override' ? undefined : emulatedMedia.colorScheme; + const reducedMotion = emulatedMedia.reducedMotion === 'no-override' ? undefined : emulatedMedia.reducedMotion; + const forcedColors = emulatedMedia.forcedColors === 'no-override' ? undefined : emulatedMedia.forcedColors; await this._session.send('Page.setEmulatedMedia', { // Empty string means reset. - type: emulatedMedia.media === null ? '' : emulatedMedia.media, + type: emulatedMedia.media === 'no-override' ? '' : emulatedMedia.media, colorScheme, reducedMotion, forcedColors, diff --git a/packages/playwright-core/src/server/page.ts b/packages/playwright-core/src/server/page.ts index b8c7ebbe3e..e66162c7a2 100644 --- a/packages/playwright-core/src/server/page.ts +++ b/packages/playwright-core/src/server/page.ts @@ -101,10 +101,10 @@ export interface PageDelegate { type EmulatedSize = { screen: types.Size, viewport: types.Size }; type EmulatedMedia = { - media: types.MediaType | null; - colorScheme: types.ColorScheme | null; - reducedMotion: types.ReducedMotion | null; - forcedColors: types.ForcedColors | null; + media: types.MediaType; + colorScheme: types.ColorScheme; + reducedMotion: types.ReducedMotion; + forcedColors: types.ForcedColors; }; type ExpectScreenshotOptions = { @@ -442,7 +442,7 @@ export class Page extends SdkObject { emulatedMedia(): EmulatedMedia { const contextOptions = this._browserContext._options; return { - media: this._emulatedMedia.media || null, + media: this._emulatedMedia.media || 'no-override', colorScheme: this._emulatedMedia.colorScheme !== undefined ? this._emulatedMedia.colorScheme : contextOptions.colorScheme ?? 'light', reducedMotion: this._emulatedMedia.reducedMotion !== undefined ? this._emulatedMedia.reducedMotion : contextOptions.reducedMotion ?? 'no-preference', forcedColors: this._emulatedMedia.forcedColors !== undefined ? this._emulatedMedia.forcedColors : contextOptions.forcedColors ?? 'none', diff --git a/packages/playwright-core/src/server/recorder/recorderApp.ts b/packages/playwright-core/src/server/recorder/recorderApp.ts index 9add17d1c2..5d6f29398d 100644 --- a/packages/playwright-core/src/server/recorder/recorderApp.ts +++ b/packages/playwright-core/src/server/recorder/recorderApp.ts @@ -125,6 +125,7 @@ export class RecorderApp extends EventEmitter implements IRecorderApp { channel: findChromiumChannel(sdkLanguage), args, noDefaultViewport: true, + colorScheme: 'no-override', ignoreDefaultArgs: ['--enable-automation'], headless: !!process.env.PWTEST_CLI_HEADLESS || (isUnderTest() && !headed), useWebSocket: !!process.env.PWTEST_RECORDER_PORT, diff --git a/packages/playwright-core/src/server/trace/viewer/traceViewer.ts b/packages/playwright-core/src/server/trace/viewer/traceViewer.ts index a6ba863633..ff924da5a1 100644 --- a/packages/playwright-core/src/server/trace/viewer/traceViewer.ts +++ b/packages/playwright-core/src/server/trace/viewer/traceViewer.ts @@ -68,6 +68,7 @@ export async function showTraceViewer(traceUrls: string[], browserName: string, noDefaultViewport: true, ignoreDefaultArgs: ['--enable-automation'], headless, + colorScheme: 'no-override', useWebSocket: isUnderTest() }); diff --git a/packages/playwright-core/src/server/types.ts b/packages/playwright-core/src/server/types.ts index 661244a9c9..319b774839 100644 --- a/packages/playwright-core/src/server/types.ts +++ b/packages/playwright-core/src/server/types.ts @@ -77,13 +77,13 @@ export type FilePayload = { buffer: string, }; -export type MediaType = 'screen' | 'print'; +export type MediaType = 'screen' | 'print' | 'no-override'; -export type ColorScheme = 'dark' | 'light' | 'no-preference'; +export type ColorScheme = 'dark' | 'light' | 'no-preference' | 'no-override'; -export type ReducedMotion = 'no-preference' | 'reduce'; +export type ReducedMotion = 'no-preference' | 'reduce' | 'no-override'; -export type ForcedColors = 'active' | 'none'; +export type ForcedColors = 'active' | 'none' | 'no-override'; export type DeviceDescriptor = { userAgent: string, diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index f3939b2993..e367a5dc69 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -627,25 +627,28 @@ export class WKPage implements PageDelegate { await this._page._onFileChooserOpened(handle); } - private static async _setEmulateMedia(session: WKSession, mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null, reducedMotion: types.ReducedMotion | null, forcedColors: types.ForcedColors | null): Promise { + private static async _setEmulateMedia(session: WKSession, mediaType: types.MediaType, colorScheme: types.ColorScheme, reducedMotion: types.ReducedMotion, forcedColors: types.ForcedColors): Promise { const promises = []; - promises.push(session.send('Page.setEmulatedMedia', { media: mediaType || '' })); + promises.push(session.send('Page.setEmulatedMedia', { media: mediaType === 'no-override' ? '' : mediaType })); let appearance: any = undefined; switch (colorScheme) { case 'light': appearance = 'Light'; break; case 'dark': appearance = 'Dark'; break; + case 'no-override': appearance = undefined; break; } promises.push(session.send('Page.setForcedAppearance', { appearance })); let reducedMotionWk: any = undefined; switch (reducedMotion) { case 'reduce': reducedMotionWk = 'Reduce'; break; case 'no-preference': reducedMotionWk = 'NoPreference'; break; + case 'no-override': reducedMotionWk = undefined; break; } promises.push(session.send('Page.setForcedReducedMotion', { reducedMotion: reducedMotionWk })); let forcedColorsWk: any = undefined; switch (forcedColors) { case 'active': forcedColorsWk = 'Active'; break; case 'none': forcedColorsWk = 'None'; break; + case 'no-override': forcedColorsWk = undefined; break; } promises.push(session.send('Page.setForcedColors', { forcedColors: forcedColorsWk })); await Promise.all(promises); diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 17f32c8b7a..c850dcc02d 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -11337,10 +11337,10 @@ export interface BrowserType { /** * Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'light'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'light'`. */ - colorScheme?: "light"|"dark"|"no-preference"; + colorScheme?: null|"light"|"dark"|"no-preference"; /** * Specify device scale factor (can be thought of as dpr). Defaults to `1`. @@ -11379,10 +11379,10 @@ export interface BrowserType { /** * Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'none'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'none'`. */ - forcedColors?: "active"|"none"; + forcedColors?: null|"active"|"none"; geolocation?: { /** @@ -11581,10 +11581,10 @@ export interface BrowserType { /** * Emulates `'prefers-reduced-motion'` media feature, supported values are `'reduce'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'no-preference'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'no-preference'`. */ - reducedMotion?: "reduce"|"no-preference"; + reducedMotion?: null|"reduce"|"no-preference"; /** * Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the `viewport` @@ -12765,10 +12765,10 @@ export interface AndroidDevice { /** * Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'light'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'light'`. */ - colorScheme?: "light"|"dark"|"no-preference"; + colorScheme?: null|"light"|"dark"|"no-preference"; /** * Optional package name to launch instead of default Chrome for Android. @@ -12787,10 +12787,10 @@ export interface AndroidDevice { /** * Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'none'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'none'`. */ - forcedColors?: "active"|"none"; + forcedColors?: null|"active"|"none"; geolocation?: { /** @@ -12934,10 +12934,10 @@ export interface AndroidDevice { /** * Emulates `'prefers-reduced-motion'` media feature, supported values are `'reduce'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'no-preference'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'no-preference'`. */ - reducedMotion?: "reduce"|"no-preference"; + reducedMotion?: null|"reduce"|"no-preference"; /** * Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the `viewport` @@ -14552,10 +14552,10 @@ export interface Browser extends EventEmitter { /** * Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'light'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'light'`. */ - colorScheme?: "light"|"dark"|"no-preference"; + colorScheme?: null|"light"|"dark"|"no-preference"; /** * Specify device scale factor (can be thought of as dpr). Defaults to `1`. @@ -14569,10 +14569,10 @@ export interface Browser extends EventEmitter { /** * Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'none'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'none'`. */ - forcedColors?: "active"|"none"; + forcedColors?: null|"active"|"none"; geolocation?: { /** @@ -14746,10 +14746,10 @@ export interface Browser extends EventEmitter { /** * Emulates `'prefers-reduced-motion'` media feature, supported values are `'reduce'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'no-preference'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'no-preference'`. */ - reducedMotion?: "reduce"|"no-preference"; + reducedMotion?: null|"reduce"|"no-preference"; /** * Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the `viewport` @@ -15400,10 +15400,10 @@ export interface Electron { /** * Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'light'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'light'`. */ - colorScheme?: "light"|"dark"|"no-preference"; + colorScheme?: null|"light"|"dark"|"no-preference"; /** * Current working directory to launch application from. @@ -17421,10 +17421,10 @@ export interface BrowserContextOptions { /** * Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'light'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'light'`. */ - colorScheme?: "light"|"dark"|"no-preference"; + colorScheme?: null|"light"|"dark"|"no-preference"; /** * Specify device scale factor (can be thought of as dpr). Defaults to `1`. @@ -17438,10 +17438,10 @@ export interface BrowserContextOptions { /** * Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'none'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'none'`. */ - forcedColors?: "active"|"none"; + forcedColors?: null|"active"|"none"; geolocation?: Geolocation; @@ -17596,10 +17596,10 @@ export interface BrowserContextOptions { /** * Emulates `'prefers-reduced-motion'` media feature, supported values are `'reduce'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'no-preference'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'no-preference'`. */ - reducedMotion?: "reduce"|"no-preference"; + reducedMotion?: null|"reduce"|"no-preference"; /** * Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the `viewport` diff --git a/packages/playwright-test/types/test.d.ts b/packages/playwright-test/types/test.d.ts index 5d651ac92b..dd9e24f8dd 100644 --- a/packages/playwright-test/types/test.d.ts +++ b/packages/playwright-test/types/test.d.ts @@ -2857,8 +2857,8 @@ export interface PlaywrightTestOptions { bypassCSP: boolean | undefined; /** * Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See - * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Defaults - * to `'light'`. + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. Passing + * `null` resets emulation to system defaults. Defaults to `'light'`. */ colorScheme: ColorScheme | undefined; /** diff --git a/packages/protocol/src/channels.ts b/packages/protocol/src/channels.ts index a7d6c5881c..77f76577f6 100644 --- a/packages/protocol/src/channels.ts +++ b/packages/protocol/src/channels.ts @@ -892,9 +892,9 @@ export type BrowserTypeLaunchPersistentContextParams = { deviceScaleFactor?: number, isMobile?: boolean, hasTouch?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', - reducedMotion?: 'reduce' | 'no-preference', - forcedColors?: 'active' | 'none', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: boolean, baseURL?: string, recordVideo?: { @@ -962,9 +962,9 @@ export type BrowserTypeLaunchPersistentContextOptions = { deviceScaleFactor?: number, isMobile?: boolean, hasTouch?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', - reducedMotion?: 'reduce' | 'no-preference', - forcedColors?: 'active' | 'none', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: boolean, baseURL?: string, recordVideo?: { @@ -1057,9 +1057,9 @@ export type BrowserNewContextParams = { deviceScaleFactor?: number, isMobile?: boolean, hasTouch?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', - reducedMotion?: 'reduce' | 'no-preference', - forcedColors?: 'active' | 'none', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: boolean, baseURL?: string, recordVideo?: { @@ -1114,9 +1114,9 @@ export type BrowserNewContextOptions = { deviceScaleFactor?: number, isMobile?: boolean, hasTouch?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', - reducedMotion?: 'reduce' | 'no-preference', - forcedColors?: 'active' | 'none', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: boolean, baseURL?: string, recordVideo?: { @@ -1174,9 +1174,9 @@ export type BrowserNewContextForReuseParams = { deviceScaleFactor?: number, isMobile?: boolean, hasTouch?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', - reducedMotion?: 'reduce' | 'no-preference', - forcedColors?: 'active' | 'none', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: boolean, baseURL?: string, recordVideo?: { @@ -1231,9 +1231,9 @@ export type BrowserNewContextForReuseOptions = { deviceScaleFactor?: number, isMobile?: boolean, hasTouch?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', - reducedMotion?: 'reduce' | 'no-preference', - forcedColors?: 'active' | 'none', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: boolean, baseURL?: string, recordVideo?: { @@ -1740,16 +1740,16 @@ export type PageCloseOptions = { }; export type PageCloseResult = void; export type PageEmulateMediaParams = { - media?: 'screen' | 'print' | 'null', - colorScheme?: 'dark' | 'light' | 'no-preference' | 'null', - reducedMotion?: 'reduce' | 'no-preference' | 'null', - forcedColors?: 'active' | 'none' | 'null', + media?: 'screen' | 'print' | 'no-override', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', }; export type PageEmulateMediaOptions = { - media?: 'screen' | 'print' | 'null', - colorScheme?: 'dark' | 'light' | 'no-preference' | 'null', - reducedMotion?: 'reduce' | 'no-preference' | 'null', - forcedColors?: 'active' | 'none' | 'null', + media?: 'screen' | 'print' | 'no-override', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', }; export type PageEmulateMediaResult = void; export type PageExposeBindingParams = { @@ -3856,7 +3856,7 @@ export type ElectronLaunchParams = { timeout?: number, acceptDownloads?: boolean, bypassCSP?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', extraHTTPHeaders?: NameValue[], geolocation?: { longitude: number, @@ -3889,7 +3889,7 @@ export type ElectronLaunchOptions = { timeout?: number, acceptDownloads?: boolean, bypassCSP?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', extraHTTPHeaders?: NameValue[], geolocation?: { longitude: number, @@ -4272,9 +4272,9 @@ export type AndroidDeviceLaunchBrowserParams = { deviceScaleFactor?: number, isMobile?: boolean, hasTouch?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', - reducedMotion?: 'reduce' | 'no-preference', - forcedColors?: 'active' | 'none', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: boolean, baseURL?: string, recordVideo?: { @@ -4326,9 +4326,9 @@ export type AndroidDeviceLaunchBrowserOptions = { deviceScaleFactor?: number, isMobile?: boolean, hasTouch?: boolean, - colorScheme?: 'dark' | 'light' | 'no-preference', - reducedMotion?: 'reduce' | 'no-preference', - forcedColors?: 'active' | 'none', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', + reducedMotion?: 'reduce' | 'no-preference' | 'no-override', + forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: boolean, baseURL?: string, recordVideo?: { diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index 78f94925f2..767c451474 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -445,16 +445,19 @@ ContextOptions: - dark - light - no-preference + - no-override reducedMotion: type: enum? literals: - reduce - no-preference + - no-override forcedColors: type: enum? literals: - active - none + - no-override acceptDownloads: boolean? baseURL: string? recordVideo: @@ -1173,30 +1176,26 @@ Page: literals: - screen - print - # Reset emulated value to the system default. - - null + - no-override colorScheme: type: enum? literals: - dark - light - no-preference - # Reset emulated value to the system default. - - null + - no-override reducedMotion: type: enum? literals: - reduce - no-preference - # Reset emulated value to the system default. - - null + - no-override forcedColors: type: enum? literals: - active - none - # Reset emulated value to the system default. - - null + - no-override exposeBinding: parameters: @@ -2974,6 +2973,7 @@ Electron: - dark - light - no-preference + - no-override extraHTTPHeaders: type: array? items: NameValue diff --git a/tests/page/page-emulate-media.spec.ts b/tests/page/page-emulate-media.spec.ts index 1f8bcca841..85caa1dc8f 100644 --- a/tests/page/page-emulate-media.spec.ts +++ b/tests/page/page-emulate-media.spec.ts @@ -35,7 +35,7 @@ it('should throw in case of bad media argument', async ({ page }) => { let error = null; // @ts-expect-error 'bad' is not a valid media type await page.emulateMedia({ media: 'bad' }).catch(e => error = e); - expect(error.message).toContain('media: expected one of (screen|print|null)'); + expect(error.message).toContain('media: expected one of (screen|print|no-override)'); }); it('should emulate colorScheme should work @smoke', async ({ page }) => { @@ -64,7 +64,7 @@ it('should throw in case of bad colorScheme argument', async ({ page }) => { let error = null; // @ts-expect-error 'bad' is not a valid media type await page.emulateMedia({ colorScheme: 'bad' }).catch(e => error = e); - expect(error.message).toContain('colorScheme: expected one of (dark|light|no-preference|null)'); + expect(error.message).toContain('colorScheme: expected one of (dark|light|no-preference|no-override)'); }); it('should work during navigation', async ({ page, server }) => {