fix: make sure screenshots work when main page context is tampered (#20615)

This patch has 2 fixes:
- screenshot code was accidentally using main page context to fetch
  page layout metrics instead of a utility context
- Avoid usage of `self.eval` inside utility context since it escapes
Firefox sandbox. This turns out to be an upstream bug:
https://bugzilla.mozilla.org/show_bug.cgi?id=1814898

Fixes #20434
This commit is contained in:
Andrey Lushnikov 2023-02-03 10:01:23 -08:00 committed by GitHub
parent f45f20a8c9
commit 9c6a1a6ff0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 2 deletions

View File

@ -1474,11 +1474,14 @@ export class Frame extends SdkObject {
expression = js.normalizeEvaluationExpression(expression, isFunction);
return controller.run(async progress => {
return this.retryWithProgressAndTimeouts(progress, [100], async () => {
const context = await this._mainContext();
const context = world === 'main' ? await this._mainContext() : await this._utilityContext();
const injectedScript = await context.injectedScript();
const handle = await injectedScript.evaluateHandle((injected, { expression, isFunction, polling, arg }) => {
const predicate = (): R => {
let result = self.eval(expression);
// NOTE: make sure to use `globalThis.eval` instead of `self.eval` due to a bug with sandbox isolation
// in firefox.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1814898
let result = globalThis.eval(expression);
if (isFunction === true) {
result = result(arg);
} else if (isFunction === false) {

View File

@ -33,6 +33,18 @@ it.describe('element screenshot', () => {
expect(screenshot).toMatchSnapshot('screenshot-element-bounding-box.png');
});
it('should work when main world busts JSON.stringify', async ({ page, server }) => {
await page.setViewportSize({ width: 500, height: 500 });
await page.goto(server.PREFIX + '/grid.html');
await page.evaluate(() => {
window.scrollBy(50, 100);
JSON.stringify = () => undefined;
});
const elementHandle = await page.$('.box:nth-of-type(3)');
const screenshot = await elementHandle.screenshot();
expect(screenshot).toMatchSnapshot('screenshot-element-bounding-box.png');
});
it('should take into account padding and border', async ({ page }) => {
await page.setViewportSize({ width: 500, height: 500 });
await page.setContent(`