mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(screenshot): provide nice error message during navigation (#456)
This commit is contained in:
parent
02af0e5285
commit
63f16a9ef8
@ -32,6 +32,7 @@ import * as network from '../network';
|
|||||||
import * as types from '../types';
|
import * as types from '../types';
|
||||||
import * as accessibility from '../accessibility';
|
import * as accessibility from '../accessibility';
|
||||||
import * as platform from '../platform';
|
import * as platform from '../platform';
|
||||||
|
import { kScreenshotDuringNavigationError } from '../screenshotter';
|
||||||
|
|
||||||
export class FFPage implements PageDelegate {
|
export class FFPage implements PageDelegate {
|
||||||
readonly rawMouse: RawMouseImpl;
|
readonly rawMouse: RawMouseImpl;
|
||||||
@ -278,6 +279,10 @@ export class FFPage implements PageDelegate {
|
|||||||
mimeType: ('image/' + format) as ('image/png' | 'image/jpeg'),
|
mimeType: ('image/' + format) as ('image/png' | 'image/jpeg'),
|
||||||
fullPage: options.fullPage,
|
fullPage: options.fullPage,
|
||||||
clip: options.clip,
|
clip: options.clip,
|
||||||
|
}).catch(e => {
|
||||||
|
if (e instanceof Error && e.message.includes('document.documentElement is null'))
|
||||||
|
e.message = kScreenshotDuringNavigationError;
|
||||||
|
throw e;
|
||||||
});
|
});
|
||||||
return platform.Buffer.from(data, 'base64');
|
return platform.Buffer.from(data, 'base64');
|
||||||
}
|
}
|
||||||
|
@ -43,13 +43,22 @@ export class Screenshotter {
|
|||||||
const viewport = this._page.viewport();
|
const viewport = this._page.viewport();
|
||||||
let viewportSize: types.Size | undefined;
|
let viewportSize: types.Size | undefined;
|
||||||
if (!viewport) {
|
if (!viewport) {
|
||||||
viewportSize = await this._page.evaluate(() => ({
|
viewportSize = await this._page.evaluate(() => {
|
||||||
|
if (!document.body || !document.documentElement)
|
||||||
|
return null;
|
||||||
|
return {
|
||||||
width: Math.max(document.body.offsetWidth, document.documentElement.offsetWidth),
|
width: Math.max(document.body.offsetWidth, document.documentElement.offsetWidth),
|
||||||
height: Math.max(document.body.offsetHeight, document.documentElement.offsetHeight)
|
height: Math.max(document.body.offsetHeight, document.documentElement.offsetHeight),
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
|
if (!viewportSize)
|
||||||
|
throw new Error(kScreenshotDuringNavigationError);
|
||||||
}
|
}
|
||||||
if (options.fullPage && !this._page._delegate.canScreenshotOutsideViewport()) {
|
if (options.fullPage && !this._page._delegate.canScreenshotOutsideViewport()) {
|
||||||
const fullPageRect = await this._page.evaluate(() => ({
|
const fullPageRect = await this._page.evaluate(() => {
|
||||||
|
if (!document.body || !document.documentElement)
|
||||||
|
return null;
|
||||||
|
return {
|
||||||
width: Math.max(
|
width: Math.max(
|
||||||
document.body.scrollWidth, document.documentElement.scrollWidth,
|
document.body.scrollWidth, document.documentElement.scrollWidth,
|
||||||
document.body.offsetWidth, document.documentElement.offsetWidth,
|
document.body.offsetWidth, document.documentElement.offsetWidth,
|
||||||
@ -59,8 +68,11 @@ export class Screenshotter {
|
|||||||
document.body.scrollHeight, document.documentElement.scrollHeight,
|
document.body.scrollHeight, document.documentElement.scrollHeight,
|
||||||
document.body.offsetHeight, document.documentElement.offsetHeight,
|
document.body.offsetHeight, document.documentElement.offsetHeight,
|
||||||
document.body.clientHeight, document.documentElement.clientHeight
|
document.body.clientHeight, document.documentElement.clientHeight
|
||||||
)
|
),
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
|
if (!fullPageRect)
|
||||||
|
throw new Error(kScreenshotDuringNavigationError);
|
||||||
overridenViewport = viewport ? { ...viewport, ...fullPageRect } : fullPageRect;
|
overridenViewport = viewport ? { ...viewport, ...fullPageRect } : fullPageRect;
|
||||||
await this._page.setViewport(overridenViewport);
|
await this._page.setViewport(overridenViewport);
|
||||||
} else if (options.clip) {
|
} else if (options.clip) {
|
||||||
@ -76,7 +88,7 @@ export class Screenshotter {
|
|||||||
await this._page._delegate.resetViewport(viewportSize);
|
await this._page._delegate.resetViewport(viewportSize);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
}).catch(rewriteError);
|
||||||
}
|
}
|
||||||
|
|
||||||
async screenshotElement(handle: dom.ElementHandle, options: types.ElementScreenshotOptions = {}): Promise<platform.BufferType> {
|
async screenshotElement(handle: dom.ElementHandle, options: types.ElementScreenshotOptions = {}): Promise<platform.BufferType> {
|
||||||
@ -115,7 +127,7 @@ export class Screenshotter {
|
|||||||
await this._page.setViewport(viewport);
|
await this._page.setViewport(viewport);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
}).catch(rewriteError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _screenshot(format: 'png' | 'jpeg', options: types.ScreenshotOptions, viewport: types.Viewport): Promise<platform.BufferType> {
|
private async _screenshot(format: 'png' | 'jpeg', options: types.ScreenshotOptions, viewport: types.Viewport): Promise<platform.BufferType> {
|
||||||
@ -201,3 +213,10 @@ function enclosingIntRect(rect: types.Rect): types.Rect {
|
|||||||
const y2 = Math.ceil(rect.y + rect.height - 1e-3);
|
const y2 = Math.ceil(rect.y + rect.height - 1e-3);
|
||||||
return { x, y, width: x2 - x, height: y2 - y };
|
return { x, y, width: x2 - x, height: y2 - y };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const kScreenshotDuringNavigationError = 'Cannot take a screenshot while page is navigating';
|
||||||
|
function rewriteError(e: any) {
|
||||||
|
if (typeof e === 'object' && e instanceof Error && e.message.includes('Execution context was destroyed'))
|
||||||
|
e.message = kScreenshotDuringNavigationError;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
9
test/assets/redirectloop1.html
Normal file
9
test/assets/redirectloop1.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
setTimeout(() => {
|
||||||
|
const iter = window.localStorage.iter || '';
|
||||||
|
window.localStorage.iter = iter + 'a';
|
||||||
|
if (iter.length === 10)
|
||||||
|
return;
|
||||||
|
window.location.href = window.location.href.replace('loop1', 'loop2');
|
||||||
|
}, 1);
|
||||||
|
</script>>
|
5
test/assets/redirectloop2.html
Normal file
5
test/assets/redirectloop2.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = window.location.href.replace('loop2', 'loop1');
|
||||||
|
}, 1);
|
||||||
|
</script>
|
@ -181,6 +181,18 @@ module.exports.describe = function({testRunner, expect, product, FFOX, CHROME, W
|
|||||||
const screenshot = await page.screenshot();
|
const screenshot = await page.screenshot();
|
||||||
expect(screenshot).toBeGolden('screenshot-webgl.png');
|
expect(screenshot).toBeGolden('screenshot-webgl.png');
|
||||||
});
|
});
|
||||||
|
it('should work while navigating', async({page, server}) => {
|
||||||
|
await page.setViewport({width: 500, height: 500});
|
||||||
|
await page.goto(server.PREFIX + '/redirectloop1.html');
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const screenshot = await page.screenshot({ fullPage: true }).catch(e => {
|
||||||
|
if (e.message.includes('Cannot take a screenshot while page is navigating'))
|
||||||
|
return Buffer.from('');
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
expect(screenshot).toBeInstanceOf(Buffer);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ElementHandle.screenshot', function() {
|
describe('ElementHandle.screenshot', function() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user