fix(screenshot): provide nice error message during navigation (#456)

This commit is contained in:
Dmitry Gozman 2020-01-10 17:25:28 -08:00 committed by GitHub
parent 02af0e5285
commit 63f16a9ef8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 18 deletions

View File

@ -32,6 +32,7 @@ import * as network from '../network';
import * as types from '../types';
import * as accessibility from '../accessibility';
import * as platform from '../platform';
import { kScreenshotDuringNavigationError } from '../screenshotter';
export class FFPage implements PageDelegate {
readonly rawMouse: RawMouseImpl;
@ -278,6 +279,10 @@ export class FFPage implements PageDelegate {
mimeType: ('image/' + format) as ('image/png' | 'image/jpeg'),
fullPage: options.fullPage,
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');
}

View File

@ -43,13 +43,22 @@ export class Screenshotter {
const viewport = this._page.viewport();
let viewportSize: types.Size | undefined;
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),
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()) {
const fullPageRect = await this._page.evaluate(() => ({
const fullPageRect = await this._page.evaluate(() => {
if (!document.body || !document.documentElement)
return null;
return {
width: Math.max(
document.body.scrollWidth, document.documentElement.scrollWidth,
document.body.offsetWidth, document.documentElement.offsetWidth,
@ -59,8 +68,11 @@ export class Screenshotter {
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
document.body.clientHeight, document.documentElement.clientHeight
)
}));
),
};
});
if (!fullPageRect)
throw new Error(kScreenshotDuringNavigationError);
overridenViewport = viewport ? { ...viewport, ...fullPageRect } : fullPageRect;
await this._page.setViewport(overridenViewport);
} else if (options.clip) {
@ -76,7 +88,7 @@ export class Screenshotter {
await this._page._delegate.resetViewport(viewportSize);
}
return result;
});
}).catch(rewriteError);
}
async screenshotElement(handle: dom.ElementHandle, options: types.ElementScreenshotOptions = {}): Promise<platform.BufferType> {
@ -115,7 +127,7 @@ export class Screenshotter {
await this._page.setViewport(viewport);
return result;
});
}).catch(rewriteError);
}
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);
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;
}

View 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>>

View File

@ -0,0 +1,5 @@
<script>
setTimeout(() => {
window.location.href = window.location.href.replace('loop2', 'loop1');
}, 1);
</script>

View File

@ -181,6 +181,18 @@ module.exports.describe = function({testRunner, expect, product, FFOX, CHROME, W
const screenshot = await page.screenshot();
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() {