From a200fe35282206ffdc2dd0b04b545daf90900321 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Fri, 1 Apr 2022 12:28:40 -0700 Subject: [PATCH] feat(screenshot): rename "size" option to "scale" (#13254) Drive-by: fix `caret` handling in `toHaveScreenshot`. --- docs/src/api/params.md | 6 ++--- .../playwright-core/src/protocol/channels.ts | 12 +++++----- .../playwright-core/src/protocol/protocol.yml | 2 +- .../playwright-core/src/protocol/validator.ts | 6 ++--- .../src/server/chromium/crPage.ts | 4 ++-- .../src/server/firefox/ffPage.ts | 4 ++-- packages/playwright-core/src/server/page.ts | 2 +- .../src/server/screenshotter.ts | 4 ++-- .../src/server/webkit/wkPage.ts | 4 ++-- packages/playwright-core/types/types.d.ts | 6 ++--- .../src/matchers/toMatchSnapshot.ts | 3 ++- packages/playwright-test/types/test.d.ts | 4 ++-- tests/library/screenshot.spec.ts | 12 +++++----- .../to-have-screenshot.spec.ts | 23 ++++++++++++++++++- utils/generate_types/overrides-test.d.ts | 4 ++-- 15 files changed, 59 insertions(+), 37 deletions(-) diff --git a/docs/src/api/params.md b/docs/src/api/params.md index 28ee059d79..97a1f1da3c 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -954,8 +954,8 @@ When true, takes a screenshot of the full scrollable page, instead of the curren An object which specifies clipping of the resulting image. Should have the following fields: -## screenshot-option-size -- `size` <[ScreenshotSize]<"css"|"device">> +## screenshot-option-scale +- `scale` <[ScreenshotScale]<"css"|"device">> When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this will keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so screenhots of high-dpi devices will be twice as large or even larger. Defaults to `"device"`. @@ -974,7 +974,7 @@ When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, - %%-screenshot-option-omit-background-%% - %%-screenshot-option-quality-%% - %%-screenshot-option-path-%% -- %%-screenshot-option-size-%% +- %%-screenshot-option-scale-%% - %%-screenshot-option-fonts-%% - %%-screenshot-option-caret-%% - %%-screenshot-option-type-%% diff --git a/packages/playwright-core/src/protocol/channels.ts b/packages/playwright-core/src/protocol/channels.ts index b2d2b657f0..cf56f673e3 100644 --- a/packages/playwright-core/src/protocol/channels.ts +++ b/packages/playwright-core/src/protocol/channels.ts @@ -1519,7 +1519,7 @@ export type PageExpectScreenshotParams = { omitBackground?: boolean, caret?: 'hide' | 'initial', animations?: 'disabled' | 'allow', - size?: 'css' | 'device', + scale?: 'css' | 'device', fonts?: 'ready' | 'nowait', mask?: { frame: FrameChannel, @@ -1545,7 +1545,7 @@ export type PageExpectScreenshotOptions = { omitBackground?: boolean, caret?: 'hide' | 'initial', animations?: 'disabled' | 'allow', - size?: 'css' | 'device', + scale?: 'css' | 'device', fonts?: 'ready' | 'nowait', mask?: { frame: FrameChannel, @@ -1569,7 +1569,7 @@ export type PageScreenshotParams = { omitBackground?: boolean, caret?: 'hide' | 'initial', animations?: 'disabled' | 'allow', - size?: 'css' | 'device', + scale?: 'css' | 'device', fonts?: 'ready' | 'nowait', mask?: { frame: FrameChannel, @@ -1585,7 +1585,7 @@ export type PageScreenshotOptions = { omitBackground?: boolean, caret?: 'hide' | 'initial', animations?: 'disabled' | 'allow', - size?: 'css' | 'device', + scale?: 'css' | 'device', fonts?: 'ready' | 'nowait', mask?: { frame: FrameChannel, @@ -2905,7 +2905,7 @@ export type ElementHandleScreenshotParams = { omitBackground?: boolean, caret?: 'hide' | 'initial', animations?: 'disabled' | 'allow', - size?: 'css' | 'device', + scale?: 'css' | 'device', fonts?: 'ready' | 'nowait', mask?: { frame: FrameChannel, @@ -2919,7 +2919,7 @@ export type ElementHandleScreenshotOptions = { omitBackground?: boolean, caret?: 'hide' | 'initial', animations?: 'disabled' | 'allow', - size?: 'css' | 'device', + scale?: 'css' | 'device', fonts?: 'ready' | 'nowait', mask?: { frame: FrameChannel, diff --git a/packages/playwright-core/src/protocol/protocol.yml b/packages/playwright-core/src/protocol/protocol.yml index 62fb42b633..d874749c27 100644 --- a/packages/playwright-core/src/protocol/protocol.yml +++ b/packages/playwright-core/src/protocol/protocol.yml @@ -323,7 +323,7 @@ CommonScreenshotOptions: literals: - disabled - allow - size: + scale: type: enum? literals: - css diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index ee6fcc8d2b..86e441a952 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -563,7 +563,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { omitBackground: tOptional(tBoolean), caret: tOptional(tEnum(['hide', 'initial'])), animations: tOptional(tEnum(['disabled', 'allow'])), - size: tOptional(tEnum(['css', 'device'])), + scale: tOptional(tEnum(['css', 'device'])), fonts: tOptional(tEnum(['ready', 'nowait'])), mask: tOptional(tArray(tObject({ frame: tChannel('Frame'), @@ -580,7 +580,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { omitBackground: tOptional(tBoolean), caret: tOptional(tEnum(['hide', 'initial'])), animations: tOptional(tEnum(['disabled', 'allow'])), - size: tOptional(tEnum(['css', 'device'])), + scale: tOptional(tEnum(['css', 'device'])), fonts: tOptional(tEnum(['ready', 'nowait'])), mask: tOptional(tArray(tObject({ frame: tChannel('Frame'), @@ -1085,7 +1085,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { omitBackground: tOptional(tBoolean), caret: tOptional(tEnum(['hide', 'initial'])), animations: tOptional(tEnum(['disabled', 'allow'])), - size: tOptional(tEnum(['css', 'device'])), + scale: tOptional(tEnum(['css', 'device'])), fonts: tOptional(tEnum(['ready', 'nowait'])), mask: tOptional(tArray(tObject({ frame: tChannel('Frame'), diff --git a/packages/playwright-core/src/server/chromium/crPage.ts b/packages/playwright-core/src/server/chromium/crPage.ts index 679d862dfc..a8ffd5c07f 100644 --- a/packages/playwright-core/src/server/chromium/crPage.ts +++ b/packages/playwright-core/src/server/chromium/crPage.ts @@ -252,7 +252,7 @@ export class CRPage implements PageDelegate { await this._mainFrameSession._client.send('Emulation.setDefaultBackgroundColorOverride', { color }); } - async takeScreenshot(progress: Progress, format: 'png' | 'jpeg', documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, size: 'css' | 'device'): Promise { + async takeScreenshot(progress: Progress, format: 'png' | 'jpeg', documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, scale: 'css' | 'device'): Promise { const { visualViewport } = await this._mainFrameSession._client.send('Page.getLayoutMetrics'); if (!documentRect) { documentRect = { @@ -267,7 +267,7 @@ export class CRPage implements PageDelegate { // When taking screenshots with documentRect (based on the page content, not viewport), // ignore current page scale. const clip = { ...documentRect, scale: viewportRect ? visualViewport.scale : 1 }; - if (size === 'css') { + if (scale === 'css') { const deviceScaleFactor = this._browserContext._options.deviceScaleFactor || 1; clip.scale /= deviceScaleFactor; } diff --git a/packages/playwright-core/src/server/firefox/ffPage.ts b/packages/playwright-core/src/server/firefox/ffPage.ts index 181b88b2ba..d07390cd39 100644 --- a/packages/playwright-core/src/server/firefox/ffPage.ts +++ b/packages/playwright-core/src/server/firefox/ffPage.ts @@ -412,7 +412,7 @@ export class FFPage implements PageDelegate { throw new Error('Not implemented'); } - async takeScreenshot(progress: Progress, format: 'png' | 'jpeg', documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, size: 'css' | 'device'): Promise { + async takeScreenshot(progress: Progress, format: 'png' | 'jpeg', documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, scale: 'css' | 'device'): Promise { if (!documentRect) { const scrollOffset = await this._page.mainFrame().waitForFunctionValueInUtility(progress, () => ({ x: window.scrollX, y: window.scrollY })); documentRect = { @@ -428,7 +428,7 @@ export class FFPage implements PageDelegate { const { data } = await this._session.send('Page.screenshot', { mimeType: ('image/' + format) as ('image/png' | 'image/jpeg'), clip: documentRect, - omitDeviceScaleFactor: size === 'css', + omitDeviceScaleFactor: scale === 'css', }); return Buffer.from(data, 'base64'); } diff --git a/packages/playwright-core/src/server/page.ts b/packages/playwright-core/src/server/page.ts index 33d8305abb..6f7dc9e889 100644 --- a/packages/playwright-core/src/server/page.ts +++ b/packages/playwright-core/src/server/page.ts @@ -62,7 +62,7 @@ export interface PageDelegate { bringToFront(): Promise; setBackgroundColor(color?: { r: number; g: number; b: number; a: number; }): Promise; - takeScreenshot(progress: Progress, format: string, documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, size: 'css' | 'device'): Promise; + takeScreenshot(progress: Progress, format: string, documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, scale: 'css' | 'device'): Promise; isElementHandle(remoteObject: any): boolean; adoptElementHandle(handle: dom.ElementHandle, to: dom.FrameExecutionContext): Promise>; diff --git a/packages/playwright-core/src/server/screenshotter.ts b/packages/playwright-core/src/server/screenshotter.ts index ba92d309e6..dfaf834809 100644 --- a/packages/playwright-core/src/server/screenshotter.ts +++ b/packages/playwright-core/src/server/screenshotter.ts @@ -40,7 +40,7 @@ export type ScreenshotOptions = { mask?: { frame: Frame, selector: string}[], fullPage?: boolean, clip?: Rect, - size?: 'css' | 'device', + scale?: 'css' | 'device', fonts?: 'ready' | 'nowait', caret?: 'hide' | 'initial', }; @@ -278,7 +278,7 @@ export class Screenshotter { const cleanupHighlight = await this._maskElements(progress, options); progress.throwIfAborted(); // Avoid extra work. - const buffer = await this._page._delegate.takeScreenshot(progress, format, documentRect, viewportRect, options.quality, fitsViewport, options.size || 'device'); + const buffer = await this._page._delegate.takeScreenshot(progress, format, documentRect, viewportRect, options.quality, fitsViewport, options.scale || 'device'); progress.throwIfAborted(); // Avoid restoring after failure - should be done by cleanup. await cleanupHighlight(); diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index 1e89ec76be..8c487de975 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -821,9 +821,9 @@ export class WKPage implements PageDelegate { this._recordingVideoFile = null; } - async takeScreenshot(progress: Progress, format: string, documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, size: 'css' | 'device'): Promise { + async takeScreenshot(progress: Progress, format: string, documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, scale: 'css' | 'device'): Promise { const rect = (documentRect || viewportRect)!; - const result = await this._session.send('Page.snapshotRect', { ...rect, coordinateSystem: documentRect ? 'Page' : 'Viewport', omitDeviceScaleFactor: size === 'css' }); + const result = await this._session.send('Page.snapshotRect', { ...rect, coordinateSystem: documentRect ? 'Page' : 'Viewport', omitDeviceScaleFactor: scale === 'css' }); const prefix = 'data:image/png;base64,'; let buffer = Buffer.from(result.dataURL.substr(prefix.length), 'base64'); if (format === 'jpeg') diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 2f0225d3b5..ff76d4bf85 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -8188,7 +8188,7 @@ export interface ElementHandle extends JSHandle { * keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so screenhots of * high-dpi devices will be twice as large or even larger. Defaults to `"device"`. */ - size?: "css"|"device"; + scale?: "css"|"device"; /** * Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by @@ -15770,7 +15770,7 @@ export interface LocatorScreenshotOptions { * keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so screenhots of * high-dpi devices will be twice as large or even larger. Defaults to `"device"`. */ - size?: "css"|"device"; + scale?: "css"|"device"; /** * Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by @@ -15960,7 +15960,7 @@ export interface PageScreenshotOptions { * keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so screenhots of * high-dpi devices will be twice as large or even larger. Defaults to `"device"`. */ - size?: "css"|"device"; + scale?: "css"|"device"; /** * Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by diff --git a/packages/playwright-test/src/matchers/toMatchSnapshot.ts b/packages/playwright-test/src/matchers/toMatchSnapshot.ts index 41645ca405..4f61157cba 100644 --- a/packages/playwright-test/src/matchers/toMatchSnapshot.ts +++ b/packages/playwright-test/src/matchers/toMatchSnapshot.ts @@ -311,7 +311,8 @@ export async function toHaveScreenshot( const screenshotOptions = { animations: config?.animations ?? 'disabled', fonts: config?.fonts ?? 'ready', - size: config?.size ?? 'css', + scale: config?.scale ?? 'css', + caret: config?.caret ?? 'hide', ...helper.allOptions, mask: (helper.allOptions.mask || []) as LocatorEx[], name: undefined, diff --git a/packages/playwright-test/types/test.d.ts b/packages/playwright-test/types/test.d.ts index 88a9a49ec4..b5c6415f4e 100644 --- a/packages/playwright-test/types/test.d.ts +++ b/packages/playwright-test/types/test.d.ts @@ -75,12 +75,12 @@ type ExpectSettings = { * keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so screenhots of * high-dpi devices will be twice as large or even larger. Defaults to `"css"`. */ - size?: 'css'|'device', + scale?: 'css'|'device', /** * When set to `"hide"`, screenshot will hide text caret. * When set to `"initial"`, text caret behavior will not be changed. Defaults to `"hide"`. */ - caret?: 'hide'|'initia', + caret?: 'hide'|'initial', } toMatchSnapshot?: { /** An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between pixels in compared images, between zero (strict) and one (lax). Defaults to `0.2`. diff --git a/tests/library/screenshot.spec.ts b/tests/library/screenshot.spec.ts index 78d58b91ff..31f0f9e395 100644 --- a/tests/library/screenshot.spec.ts +++ b/tests/library/screenshot.spec.ts @@ -90,20 +90,20 @@ browserTest.describe('page screenshot', () => { await context.close(); }); - browserTest('should work with device scale factor and size:css', async ({ browser, server }) => { + browserTest('should work with device scale factor and scale:css', async ({ browser, server }) => { const context = await browser.newContext({ viewport: { width: 320, height: 480 }, deviceScaleFactor: 2 }); const page = await context.newPage(); await page.goto(server.PREFIX + '/grid.html'); - const screenshot = await page.screenshot({ size: 'css' }); + const screenshot = await page.screenshot({ scale: 'css' }); expect(screenshot).toMatchSnapshot('screenshot-device-scale-factor-css-size.png'); await context.close(); }); - browserTest('should work with device scale factor, clip and size:css', async ({ browser, server }) => { + browserTest('should work with device scale factor, clip and scale:css', async ({ browser, server }) => { const context = await browser.newContext({ viewport: { width: 500, height: 500 }, deviceScaleFactor: 3 }); const page = await context.newPage(); await page.goto(server.PREFIX + '/grid.html'); - const screenshot = await page.screenshot({ clip: { x: 50, y: 100, width: 150, height: 100 }, size: 'css' }); + const screenshot = await page.screenshot({ clip: { x: 50, y: 100, width: 150, height: 100 }, scale: 'css' }); expect(screenshot).toMatchSnapshot('screenshot-device-scale-factor-clip-css-size.png'); await context.close(); }); @@ -396,7 +396,7 @@ browserTest.describe('element screenshot', () => { await context.close(); }); - browserTest('should capture full element when larger than viewport with device scale factor and size:css', async ({ browser }) => { + browserTest('should capture full element when larger than viewport with device scale factor and scale:css', async ({ browser }) => { const context = await browser.newContext({ viewport: { width: 501, height: 501 }, deviceScaleFactor: 2.5 }); const page = await context.newPage(); await page.setContent(` @@ -416,7 +416,7 @@ browserTest.describe('element screenshot', () => {
`); - const screenshot = await page.locator('div.to-screenshot').screenshot({ size: 'css' }); + const screenshot = await page.locator('div.to-screenshot').screenshot({ scale: 'css' }); expect(screenshot).toMatchSnapshot('element-larger-than-viewport-dsf-css-size.png'); await context.close(); }); diff --git a/tests/playwright-test/to-have-screenshot.spec.ts b/tests/playwright-test/to-have-screenshot.spec.ts index 47f704b4d0..bbfe50362b 100644 --- a/tests/playwright-test/to-have-screenshot.spec.ts +++ b/tests/playwright-test/to-have-screenshot.spec.ts @@ -73,7 +73,7 @@ test('should disable animations by default', async ({ runInlineTest }, testInfo) expect(result.exitCode).toBe(0); }); -test('should have size as css by default', async ({ runInlineTest }, testInfo) => { +test('should have scale:css by default', async ({ runInlineTest }, testInfo) => { const result = await runInlineTest({ ...playwrightConfig({ screenshotsDir: '__screenshots__' }), 'a.spec.js': ` @@ -339,6 +339,24 @@ test('should generate default name', async ({ runInlineTest }, testInfo) => { test('should compile with different option combinations', async ({ runTSC }) => { const result = await runTSC({ + 'playwright.config.ts': ` + import type { PlaywrightTestConfig } from '@playwright/test'; + const config: PlaywrightTestConfig = { + expect: { + timeout: 10000, + toHaveScreenshot: { + threshold: 0.2, + maxDiffPixels: 10, + maxDiffPixelRatio: 0.2, + animations: "allow", + fonts: "ready", + caret: "hide", + scale: "css", + }, + }, + }; + export default config; + `, 'a.spec.ts': ` const { test } = pwt; test('is a test', async ({ page }) => { @@ -351,6 +369,9 @@ test('should compile with different option combinations', async ({ runTSC }) => maxDiffPixelRatio: 0.2, animations: "disabled", omitBackground: true, + fonts: "nowait", + caret: "initial", + scale: "device", timeout: 1000, }); }); diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index 34b4862816..2e02456029 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -74,12 +74,12 @@ type ExpectSettings = { * keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so screenhots of * high-dpi devices will be twice as large or even larger. Defaults to `"css"`. */ - size?: 'css'|'device', + scale?: 'css'|'device', /** * When set to `"hide"`, screenshot will hide text caret. * When set to `"initial"`, text caret behavior will not be changed. Defaults to `"hide"`. */ - caret?: 'hide'|'initia', + caret?: 'hide'|'initial', } toMatchSnapshot?: { /** An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between pixels in compared images, between zero (strict) and one (lax). Defaults to `0.2`.