fix: emulate if captureBeyondViewport is false (#11525)

This commit is contained in:
jrandolf 2023-12-13 00:12:24 +01:00 committed by GitHub
parent 026172761b
commit b6d1163f7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 162 additions and 85 deletions

View File

@ -16,7 +16,7 @@ export interface Viewport
| ----------------- | --------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| deviceScaleFactor | <code>optional</code> | number | Specify device scale factor. See [devicePixelRatio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) for more info. | <code>1</code> |
| hasTouch | <code>optional</code> | boolean | Specify if the viewport supports touch events. | <code>false</code> |
| height | | number | The page height in pixels. | |
| height | | number | The page height in CSS pixels. | |
| isLandscape | <code>optional</code> | boolean | Specifies if the viewport is in landscape mode. | <code>false</code> |
| isMobile | <code>optional</code> | boolean | Whether the <code>meta viewport</code> tag is taken into account. | <code>false</code> |
| width | | number | The page width in pixels. | |
| width | | number | The page width in CSS pixels. | |

View File

@ -85,6 +85,7 @@ import type {ScreenRecorder} from '../node/ScreenRecorder.js';
import {assert} from '../util/assert.js';
import {guarded} from '../util/decorators.js';
import {
AsyncDisposableStack,
asyncDisposeSymbol,
DisposableStack,
disposeSymbol,
@ -2450,19 +2451,48 @@ export abstract class Page extends EventEmitter<PageEvents> {
setDefaultScreenshotOptions(options);
options.clip =
options.clip && roundRectangle(normalizeRectangle(options.clip));
if (options.fullPage) {
await using stack = new AsyncDisposableStack();
if (options.clip) {
throw new Error("'clip' and 'fullPage' are exclusive");
if (options.fullPage) {
throw new Error("'clip' and 'fullPage' are mutually exclusive");
}
} else if (
!options.clip &&
userOptions.captureBeyondViewport === undefined
) {
options.clip = roundRectangle(normalizeRectangle(options.clip));
} else {
if (options.fullPage) {
// If `captureBeyondViewport` is `false`, then we set the viewport to
// capture the full page. Note this may be affected by on-page CSS and
// JavaScript.
if (!options.captureBeyondViewport) {
const scrollDimensions = await this.mainFrame()
.isolatedRealm()
.evaluate(() => {
const element = document.documentElement;
return {
width: element.scrollWidth,
height: element.scrollHeight,
};
});
const viewport = this.viewport();
await this.setViewport({
...viewport,
...scrollDimensions,
});
stack.defer(async () => {
if (viewport) {
await this.setViewport(viewport).catch(debugError);
} else {
await this.setViewport({
width: 0,
height: 0,
}).catch(debugError);
}
});
}
} else {
options.captureBeyondViewport = false;
}
}
const data = await this._screenshot(options);
if (options.encoding === 'base64') {

View File

@ -666,12 +666,20 @@ export class BidiPage extends Page {
if (options.fromSurface !== undefined && !options.fromSurface) {
throw new UnsupportedOperation(`BiDi does not support 'fromSurface'.`);
}
if (clip !== undefined && clip.scale !== undefined && clip.scale !== 1) {
throw new UnsupportedOperation(
`BiDi does not support 'scale' in 'clip'.`
);
}
let box: BoundingBox | undefined;
if (clip) {
if (captureBeyondViewport) {
box = clip;
} else {
// The clip is always with respect to the document coordinates, so we
// need to convert this to viewport coordinates when we aren't capturing
// beyond the viewport.
const [pageLeft, pageTop] = await this.evaluate(() => {
if (!window.visualViewport) {
throw new Error('window.visualViewport is not supported.');
@ -689,12 +697,6 @@ export class BidiPage extends Page {
}
}
if (clip !== undefined && clip.scale !== undefined && clip.scale !== 1) {
throw new UnsupportedOperation(
`BiDi does not support 'scale' in 'clip'.`
);
}
const {
result: {data},
} = await this.#connection.send('browsingContext.captureScreenshot', {

View File

@ -1122,10 +1122,7 @@ export class CdpPage extends Page {
format: type,
...(optimizeForSpeed ? {optimizeForSpeed} : {}),
...(quality !== undefined ? {quality: Math.round(quality)} : {}),
clip: clip && {
...clip,
scale: clip.scale ?? 1,
},
...(clip ? {clip: {...clip, scale: clip.scale ?? 1}} : {}),
...(!fromSurface ? {fromSurface} : {}),
captureBeyondViewport,
}

View File

@ -19,11 +19,17 @@
*/
export interface Viewport {
/**
* The page width in pixels.
* The page width in CSS pixels.
*
* @remarks
* Setting this value to `0` will reset this value to the system default.
*/
width: number;
/**
* The page height in pixels.
* The page height in CSS pixels.
*
* @remarks
* Setting this value to `0` will reset this value to the system default.
*/
height: number;
/**
@ -31,7 +37,7 @@ export interface Viewport {
* See {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio | devicePixelRatio} for more info.
*
* @remarks
* Setting this value to `0` will set the deviceScaleFactor to the system default.
* Setting this value to `0` will reset this value to the system default.
*
* @defaultValue `1`
*/

View File

@ -1157,24 +1157,12 @@
"parameters": ["firefox"],
"expectations": ["PASS"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should clip clip bigger than the viewport without \"captureBeyondViewport\"",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox"],
"expectations": ["FAIL", "PASS"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should get screenshot bigger than the viewport",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should use scale for clip",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[stacktrace.spec] Stack trace *",
"platforms": ["darwin", "linux", "win32"],
@ -3371,24 +3359,12 @@
"parameters": ["cdp", "chrome"],
"expectations": ["FAIL", "PASS"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element",
"platforms": ["darwin", "linux", "win32"],
@ -3409,6 +3385,7 @@
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should return base64",
"comment": "Bisected to https://chromium.googlesource.com/chromium/src/+log/b8b95f5715b4bd2348e537b740048e4b6aa281b1..8026f46b0e73174f33834a26748107d1089a83bf",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "chrome"],
"expectations": ["FAIL", "PASS"]
@ -3421,12 +3398,20 @@
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots",
"comment": "Bisected to https://chromium.googlesource.com/chromium/src/+log/b8b95f5715b4bd2348e537b740048e4b6aa281b1..8026f46b0e73174f33834a26748107d1089a83bf",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"parameters": ["cdp", "chrome"],
"expectations": ["FAIL", "PASS"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots without captureBeyondViewport",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots",
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots without captureBeyondViewport",
"comment": "Bisected to https://chromium.googlesource.com/chromium/src/+log/b8b95f5715b4bd2348e537b740048e4b6aa281b1..8026f46b0e73174f33834a26748107d1089a83bf",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "chrome"],
"expectations": ["FAIL", "PASS"]
@ -3439,6 +3424,7 @@
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should work",
"comment": "Bisected to https://chromium.googlesource.com/chromium/src/+log/b8b95f5715b4bd2348e537b740048e4b6aa281b1..8026f46b0e73174f33834a26748107d1089a83bf",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "chrome"],
"expectations": ["FAIL", "PASS"]
@ -3762,15 +3748,39 @@
"expectations": ["FAIL", "PASS"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Cdp should work in \"fromSurface: false\" mode",
"platforms": ["darwin", "win32"],
"parameters": ["cdp", "chrome", "headless"],
"testIdPattern": "[screenshot.spec] Screenshots Cdp should use scale for clip",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox", "headless"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Cdp should work in \"fromSurface: false\" mode",
"platforms": ["darwin"],
"parameters": ["cdp", "chrome", "new-headless"],
"testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox", "headful"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox", "headless"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox", "headful"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox", "headless"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should clip clip bigger than the viewport without \"captureBeyondViewport\"",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox", "headless"],
"expectations": ["FAIL"]
},
{
@ -3786,7 +3796,19 @@
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should use scale for clip",
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox", "headful"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox", "headless"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots without captureBeyondViewport",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox", "headless"],
"expectations": ["FAIL"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -18,7 +18,12 @@ import assert from 'assert';
import expect from 'expect';
import {getTestState, launch, setupTestBrowserHooks} from './mocha-utils.js';
import {
getTestState,
isHeadless,
launch,
setupTestBrowserHooks,
} from './mocha-utils.js';
describe('Screenshots', function () {
setupTestBrowserHooks();
@ -47,22 +52,6 @@ describe('Screenshots', function () {
});
expect(screenshot).toBeGolden('screenshot-clip-rect.png');
});
it('should use scale for clip', async () => {
const {page, server} = await getTestState();
await page.setViewport({width: 500, height: 500});
await page.goto(server.PREFIX + '/grid.html');
const screenshot = await page.screenshot({
clip: {
x: 50,
y: 100,
width: 150,
height: 100,
scale: 2,
},
});
expect(screenshot).toBeGolden('screenshot-clip-rect-scale2.png');
});
it('should get screenshot bigger than the viewport', async () => {
const {page, server} = await getTestState();
await page.setViewport({width: 50, height: 50});
@ -123,6 +112,18 @@ describe('Screenshots', function () {
});
expect(screenshot).toBeGolden('screenshot-grid-fullpage.png');
});
it('should take fullPage screenshots without captureBeyondViewport', async () => {
const {page, server} = await getTestState();
await page.setViewport({width: 500, height: 500});
await page.goto(server.PREFIX + '/grid.html');
const screenshot = await page.screenshot({
fullPage: true,
captureBeyondViewport: false,
});
expect(screenshot).toBeGolden('screenshot-grid-fullpage-2.png');
expect(page.viewport()).toMatchObject({width: 500, height: 500});
});
it('should run in parallel in multiple pages', async () => {
const {server, context} = await getTestState();
@ -371,6 +372,22 @@ describe('Screenshots', function () {
});
describe('Cdp', () => {
it('should use scale for clip', async () => {
const {page, server} = await getTestState();
await page.setViewport({width: 500, height: 500});
await page.goto(server.PREFIX + '/grid.html');
const screenshot = await page.screenshot({
clip: {
x: 50,
y: 100,
width: 150,
height: 100,
scale: 2,
},
});
expect(screenshot).toBeGolden('screenshot-clip-rect-scale2.png');
});
it('should allow transparency', async () => {
const {page, server} = await getTestState();
@ -390,7 +407,9 @@ describe('Screenshots', function () {
});
expect(screenshot).toBeGolden('white.jpg');
});
it('should work in "fromSurface: false" mode', async () => {
(!isHeadless ? it : it.skip)(
'should work in "fromSurface: false" mode',
async () => {
const {page, server} = await getTestState();
await page.setViewport({width: 500, height: 500});
@ -399,6 +418,7 @@ describe('Screenshots', function () {
fromSurface: false,
});
expect(screenshot).toBeDefined(); // toBeGolden('screenshot-fromsurface-false.png');
});
}
);
});
});