feat(firefox): support isolated worlds (#507)

This commit is contained in:
Dmitry Gozman 2020-01-16 12:57:28 -08:00 committed by GitHub
parent 6b0b7500bd
commit 21510a5b06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 31 additions and 18 deletions

View File

@ -9,7 +9,7 @@
"main": "index.js",
"playwright": {
"chromium_revision": "724623",
"firefox_revision": "1012",
"firefox_revision": "1013",
"webkit_revision": "1092"
},
"scripts": {

View File

@ -38,7 +38,6 @@ import { CRBrowser } from './crBrowser';
import { BrowserContext } from '../browserContext';
import * as types from '../types';
import { ConsoleMessage } from '../console';
import * as accessibility from '../accessibility';
import * as platform from '../platform';
const UTILITY_WORLD_NAME = '__playwright_utility_world__';

View File

@ -16,7 +16,7 @@
*/
import * as frames from '../frames';
import { assert, helper, RegisteredListener, debugError } from '../helper';
import { helper, RegisteredListener, debugError } from '../helper';
import * as dom from '../dom';
import { FFSession } from './ffConnection';
import { FFExecutionContext } from './ffExecutionContext';
@ -30,10 +30,11 @@ import { BrowserContext } from '../browserContext';
import { getAccessibilityTree } from './ffAccessibility';
import * as network from '../network';
import * as types from '../types';
import * as accessibility from '../accessibility';
import * as platform from '../platform';
import { kScreenshotDuringNavigationError } from '../screenshotter';
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
export class FFPage implements PageDelegate {
readonly rawMouse: RawMouseImpl;
readonly rawKeyboard: RawKeyboardImpl;
@ -70,7 +71,7 @@ export class FFPage implements PageDelegate {
async _initialize() {
const promises: Promise<any>[] = [
this._session.send('Runtime.enable'),
this._session.send('Runtime.enable').then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)),
this._session.send('Network.enable'),
this._session.send('Page.enable'),
this._session.send('Page.setInterceptFileChooserDialog', { enabled: true })
@ -87,6 +88,13 @@ export class FFPage implements PageDelegate {
await Promise.all(promises);
}
async _ensureIsolatedWorld(name: string) {
await this._session.send('Page.addScriptToEvaluateOnNewDocument', {
script: '',
worldName: name,
});
}
_onExecutionContextCreated(payload: Protocol.Runtime.executionContextCreatedPayload) {
const {executionContextId, auxData} = payload;
const frame = this._page._frameManager.frame(auxData ? auxData.frameId : null);
@ -94,8 +102,10 @@ export class FFPage implements PageDelegate {
return;
const delegate = new FFExecutionContext(this._session, executionContextId);
const context = new dom.FrameExecutionContext(delegate, frame);
frame._contextCreated('main', context);
frame._contextCreated('utility', context);
if (auxData.name === UTILITY_WORLD_NAME)
frame._contextCreated('utility', context);
else if (!auxData.name)
frame._contextCreated('main', context);
this._contextIdToContext.set(executionContextId, context);
}
@ -351,8 +361,12 @@ export class FFPage implements PageDelegate {
}
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {
assert(false, 'Multiple isolated worlds are not implemented');
return handle;
const result = await this._session.send('Page.adoptNode', {
frameId: handle._context.frame._id,
objectId: toRemoteObject(handle).objectId!,
executionContextId: (to._delegate as FFExecutionContext)._executionContextId
});
return to._createHandle(result.remoteObject) as dom.ElementHandle<T>;
}
async getAccessibilityTree(needle?: dom.ElementHandle) {

View File

@ -37,7 +37,7 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
await page.click('circle');
expect(await page.evaluate(() => window.__CLICKED)).toBe(42);
});
it.skip(FFOX)('should click the button if window.Node is removed', async({page, server}) => {
it('should click the button if window.Node is removed', async({page, server}) => {
await page.goto(server.PREFIX + '/input/button.html');
await page.evaluate(() => delete window.Node);
await page.click('button');

View File

@ -182,7 +182,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
await button.click();
expect(await page.evaluate(() => result)).toBe('Clicked');
});
it.skip(FFOX)('should work with Node removed', async({page, server}) => {
it('should work with Node removed', async({page, server}) => {
await page.goto(server.PREFIX + '/input/button.html');
await page.evaluate(() => delete window['Node']);
const button = await page.$('button');
@ -239,7 +239,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
await button.hover();
expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-6');
});
it.skip(FFOX)('should work when Node is removed', async({page, server}) => {
it('should work when Node is removed', async({page, server}) => {
await page.goto(server.PREFIX + '/input/scrollable.html');
await page.evaluate(() => delete window['Node']);
const button = await page.$('#button-6');
@ -257,7 +257,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
expect(Math.round(ratio * 10)).toBe(10 - i);
}
});
it.skip(FFOX)('should work when Node is removed', async({page, server}) => {
it('should work when Node is removed', async({page, server}) => {
await page.goto(server.PREFIX + '/offscreenbuttons.html');
await page.evaluate(() => delete window['Node']);
for (let i = 0; i < 11; ++i) {
@ -290,7 +290,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
await handle.fill('some value');
expect(await page.evaluate(() => result)).toBe('some value');
});
it.skip(FFOX)('should fill input when Node is removed', async({page, server}) => {
it('should fill input when Node is removed', async({page, server}) => {
await page.goto(server.PREFIX + '/input/textarea.html');
await page.evaluate(() => delete window['Node']);
const handle = await page.$('input');

View File

@ -98,7 +98,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT,
await page.hover('#button-91');
expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-91');
});
it.skip(FFOX)('should trigger hover state with removed window.Node', async({page, server}) => {
it('should trigger hover state with removed window.Node', async({page, server}) => {
await page.goto(server.PREFIX + '/input/scrollable.html');
await page.evaluate(() => delete window.Node);
await page.hover('#button-6');

View File

@ -960,7 +960,7 @@ module.exports.describe = function({testRunner, expect, headless, playwright, FF
expect(error.message).toContain('Indices must be numbers');
});
// @see https://github.com/GoogleChrome/puppeteer/issues/3327
it.skip(FFOX)('should work when re-defining top-level Event class', async({page, server}) => {
it('should work when re-defining top-level Event class', async({page, server}) => {
await page.goto(server.PREFIX + '/input/select.html');
await page.evaluate(() => window.Event = null);
await page.select('select', 'blue');

View File

@ -246,7 +246,7 @@ module.exports.describe = function({testRunner, expect, product, playwright, FFO
await frame.waitForSelector('div');
});
it.skip(FFOX)('should work with removed MutationObserver', async({page, server}) => {
it('should work with removed MutationObserver', async({page, server}) => {
await page.evaluate(() => delete window.MutationObserver);
const [handle] = await Promise.all([
page.waitForSelector('.zombo'),
@ -318,7 +318,7 @@ module.exports.describe = function({testRunner, expect, product, playwright, FFO
await waitForSelector;
expect(boxFound).toBe(true);
});
it.skip(FFOX)('should wait for visible', async({page, server}) => {
it('should wait for visible', async({page, server}) => {
let divFound = false;
const waitForSelector = page.waitForSelector('div').then(() => divFound = true);
await page.setContent(`<div style='display: none; visibility: hidden;'>1</div>`);