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
This commit is contained in:
Andrey Lushnikov 2022-03-04 12:02:59 -07:00 committed by GitHub
parent 1f5cfcaeec
commit b45c788a33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 71 additions and 56 deletions

View File

@ -1015,7 +1015,7 @@ await expect(locator).toHaveScreenshot();
### option: LocatorAssertions.toHaveScreenshot.timeout = %%-js-assertions-timeout-%% ### option: LocatorAssertions.toHaveScreenshot.timeout = %%-js-assertions-timeout-%%
### option: LocatorAssertions.toHaveScreenshot.timeout = %%-csharp-java-python-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-%% ### option: LocatorAssertions.toHaveScreenshot.omitBackground = %%-screenshot-option-omit-background-%%

View File

@ -130,7 +130,7 @@ await expect(page).toHaveScreenshot();
### option: PageAssertions.toHaveScreenshot.timeout = %%-js-assertions-timeout-%% ### option: PageAssertions.toHaveScreenshot.timeout = %%-js-assertions-timeout-%%
### option: PageAssertions.toHaveScreenshot.timeout = %%-csharp-java-python-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-%% ### option: PageAssertions.toHaveScreenshot.omitBackground = %%-screenshot-option-omit-background-%%

View File

@ -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-text-%%
- %%-locator-option-has-%% - %%-locator-option-has-%%
## screenshot-option-disable-animations ## screenshot-option-animations
- `disableAnimations` <[boolean]> - `animations` <"disabled">
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. * 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. * infinite animations are canceled to initial state, and then played over after the screenshot.
## screenshot-option-omit-background ## screenshot-option-omit-background
- `omitBackground` <[boolean]> - `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: An object which specifies clipping of the resulting image. Should have the following fields:
## screenshot-options-common-list ## screenshot-options-common-list
- %%-screenshot-option-disable-animations-%% - %%-screenshot-option-animations-%%
- %%-screenshot-option-omit-background-%% - %%-screenshot-option-omit-background-%%
- %%-screenshot-option-quality-%% - %%-screenshot-option-quality-%%
- %%-screenshot-option-path-%% - %%-screenshot-option-path-%%

View File

@ -1503,7 +1503,7 @@ export type PageExpectScreenshotParams = {
screenshotOptions?: { screenshotOptions?: {
omitBackground?: boolean, omitBackground?: boolean,
fullPage?: boolean, fullPage?: boolean,
disableAnimations?: boolean, animations?: 'disabled',
clip?: Rect, clip?: Rect,
mask?: { mask?: {
frame: FrameChannel, frame: FrameChannel,
@ -1526,7 +1526,7 @@ export type PageExpectScreenshotOptions = {
screenshotOptions?: { screenshotOptions?: {
omitBackground?: boolean, omitBackground?: boolean,
fullPage?: boolean, fullPage?: boolean,
disableAnimations?: boolean, animations?: 'disabled',
clip?: Rect, clip?: Rect,
mask?: { mask?: {
frame: FrameChannel, frame: FrameChannel,
@ -1547,7 +1547,7 @@ export type PageScreenshotParams = {
quality?: number, quality?: number,
omitBackground?: boolean, omitBackground?: boolean,
fullPage?: boolean, fullPage?: boolean,
disableAnimations?: boolean, animations?: 'disabled',
clip?: Rect, clip?: Rect,
mask?: { mask?: {
frame: FrameChannel, frame: FrameChannel,
@ -1560,7 +1560,7 @@ export type PageScreenshotOptions = {
quality?: number, quality?: number,
omitBackground?: boolean, omitBackground?: boolean,
fullPage?: boolean, fullPage?: boolean,
disableAnimations?: boolean, animations?: 'disabled',
clip?: Rect, clip?: Rect,
mask?: { mask?: {
frame: FrameChannel, frame: FrameChannel,
@ -2860,7 +2860,7 @@ export type ElementHandleScreenshotParams = {
type?: 'png' | 'jpeg', type?: 'png' | 'jpeg',
quality?: number, quality?: number,
omitBackground?: boolean, omitBackground?: boolean,
disableAnimations?: boolean, animations?: 'disabled',
mask?: { mask?: {
frame: FrameChannel, frame: FrameChannel,
selector: string, selector: string,
@ -2871,7 +2871,7 @@ export type ElementHandleScreenshotOptions = {
type?: 'png' | 'jpeg', type?: 'png' | 'jpeg',
quality?: number, quality?: number,
omitBackground?: boolean, omitBackground?: boolean,
disableAnimations?: boolean, animations?: 'disabled',
mask?: { mask?: {
frame: FrameChannel, frame: FrameChannel,
selector: string, selector: string,

View File

@ -1011,7 +1011,10 @@ Page:
properties: properties:
omitBackground: boolean? omitBackground: boolean?
fullPage: boolean? fullPage: boolean?
disableAnimations: boolean? animations:
type: enum?
literals:
- disabled
clip: Rect? clip: Rect?
mask: mask:
type: array? type: array?
@ -1042,7 +1045,10 @@ Page:
quality: number? quality: number?
omitBackground: boolean? omitBackground: boolean?
fullPage: boolean? fullPage: boolean?
disableAnimations: boolean? animations:
type: enum?
literals:
- disabled
clip: Rect? clip: Rect?
mask: mask:
type: array? type: array?
@ -2204,7 +2210,10 @@ ElementHandle:
- jpeg - jpeg
quality: number? quality: number?
omitBackground: boolean? omitBackground: boolean?
disableAnimations: boolean? animations:
type: enum?
literals:
- disabled
mask: mask:
type: array? type: array?
items: items:

View File

@ -556,7 +556,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
screenshotOptions: tOptional(tObject({ screenshotOptions: tOptional(tObject({
omitBackground: tOptional(tBoolean), omitBackground: tOptional(tBoolean),
fullPage: tOptional(tBoolean), fullPage: tOptional(tBoolean),
disableAnimations: tOptional(tBoolean), animations: tOptional(tEnum(['disabled'])),
clip: tOptional(tType('Rect')), clip: tOptional(tType('Rect')),
mask: tOptional(tArray(tObject({ mask: tOptional(tArray(tObject({
frame: tChannel('Frame'), frame: tChannel('Frame'),
@ -570,7 +570,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
quality: tOptional(tNumber), quality: tOptional(tNumber),
omitBackground: tOptional(tBoolean), omitBackground: tOptional(tBoolean),
fullPage: tOptional(tBoolean), fullPage: tOptional(tBoolean),
disableAnimations: tOptional(tBoolean), animations: tOptional(tEnum(['disabled'])),
clip: tOptional(tType('Rect')), clip: tOptional(tType('Rect')),
mask: tOptional(tArray(tObject({ mask: tOptional(tArray(tObject({
frame: tChannel('Frame'), frame: tChannel('Frame'),
@ -1065,7 +1065,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
type: tOptional(tEnum(['png', 'jpeg'])), type: tOptional(tEnum(['png', 'jpeg'])),
quality: tOptional(tNumber), quality: tOptional(tNumber),
omitBackground: tOptional(tBoolean), omitBackground: tOptional(tBoolean),
disableAnimations: tOptional(tBoolean), animations: tOptional(tEnum(['disabled'])),
mask: tOptional(tArray(tObject({ mask: tOptional(tArray(tObject({
frame: tChannel('Frame'), frame: tChannel('Frame'),
selector: tString, selector: tString,

View File

@ -36,7 +36,7 @@ export type ScreenshotOptions = {
type?: 'png' | 'jpeg', type?: 'png' | 'jpeg',
quality?: number, quality?: number,
omitBackground?: boolean, omitBackground?: boolean,
disableAnimations?: boolean, animations?: 'disabled',
mask?: { frame: Frame, selector: string}[], mask?: { frame: Frame, selector: string}[],
fullPage?: boolean, fullPage?: boolean,
clip?: Rect, clip?: Rect,
@ -83,7 +83,7 @@ export class Screenshotter {
const format = validateScreenshotOptions(options); const format = validateScreenshotOptions(options);
return this._queue.postTask(async () => { return this._queue.postTask(async () => {
const { viewportSize } = await this._originalViewportSize(progress); 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. progress.throwIfAborted(); // Avoid restoring after failure - should be done by cleanup.
if (options.fullPage) { if (options.fullPage) {
@ -111,7 +111,7 @@ export class Screenshotter {
return this._queue.postTask(async () => { return this._queue.postTask(async () => {
const { viewportSize } = await this._originalViewportSize(progress); 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. progress.throwIfAborted(); // Do not do extra work.
await handle._waitAndScrollIntoViewIfNeeded(progress); await handle._waitAndScrollIntoViewIfNeeded(progress);

View File

@ -8066,10 +8066,12 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
*/ */
screenshot(options?: { screenshot(options?: {
/** /**
* When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on * When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment
* their duration: * 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 * 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 { export interface LocatorScreenshotOptions {
/** /**
* When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on * When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment
* their duration: * 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 * 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 { 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: * An object which specifies clipping of the resulting image. Should have the following fields:
*/ */
@ -15731,12 +15743,6 @@ export interface PageScreenshotOptions {
height: number; 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 * When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Defaults to
* `false`. * `false`.

View File

@ -452,12 +452,12 @@ it.describe('page screenshot animations', () => {
await page.goto(server.PREFIX + '/rotate-z.html'); await page.goto(server.PREFIX + '/rotate-z.html');
const div = page.locator('div'); const div = page.locator('div');
const screenshot = await div.screenshot({ const screenshot = await div.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
for (let i = 0; i < 10; ++i) { for (let i = 0; i < 10; ++i) {
await rafraf(page); await rafraf(page);
const newScreenshot = await div.screenshot({ const newScreenshot = await div.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
expect(newScreenshot.equals(screenshot)).toBe(true); expect(newScreenshot.equals(screenshot)).toBe(true);
} }
@ -467,12 +467,12 @@ it.describe('page screenshot animations', () => {
await page.goto(server.PREFIX + '/rotate-pseudo.html'); await page.goto(server.PREFIX + '/rotate-pseudo.html');
const div = page.locator('div'); const div = page.locator('div');
const screenshot = await div.screenshot({ const screenshot = await div.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
for (let i = 0; i < 10; ++i) { for (let i = 0; i < 10; ++i) {
await rafraf(page); await rafraf(page);
const newScreenshot = await div.screenshot({ const newScreenshot = await div.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
expect(newScreenshot.equals(screenshot)).toBe(true); 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 }) => { it('should not capture css animations in shadow DOM', async ({ page, server }) => {
await page.goto(server.PREFIX + '/rotate-z-shadow-dom.html'); await page.goto(server.PREFIX + '/rotate-z-shadow-dom.html');
const screenshot = await page.screenshot({ const screenshot = await page.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
for (let i = 0; i < 4; ++i) { for (let i = 0; i < 4; ++i) {
await rafraf(page); await rafraf(page);
const newScreenshot = await page.screenshot({ const newScreenshot = await page.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
expect(newScreenshot.equals(screenshot)).toBe(true); expect(newScreenshot.equals(screenshot)).toBe(true);
} }
@ -498,7 +498,7 @@ it.describe('page screenshot animations', () => {
// Stop rotating bar. // Stop rotating bar.
await page.$eval('div', el => el.style.setProperty('animation', 'none')); await page.$eval('div', el => el.style.setProperty('animation', 'none'));
const buffer1 = await page.screenshot({ const buffer1 = await page.screenshot({
disableAnimations: true, animations: 'disabled',
// Start rotating bar right before screenshot. // Start rotating bar right before screenshot.
__testHookBeforeScreenshot: async () => { __testHookBeforeScreenshot: async () => {
await page.$eval('div', el => el.style.removeProperty('animation')); await page.$eval('div', el => el.style.removeProperty('animation'));
@ -506,7 +506,7 @@ it.describe('page screenshot animations', () => {
} as any); } as any);
await rafraf(page); await rafraf(page);
const buffer2 = await page.screenshot({ const buffer2 = await page.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
expect(buffer1.equals(buffer2)).toBe(true); expect(buffer1.equals(buffer2)).toBe(true);
}); });
@ -514,7 +514,7 @@ it.describe('page screenshot animations', () => {
it('should resume infinite animations', async ({ page, server }) => { it('should resume infinite animations', async ({ page, server }) => {
await page.goto(server.PREFIX + '/rotate-z.html'); await page.goto(server.PREFIX + '/rotate-z.html');
await page.screenshot({ await page.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
const buffer1 = await page.screenshot(); const buffer1 = await page.screenshot();
await rafraf(page); await rafraf(page);
@ -526,12 +526,12 @@ it.describe('page screenshot animations', () => {
await page.goto(server.PREFIX + '/web-animation.html'); await page.goto(server.PREFIX + '/web-animation.html');
const div = page.locator('div'); const div = page.locator('div');
const screenshot = await div.screenshot({ const screenshot = await div.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
for (let i = 0; i < 10; ++i) { for (let i = 0; i < 10; ++i) {
await rafraf(page); await rafraf(page);
const newScreenshot = await div.screenshot({ const newScreenshot = await div.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
expect(newScreenshot.equals(screenshot)).toBe(true); expect(newScreenshot.equals(screenshot)).toBe(true);
} }
@ -558,7 +558,7 @@ it.describe('page screenshot animations', () => {
// Make a screenshot that finishes all finite animations. // Make a screenshot that finishes all finite animations.
const screenshot1 = await div.screenshot({ const screenshot1 = await div.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
await rafraf(page); await rafraf(page);
// Make sure finite transition is not restarted. // 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 // 1. Make a screenshot that finishes all finite animations
// and triggers layout. // and triggers layout.
const screenshot1 = await page.screenshot({ const screenshot1 = await page.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
// 2. Make a second screenshot after h1 is on screen. // 2. Make a second screenshot after h1 is on screen.
@ -616,11 +616,11 @@ it.describe('page screenshot animations', () => {
window.animation.currentTime = 500; window.animation.currentTime = 500;
}); });
const screenshot1 = await page.screenshot({ const screenshot1 = await page.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
await rafraf(page); await rafraf(page);
const screenshot2 = await page.screenshot({ const screenshot2 = await page.screenshot({
disableAnimations: true, animations: 'disabled',
}); });
expect(screenshot1.equals(screenshot2)).toBe(true); expect(screenshot1.equals(screenshot2)).toBe(true);
expect(await page.evaluate(() => ({ expect(await page.evaluate(() => ({
@ -648,7 +648,7 @@ it.describe('page screenshot animations', () => {
await animation.ready; await animation.ready;
}); });
await Promise.all([ await Promise.all([
page.screenshot({ disableAnimations: true }), page.screenshot({ animations: 'disabled' }),
page.waitForEvent('console', msg => msg.text() === 'transitionend'), page.waitForEvent('console', msg => msg.text() === 'transitionend'),
]); ]);
expect(await page.evaluate(() => window._EVENTS)).toEqual([ expect(await page.evaluate(() => window._EVENTS)).toEqual([
@ -672,7 +672,7 @@ it.describe('page screenshot animations', () => {
await animation.ready; await animation.ready;
}); });
await Promise.all([ await Promise.all([
page.screenshot({ disableAnimations: true }), page.screenshot({ animations: 'disabled' }),
page.waitForEvent('console', msg => msg.text() === 'animationcancel'), page.waitForEvent('console', msg => msg.text() === 'animationcancel'),
]); ]);
expect(await page.evaluate(() => window._EVENTS)).toEqual([ expect(await page.evaluate(() => window._EVENTS)).toEqual([
@ -700,7 +700,7 @@ it.describe('page screenshot animations', () => {
// Ensure CSS animation is finite. // Ensure CSS animation is finite.
expect(await div.evaluate(async el => Number.isFinite(el.getAnimations()[0].effect.getComputedTiming().endTime))).toBe(true); expect(await div.evaluate(async el => Number.isFinite(el.getAnimations()[0].effect.getComputedTiming().endTime))).toBe(true);
await Promise.all([ await Promise.all([
page.screenshot({ disableAnimations: true }), page.screenshot({ animations: 'disabled' }),
page.waitForEvent('console', msg => msg.text() === 'animationend'), page.waitForEvent('console', msg => msg.text() === 'animationend'),
]); ]);
expect(await page.evaluate(() => window._EVENTS)).toEqual([ expect(await page.evaluate(() => window._EVENTS)).toEqual([

View File

@ -75,7 +75,7 @@ test('should not fail when racing with navigation', async ({ runInlineTest }, te
page.goto('${infiniteAnimationURL}'), page.goto('${infiniteAnimationURL}'),
expect(page).toHaveScreenshot({ expect(page).toHaveScreenshot({
name: 'snapshot.png', name: 'snapshot.png',
disableAnimations: true, animations: "disabled",
clip: { x: 0, y: 0, width: 10, height: 10 }, 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 }) => { test('is a test', async ({ page }) => {
await page.goto('${infiniteAnimationURL}'); await page.goto('${infiniteAnimationURL}');
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
disableAnimations: true, animations: "disabled",
}); });
}); });
` `
@ -217,7 +217,7 @@ test('should compile with different option combinations', async ({ runTSC }) =>
threshold: 0.2, threshold: 0.2,
maxDiffPixels: 10, maxDiffPixels: 10,
maxDiffPixelRatio: 0.2, maxDiffPixelRatio: 0.2,
disableAnimations: true, animations: "disabled",
omitBackground: true, omitBackground: true,
timeout: 1000, timeout: 1000,
}); });