From 357e1759640a56fef1bacfa8bfe4405e79d46356 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Wed, 11 Dec 2019 11:26:34 -0800 Subject: [PATCH] fix(webkit): fullPage screenshot w/o viewport (#210) --- src/chromium/Screenshotter.ts | 4 ++++ src/firefox/Screenshotter.ts | 4 ++++ src/screenshotter.ts | 22 +++++++++++++++++----- src/types.ts | 3 ++- src/webkit/Screenshotter.ts | 4 ++++ test/launcher.spec.js | 5 +++++ 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/chromium/Screenshotter.ts b/src/chromium/Screenshotter.ts index c5203472bd..c9ae763493 100644 --- a/src/chromium/Screenshotter.ts +++ b/src/chromium/Screenshotter.ts @@ -37,4 +37,8 @@ export class CRScreenshotDelegate implements ScreenshotterDelegate { const result = await this._session.send('Page.captureScreenshot', { format, quality: options.quality, clip }); return Buffer.from(result.data, 'base64'); } + + async resetViewport(): Promise { + await this._session.send('Emulation.setDeviceMetricsOverride', { mobile: false, width: 0, height: 0, deviceScaleFactor: 0 }); + } } diff --git a/src/firefox/Screenshotter.ts b/src/firefox/Screenshotter.ts index f8feb96823..863ebab40f 100644 --- a/src/firefox/Screenshotter.ts +++ b/src/firefox/Screenshotter.ts @@ -39,4 +39,8 @@ export class FFScreenshotDelegate implements ScreenshotterDelegate { }); return Buffer.from(data, 'base64'); } + + async resetViewport(): Promise { + await this._session.send('Page.setViewport', { viewport: null }); + } } diff --git a/src/screenshotter.ts b/src/screenshotter.ts index fc2b3a1ee9..be3f330c7a 100644 --- a/src/screenshotter.ts +++ b/src/screenshotter.ts @@ -34,6 +34,7 @@ export interface ScreenshotterDelegate { canCaptureOutsideViewport(): boolean; setBackgroundColor(color?: { r: number; g: number; b: number; a: number; }): Promise; screenshot(format: string, options: types.ScreenshotOptions, viewport: types.Viewport): Promise; + resetViewport(oldSize: types.Size): Promise; } export class Screenshotter { @@ -57,8 +58,15 @@ export class Screenshotter { return this._queue.postTask(async () => { let overridenViewport: types.Viewport | undefined; const viewport = this._page.viewport(); - if (viewport && options.fullPage && !this._delegate.canCaptureOutsideViewport()) { - const fullPage = await this._page.evaluate(() => ({ + let viewportSize: types.Size | undefined; + if (!viewport) { + viewportSize = await this._page.evaluate(() => ({ + width: Math.max(document.body.offsetWidth, document.documentElement.offsetWidth), + height: Math.max(document.body.offsetHeight, document.documentElement.offsetHeight) + })); + } + if (options.fullPage && !this._delegate.canCaptureOutsideViewport()) { + const fullPageRect = await this._page.evaluate(() => ({ width: Math.max( document.body.scrollWidth, document.documentElement.scrollWidth, document.body.offsetWidth, document.documentElement.offsetWidth, @@ -70,7 +78,7 @@ export class Screenshotter { document.body.clientHeight, document.documentElement.clientHeight ) })); - overridenViewport = { ...viewport, ...fullPage }; + overridenViewport = viewport ? { ...viewport, ...fullPageRect } : fullPageRect; await this._page.setViewport(overridenViewport); } else if (options.clip) { options.clip = trimClipToViewport(viewport, options.clip); @@ -78,8 +86,12 @@ export class Screenshotter { const result = await this._screenshot(format, options, overridenViewport || viewport); - if (overridenViewport) - await this._page.setViewport(viewport); + if (overridenViewport) { + if (viewport) + await this._page.setViewport(viewport); + else + await this._delegate.resetViewport(viewportSize); + } return result; }); } diff --git a/src/types.ts b/src/types.ts index 14774a345e..0122dca471 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,8 +19,9 @@ export type $$Eval = export type EvaluateOn = (pageFunction: PageFunctionOn, ...args: Boxed) => Promise; export type EvaluateHandleOn = (pageFunction: PageFunctionOn, ...args: Boxed) => Promise>; -export type Rect = { x: number, y: number, width: number, height: number }; +export type Size = { width: number, height: number }; export type Point = { x: number, y: number }; +export type Rect = Size & Point; export type Quad = [ Point, Point, Point, Point ]; export type TimeoutOptions = { timeout?: number }; diff --git a/src/webkit/Screenshotter.ts b/src/webkit/Screenshotter.ts index 238c3f4c51..30805be92e 100644 --- a/src/webkit/Screenshotter.ts +++ b/src/webkit/Screenshotter.ts @@ -37,4 +37,8 @@ export class WKScreenshotDelegate implements ScreenshotterDelegate { buffer = jpeg.encode(PNG.sync.read(buffer)).data; return buffer; } + + async resetViewport(oldSize: types.Size): Promise { + await this._session.send('Emulation.setDeviceMetricsOverride', { ...oldSize, deviceScaleFactor: 0 }); + } } diff --git a/test/launcher.spec.js b/test/launcher.spec.js index 477933a08c..56b56c3d2e 100644 --- a/test/launcher.spec.js +++ b/test/launcher.spec.js @@ -74,10 +74,15 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p const browser = await playwright.launch(options); const page = await browser.newPage(); await page.goto(server.PREFIX + '/grid.html'); + const sizeBefore = await page.evaluate(() => ({ width: document.body.offsetWidth, height: document.body.offsetHeight })); const screenshot = await page.screenshot({ fullPage: true }); expect(screenshot).toBeInstanceOf(Buffer); + + const sizeAfter = await page.evaluate(() => ({ width: document.body.offsetWidth, height: document.body.offsetHeight })); + expect(sizeBefore.width).toBe(sizeAfter.width); + expect(sizeBefore.height).toBe(sizeAfter.height); await browser.close(); }); it('should have default URL when launching browser', async function() {