From b45c788a33b1329f554e154ba48370b3d142f548 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Fri, 4 Mar 2022 12:02:59 -0700 Subject: [PATCH] fix(disable-animations): rename boolean to enum (#12503) Enums are more flexible in the long run since they let us easily extend API. References #12441 --- docs/src/api/class-locatorassertions.md | 2 +- docs/src/api/class-pageassertions.md | 2 +- docs/src/api/params.md | 12 +++---- .../playwright-core/src/protocol/channels.ts | 12 +++---- .../playwright-core/src/protocol/protocol.yml | 15 ++++++-- .../playwright-core/src/protocol/validator.ts | 6 ++-- .../src/server/screenshotter.ts | 6 ++-- packages/playwright-core/types/types.d.ts | 30 +++++++++------- tests/page/page-screenshot.spec.ts | 36 +++++++++---------- .../to-have-screenshot.spec.ts | 6 ++-- 10 files changed, 71 insertions(+), 56 deletions(-) diff --git a/docs/src/api/class-locatorassertions.md b/docs/src/api/class-locatorassertions.md index d8bb7e590e..d48dce3a85 100644 --- a/docs/src/api/class-locatorassertions.md +++ b/docs/src/api/class-locatorassertions.md @@ -1015,7 +1015,7 @@ await expect(locator).toHaveScreenshot(); ### option: LocatorAssertions.toHaveScreenshot.timeout = %%-js-assertions-timeout-%% ### option: LocatorAssertions.toHaveScreenshot.timeout = %%-csharp-java-python-assertions-timeout-%% -### option: LocatorAssertions.toHaveScreenshot.disableAnimations = %%-screenshot-option-disable-animations-%% +### option: LocatorAssertions.toHaveScreenshot.animations = %%-screenshot-option-animations-%% ### option: LocatorAssertions.toHaveScreenshot.omitBackground = %%-screenshot-option-omit-background-%% diff --git a/docs/src/api/class-pageassertions.md b/docs/src/api/class-pageassertions.md index 7387fd2417..953c284724 100644 --- a/docs/src/api/class-pageassertions.md +++ b/docs/src/api/class-pageassertions.md @@ -130,7 +130,7 @@ await expect(page).toHaveScreenshot(); ### option: PageAssertions.toHaveScreenshot.timeout = %%-js-assertions-timeout-%% ### option: PageAssertions.toHaveScreenshot.timeout = %%-csharp-java-python-assertions-timeout-%% -### option: PageAssertions.toHaveScreenshot.disableAnimations = %%-screenshot-option-disable-animations-%% +### option: PageAssertions.toHaveScreenshot.animations = %%-screenshot-option-animations-%% ### option: PageAssertions.toHaveScreenshot.omitBackground = %%-screenshot-option-omit-background-%% diff --git a/docs/src/api/params.md b/docs/src/api/params.md index 4ccafbdb4d..057c3db7e6 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -901,12 +901,12 @@ Note that outer and inner locators must belong to the same frame. Inner locator - %%-locator-option-has-text-%% - %%-locator-option-has-%% -## screenshot-option-disable-animations -- `disableAnimations` <[boolean]> +## screenshot-option-animations +- `animations` <"disabled"> -When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on their duration: -- finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. -- infinite animations are canceled to initial state, and then played over after the screenshot. +When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on their duration: +* finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. +* infinite animations are canceled to initial state, and then played over after the screenshot. ## screenshot-option-omit-background - `omitBackground` <[boolean]> @@ -953,7 +953,7 @@ 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-options-common-list -- %%-screenshot-option-disable-animations-%% +- %%-screenshot-option-animations-%% - %%-screenshot-option-omit-background-%% - %%-screenshot-option-quality-%% - %%-screenshot-option-path-%% diff --git a/packages/playwright-core/src/protocol/channels.ts b/packages/playwright-core/src/protocol/channels.ts index 4cbce6f617..77caec0804 100644 --- a/packages/playwright-core/src/protocol/channels.ts +++ b/packages/playwright-core/src/protocol/channels.ts @@ -1503,7 +1503,7 @@ export type PageExpectScreenshotParams = { screenshotOptions?: { omitBackground?: boolean, fullPage?: boolean, - disableAnimations?: boolean, + animations?: 'disabled', clip?: Rect, mask?: { frame: FrameChannel, @@ -1526,7 +1526,7 @@ export type PageExpectScreenshotOptions = { screenshotOptions?: { omitBackground?: boolean, fullPage?: boolean, - disableAnimations?: boolean, + animations?: 'disabled', clip?: Rect, mask?: { frame: FrameChannel, @@ -1547,7 +1547,7 @@ export type PageScreenshotParams = { quality?: number, omitBackground?: boolean, fullPage?: boolean, - disableAnimations?: boolean, + animations?: 'disabled', clip?: Rect, mask?: { frame: FrameChannel, @@ -1560,7 +1560,7 @@ export type PageScreenshotOptions = { quality?: number, omitBackground?: boolean, fullPage?: boolean, - disableAnimations?: boolean, + animations?: 'disabled', clip?: Rect, mask?: { frame: FrameChannel, @@ -2860,7 +2860,7 @@ export type ElementHandleScreenshotParams = { type?: 'png' | 'jpeg', quality?: number, omitBackground?: boolean, - disableAnimations?: boolean, + animations?: 'disabled', mask?: { frame: FrameChannel, selector: string, @@ -2871,7 +2871,7 @@ export type ElementHandleScreenshotOptions = { type?: 'png' | 'jpeg', quality?: number, omitBackground?: boolean, - disableAnimations?: boolean, + animations?: 'disabled', mask?: { frame: FrameChannel, selector: string, diff --git a/packages/playwright-core/src/protocol/protocol.yml b/packages/playwright-core/src/protocol/protocol.yml index 65531b43e6..227eb1e79a 100644 --- a/packages/playwright-core/src/protocol/protocol.yml +++ b/packages/playwright-core/src/protocol/protocol.yml @@ -1011,7 +1011,10 @@ Page: properties: omitBackground: boolean? fullPage: boolean? - disableAnimations: boolean? + animations: + type: enum? + literals: + - disabled clip: Rect? mask: type: array? @@ -1042,7 +1045,10 @@ Page: quality: number? omitBackground: boolean? fullPage: boolean? - disableAnimations: boolean? + animations: + type: enum? + literals: + - disabled clip: Rect? mask: type: array? @@ -2204,7 +2210,10 @@ ElementHandle: - jpeg quality: number? omitBackground: boolean? - disableAnimations: boolean? + animations: + type: enum? + literals: + - disabled mask: type: array? items: diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index 8f42d65602..67d81ff6bd 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -556,7 +556,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { screenshotOptions: tOptional(tObject({ omitBackground: tOptional(tBoolean), fullPage: tOptional(tBoolean), - disableAnimations: tOptional(tBoolean), + animations: tOptional(tEnum(['disabled'])), clip: tOptional(tType('Rect')), mask: tOptional(tArray(tObject({ frame: tChannel('Frame'), @@ -570,7 +570,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { quality: tOptional(tNumber), omitBackground: tOptional(tBoolean), fullPage: tOptional(tBoolean), - disableAnimations: tOptional(tBoolean), + animations: tOptional(tEnum(['disabled'])), clip: tOptional(tType('Rect')), mask: tOptional(tArray(tObject({ frame: tChannel('Frame'), @@ -1065,7 +1065,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { type: tOptional(tEnum(['png', 'jpeg'])), quality: tOptional(tNumber), omitBackground: tOptional(tBoolean), - disableAnimations: tOptional(tBoolean), + animations: tOptional(tEnum(['disabled'])), mask: tOptional(tArray(tObject({ frame: tChannel('Frame'), selector: tString, diff --git a/packages/playwright-core/src/server/screenshotter.ts b/packages/playwright-core/src/server/screenshotter.ts index 71bef2b262..351baf5db4 100644 --- a/packages/playwright-core/src/server/screenshotter.ts +++ b/packages/playwright-core/src/server/screenshotter.ts @@ -36,7 +36,7 @@ export type ScreenshotOptions = { type?: 'png' | 'jpeg', quality?: number, omitBackground?: boolean, - disableAnimations?: boolean, + animations?: 'disabled', mask?: { frame: Frame, selector: string}[], fullPage?: boolean, clip?: Rect, @@ -83,7 +83,7 @@ export class Screenshotter { const format = validateScreenshotOptions(options); return this._queue.postTask(async () => { const { viewportSize } = await this._originalViewportSize(progress); - await this._preparePageForScreenshot(progress, options.disableAnimations || false); + await this._preparePageForScreenshot(progress, options.animations === 'disabled'); progress.throwIfAborted(); // Avoid restoring after failure - should be done by cleanup. if (options.fullPage) { @@ -111,7 +111,7 @@ export class Screenshotter { return this._queue.postTask(async () => { const { viewportSize } = await this._originalViewportSize(progress); - await this._preparePageForScreenshot(progress, options.disableAnimations || false); + await this._preparePageForScreenshot(progress, options.animations === 'disabled'); progress.throwIfAborted(); // Do not do extra work. await handle._waitAndScrollIntoViewIfNeeded(progress); diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 019db99392..78fffed093 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -8066,10 +8066,12 @@ export interface ElementHandle extends JSHandle { */ screenshot(options?: { /** - * When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on - * their duration: + * When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment + * depending on their duration: + * - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + * - infinite animations are canceled to initial state, and then played over after the screenshot. */ - disableAnimations?: boolean; + animations?: "disabled"; /** * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box @@ -15572,10 +15574,12 @@ export interface ConnectOptions { export interface LocatorScreenshotOptions { /** - * When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on - * their duration: + * When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment + * depending on their duration: + * - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + * - infinite animations are canceled to initial state, and then played over after the screenshot. */ - disableAnimations?: boolean; + animations?: "disabled"; /** * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box @@ -15706,6 +15710,14 @@ interface PageWaitForFunctionOptions { } export interface PageScreenshotOptions { + /** + * When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment + * depending on their duration: + * - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + * - infinite animations are canceled to initial state, and then played over after the screenshot. + */ + animations?: "disabled"; + /** * An object which specifies clipping of the resulting image. Should have the following fields: */ @@ -15731,12 +15743,6 @@ export interface PageScreenshotOptions { height: number; }; - /** - * When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on - * their duration: - */ - disableAnimations?: boolean; - /** * When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Defaults to * `false`. diff --git a/tests/page/page-screenshot.spec.ts b/tests/page/page-screenshot.spec.ts index 7b84fe750c..1834bbbdc9 100644 --- a/tests/page/page-screenshot.spec.ts +++ b/tests/page/page-screenshot.spec.ts @@ -452,12 +452,12 @@ it.describe('page screenshot animations', () => { await page.goto(server.PREFIX + '/rotate-z.html'); const div = page.locator('div'); const screenshot = await div.screenshot({ - disableAnimations: true, + animations: 'disabled', }); for (let i = 0; i < 10; ++i) { await rafraf(page); const newScreenshot = await div.screenshot({ - disableAnimations: true, + animations: 'disabled', }); expect(newScreenshot.equals(screenshot)).toBe(true); } @@ -467,12 +467,12 @@ it.describe('page screenshot animations', () => { await page.goto(server.PREFIX + '/rotate-pseudo.html'); const div = page.locator('div'); const screenshot = await div.screenshot({ - disableAnimations: true, + animations: 'disabled', }); for (let i = 0; i < 10; ++i) { await rafraf(page); const newScreenshot = await div.screenshot({ - disableAnimations: true, + animations: 'disabled', }); expect(newScreenshot.equals(screenshot)).toBe(true); } @@ -481,12 +481,12 @@ it.describe('page screenshot animations', () => { it('should not capture css animations in shadow DOM', async ({ page, server }) => { await page.goto(server.PREFIX + '/rotate-z-shadow-dom.html'); const screenshot = await page.screenshot({ - disableAnimations: true, + animations: 'disabled', }); for (let i = 0; i < 4; ++i) { await rafraf(page); const newScreenshot = await page.screenshot({ - disableAnimations: true, + animations: 'disabled', }); expect(newScreenshot.equals(screenshot)).toBe(true); } @@ -498,7 +498,7 @@ it.describe('page screenshot animations', () => { // Stop rotating bar. await page.$eval('div', el => el.style.setProperty('animation', 'none')); const buffer1 = await page.screenshot({ - disableAnimations: true, + animations: 'disabled', // Start rotating bar right before screenshot. __testHookBeforeScreenshot: async () => { await page.$eval('div', el => el.style.removeProperty('animation')); @@ -506,7 +506,7 @@ it.describe('page screenshot animations', () => { } as any); await rafraf(page); const buffer2 = await page.screenshot({ - disableAnimations: true, + animations: 'disabled', }); expect(buffer1.equals(buffer2)).toBe(true); }); @@ -514,7 +514,7 @@ it.describe('page screenshot animations', () => { it('should resume infinite animations', async ({ page, server }) => { await page.goto(server.PREFIX + '/rotate-z.html'); await page.screenshot({ - disableAnimations: true, + animations: 'disabled', }); const buffer1 = await page.screenshot(); await rafraf(page); @@ -526,12 +526,12 @@ it.describe('page screenshot animations', () => { await page.goto(server.PREFIX + '/web-animation.html'); const div = page.locator('div'); const screenshot = await div.screenshot({ - disableAnimations: true, + animations: 'disabled', }); for (let i = 0; i < 10; ++i) { await rafraf(page); const newScreenshot = await div.screenshot({ - disableAnimations: true, + animations: 'disabled', }); expect(newScreenshot.equals(screenshot)).toBe(true); } @@ -558,7 +558,7 @@ it.describe('page screenshot animations', () => { // Make a screenshot that finishes all finite animations. const screenshot1 = await div.screenshot({ - disableAnimations: true, + animations: 'disabled', }); await rafraf(page); // Make sure finite transition is not restarted. @@ -592,7 +592,7 @@ it.describe('page screenshot animations', () => { // 1. Make a screenshot that finishes all finite animations // and triggers layout. const screenshot1 = await page.screenshot({ - disableAnimations: true, + animations: 'disabled', }); // 2. Make a second screenshot after h1 is on screen. @@ -616,11 +616,11 @@ it.describe('page screenshot animations', () => { window.animation.currentTime = 500; }); const screenshot1 = await page.screenshot({ - disableAnimations: true, + animations: 'disabled', }); await rafraf(page); const screenshot2 = await page.screenshot({ - disableAnimations: true, + animations: 'disabled', }); expect(screenshot1.equals(screenshot2)).toBe(true); expect(await page.evaluate(() => ({ @@ -648,7 +648,7 @@ it.describe('page screenshot animations', () => { await animation.ready; }); await Promise.all([ - page.screenshot({ disableAnimations: true }), + page.screenshot({ animations: 'disabled' }), page.waitForEvent('console', msg => msg.text() === 'transitionend'), ]); expect(await page.evaluate(() => window._EVENTS)).toEqual([ @@ -672,7 +672,7 @@ it.describe('page screenshot animations', () => { await animation.ready; }); await Promise.all([ - page.screenshot({ disableAnimations: true }), + page.screenshot({ animations: 'disabled' }), page.waitForEvent('console', msg => msg.text() === 'animationcancel'), ]); expect(await page.evaluate(() => window._EVENTS)).toEqual([ @@ -700,7 +700,7 @@ it.describe('page screenshot animations', () => { // Ensure CSS animation is finite. expect(await div.evaluate(async el => Number.isFinite(el.getAnimations()[0].effect.getComputedTiming().endTime))).toBe(true); await Promise.all([ - page.screenshot({ disableAnimations: true }), + page.screenshot({ animations: 'disabled' }), page.waitForEvent('console', msg => msg.text() === 'animationend'), ]); expect(await page.evaluate(() => window._EVENTS)).toEqual([ diff --git a/tests/playwright-test/to-have-screenshot.spec.ts b/tests/playwright-test/to-have-screenshot.spec.ts index 3b8c0c30b2..bc6918b12f 100644 --- a/tests/playwright-test/to-have-screenshot.spec.ts +++ b/tests/playwright-test/to-have-screenshot.spec.ts @@ -75,7 +75,7 @@ test('should not fail when racing with navigation', async ({ runInlineTest }, te page.goto('${infiniteAnimationURL}'), expect(page).toHaveScreenshot({ name: 'snapshot.png', - disableAnimations: true, + animations: "disabled", clip: { x: 0, y: 0, width: 10, height: 10 }, }), ]); @@ -94,7 +94,7 @@ test('should successfully screenshot a page with infinite animation with disable test('is a test', async ({ page }) => { await page.goto('${infiniteAnimationURL}'); await expect(page).toHaveScreenshot({ - disableAnimations: true, + animations: "disabled", }); }); ` @@ -217,7 +217,7 @@ test('should compile with different option combinations', async ({ runTSC }) => threshold: 0.2, maxDiffPixels: 10, maxDiffPixelRatio: 0.2, - disableAnimations: true, + animations: "disabled", omitBackground: true, timeout: 1000, });