From 76ace0fc09d92fedf2137cebd9a8a1427daa9911 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Mon, 11 Dec 2023 18:20:24 -0800 Subject: [PATCH] chore: workaround webkit screenshot animation issue (#28582) --- .../playwright-core/src/server/chromium/crPage.ts | 4 ++++ .../playwright-core/src/server/firefox/ffPage.ts | 4 ++++ packages/playwright-core/src/server/page.ts | 2 ++ .../playwright-core/src/server/screenshotter.ts | 14 ++++++++++++-- .../playwright-core/src/server/webkit/wkPage.ts | 4 ++++ tests/page/page-screenshot.spec.ts | 2 -- 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/playwright-core/src/server/chromium/crPage.ts b/packages/playwright-core/src/server/chromium/crPage.ts index 2aa98d4f7f..1dd5237368 100644 --- a/packages/playwright-core/src/server/chromium/crPage.ts +++ b/packages/playwright-core/src/server/chromium/crPage.ts @@ -382,6 +382,10 @@ export class CRPage implements PageDelegate { throw new Error('Frame has been detached.'); return parentSession._adoptBackendNodeId(backendNodeId, await parent._mainContext()); } + + shouldToggleStyleSheetToSyncAnimations(): boolean { + return false; + } } class FrameSession { diff --git a/packages/playwright-core/src/server/firefox/ffPage.ts b/packages/playwright-core/src/server/firefox/ffPage.ts index 389c24ccfd..8b3876036c 100644 --- a/packages/playwright-core/src/server/firefox/ffPage.ts +++ b/packages/playwright-core/src/server/firefox/ffPage.ts @@ -594,6 +594,10 @@ export class FFPage implements PageDelegate { throw new Error('Frame has been detached.'); return context.createHandle(result.remoteObject) as dom.ElementHandle; } + + shouldToggleStyleSheetToSyncAnimations(): boolean { + return false; + } } function webSocketId(frameId: string, wsid: string): string { diff --git a/packages/playwright-core/src/server/page.ts b/packages/playwright-core/src/server/page.ts index da84d32385..a00d09cfe3 100644 --- a/packages/playwright-core/src/server/page.ts +++ b/packages/playwright-core/src/server/page.ts @@ -97,6 +97,8 @@ export interface PageDelegate { readonly cspErrorsAsynchronousForInlineScipts?: boolean; // Work around for mouse position in Firefox. resetForReuse(): Promise; + // WebKit hack. + shouldToggleStyleSheetToSyncAnimations(): boolean; } type EmulatedSize = { screen: types.Size, viewport: types.Size }; diff --git a/packages/playwright-core/src/server/screenshotter.ts b/packages/playwright-core/src/server/screenshotter.ts index 1ca0542198..696d929692 100644 --- a/packages/playwright-core/src/server/screenshotter.ts +++ b/packages/playwright-core/src/server/screenshotter.ts @@ -46,7 +46,16 @@ export type ScreenshotOptions = { style?: string; }; -function inPagePrepareForScreenshots(screenshotStyle: string, hideCaret: boolean, disableAnimations: boolean) { +function inPagePrepareForScreenshots(screenshotStyle: string, hideCaret: boolean, disableAnimations: boolean, syncAnimations: boolean) { + // In WebKit, sync the animations. + if (syncAnimations) { + const style = document.createElement('style'); + style.textContent = 'body {}'; + document.head.appendChild(style); + document.documentElement.getBoundingClientRect(); + style.remove(); + } + if (!screenshotStyle && !hideCaret && !disableAnimations) return; @@ -251,8 +260,9 @@ export class Screenshotter { async _preparePageForScreenshot(progress: Progress, screenshotStyle: string | undefined, hideCaret: boolean, disableAnimations: boolean) { if (disableAnimations) progress.log(' disabled all CSS animations'); + const syncAnimations = this._page._delegate.shouldToggleStyleSheetToSyncAnimations(); await Promise.all(this._page.frames().map(async frame => { - await frame.nonStallingEvaluateInExistingContext('(' + inPagePrepareForScreenshots.toString() + `)(${JSON.stringify(screenshotStyle)}, ${hideCaret}, ${disableAnimations})`, false, 'utility').catch(() => {}); + await frame.nonStallingEvaluateInExistingContext('(' + inPagePrepareForScreenshots.toString() + `)(${JSON.stringify(screenshotStyle)}, ${hideCaret}, ${disableAnimations}, ${syncAnimations})`, false, 'utility').catch(() => {}); })); if (!process.env.PW_TEST_SCREENSHOT_NO_FONTS_READY) { progress.log('waiting for fonts to load...'); diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index 6c219bf437..24d6ef63f6 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -1184,6 +1184,10 @@ export class WKPage implements PageDelegate { async _clearPermissions() { await this._pageProxySession.send('Emulation.resetPermissions', {}); } + + shouldToggleStyleSheetToSyncAnimations(): boolean { + return true; + } } /** diff --git a/tests/page/page-screenshot.spec.ts b/tests/page/page-screenshot.spec.ts index aaf051332e..fd7b8e91a4 100644 --- a/tests/page/page-screenshot.spec.ts +++ b/tests/page/page-screenshot.spec.ts @@ -691,7 +691,6 @@ it.describe('page screenshot animations', () => { }); it('should fire transitionend for finite transitions', async ({ page, server, browserName, platform }) => { - it.fixme(browserName === 'webkit' && platform === 'linux'); await page.goto(server.PREFIX + '/css-transition.html'); const div = page.locator('div'); await div.evaluate(el => { @@ -718,7 +717,6 @@ it.describe('page screenshot animations', () => { }); it('should capture screenshots after layoutchanges in transitionend event', async ({ page, server, browserName, platform }) => { - it.fixme(browserName === 'webkit' && platform === 'linux'); await page.goto(server.PREFIX + '/css-transition.html'); const div = page.locator('div'); await div.evaluate(el => {