feat(webkit): use webkit worlds (#194)

This commit is contained in:
Pavel Feldman 2019-12-09 23:24:12 -08:00 committed by Andrey Lushnikov
parent 5ab6514633
commit 44d6f608ef
6 changed files with 32 additions and 17 deletions

View file

@ -10,7 +10,7 @@
"playwright": {
"chromium_revision": "719491",
"firefox_revision": "1004",
"webkit_revision": "1022"
"webkit_revision": "1023"
},
"scripts": {
"unit": "node test/test.js",

View file

@ -31,7 +31,6 @@ import { Protocol } from './protocol';
import { Events as CommonEvents } from '../events';
import { toConsoleMessageLocation, exceptionToError, releaseObject } from './protocolHelper';
import * as dialog from '../dialog';
import * as console from '../console';
import { PageDelegate } from '../page';
import { RawMouseImpl, RawKeyboardImpl } from './Input';
import { CRScreenshotDelegate } from './Screenshotter';
@ -45,6 +44,7 @@ import { Browser } from './Browser';
import { BrowserContext } from './BrowserContext';
import * as types from '../types';
import * as input from '../input';
import { ConsoleMessage } from '../console';
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
@ -331,7 +331,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
await this._client.send('Page.addScriptToEvaluateOnNewDocument', {
source: `//# sourceURL=${EVALUATION_SCRIPT_URL}`,
worldName: name,
}),
});
await Promise.all(this.frames().map(frame => this._client.send('Page.createIsolatedWorld', {
frameId: this._frameData(frame).id,
grantUniveralAccess: true,
@ -457,7 +457,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
if (args)
args.map(arg => releaseObject(this._client, arg));
if (source !== 'worker')
this._page.emit(CommonEvents.Page.Console, new console.ConsoleMessage(level, text, [], {url, lineNumber}));
this._page.emit(CommonEvents.Page.Console, new ConsoleMessage(level, text, [], {url, lineNumber}));
}
async _onFileChooserOpened(event: Protocol.Page.fileChooserOpenedPayload) {

View file

@ -116,7 +116,6 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate {
try {
callFunctionOnPromise = this._session.send('Runtime.callFunctionOn', {
functionDeclaration: functionText + '\n' + suffix + '\n',
// TODO(yurys): support executionContextId in WebKit
objectId: thisObjectId,
arguments: serializableArgs.map((arg: any) => this._convertArgument(arg)),
returnByValue: false,

View file

@ -25,7 +25,7 @@ import * as network from '../network';
import { TargetSession, TargetSessionEvents } from './Connection';
import { Events } from './events';
import { Events as CommonEvents } from '../events';
import { ExecutionContextDelegate } from './ExecutionContext';
import { ExecutionContextDelegate, EVALUATION_SCRIPT_URL } from './ExecutionContext';
import { NetworkManager, NetworkManagerEvents } from './NetworkManager';
import { Page, PageDelegate } from '../page';
import { Protocol } from './protocol';
@ -37,6 +37,8 @@ import { WKScreenshotDelegate } from './Screenshotter';
import * as input from '../input';
import * as types from '../types';
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
export const FrameManagerEvents = {
FrameNavigatedWithinDocument: Symbol('FrameNavigatedWithinDocument'),
TargetSwappedOnNavigation: Symbol('TargetSwappedOnNavigation'),
@ -98,7 +100,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
]);
this._handleFrameTree(frameTree);
await Promise.all([
this._session.send('Runtime.enable'),
this._session.send('Runtime.enable').then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)),
this._session.send('Console.enable'),
this._session.send('Dialog.enable'),
this._session.send('Page.setInterceptFileChooserDialog', { enabled: true }),
@ -293,8 +295,6 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
_onExecutionContextCreated(contextPayload : Protocol.Runtime.ExecutionContextDescription) {
if (this._contextIdToContext.has(contextPayload.id))
return;
if (!contextPayload.isPageContext)
return;
const frameId = contextPayload.frameId;
// If the frame was attached manually there is no navigation event.
// FIXME: support frameAttached event in WebKit protocol.
@ -304,7 +304,9 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
const context = new js.ExecutionContext(new ExecutionContextDelegate(this._session, contextPayload));
if (frame) {
context._domWorld = new dom.DOMWorld(context, new DOMWorldDelegate(this, frame));
if (contextPayload.isPageContext)
frame._contextCreated('main', context);
else if (contextPayload.name === UTILITY_WORLD_NAME)
frame._contextCreated('utility', context);
}
this._contextIdToContext.set(contextPayload.id, context);
@ -413,7 +415,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
}
async _onFileChooserOpened(event: {frameId: Protocol.Network.FrameId, element: Protocol.Runtime.RemoteObject}) {
const context = await this.frame(event.frameId)._utilityContext();
const context = await this.frame(event.frameId)._mainContext();
const handle = context._createHandle(event.element).asElement()!;
this._page._onFileChooserOpened(handle);
}
@ -422,6 +424,16 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
return this._networkManager.setExtraHTTPHeaders(extraHTTPHeaders);
}
async _ensureIsolatedWorld(name: string) {
if (this._isolatedWorlds.has(name))
return;
this._isolatedWorlds.add(name);
await this._session.send('Page.createIsolatedWorld', {
name,
source: `//# sourceURL=${EVALUATION_SCRIPT_URL}`
});
}
async setUserAgent(userAgent: string): Promise<void> {
await this._session.send('Page.overrideUserAgent', { value: userAgent });
}

View file

@ -15,12 +15,13 @@
* limitations under the License.
*/
import { debugError, assert } from '../helper';
import * as input from '../input';
import * as dom from '../dom';
import * as frames from '../frames';
import { debugError } from '../helper';
import * as input from '../input';
import * as types from '../types';
import { TargetSession } from './Connection';
import { ExecutionContextDelegate } from './ExecutionContext';
import { FrameManager } from './FrameManager';
import { Protocol } from './protocol';
@ -99,8 +100,11 @@ export class DOMWorldDelegate implements dom.DOMWorldDelegate {
}
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.DOMWorld): Promise<dom.ElementHandle<T>> {
assert(false, 'Multiple isolated worlds are not implemented');
return handle;
const result = await this._client.send('DOM.resolveNode', {
objectId: toRemoteObject(handle).objectId,
executionContextId: (to.context._delegate as ExecutionContextDelegate)._contextId
});
return to.context._createHandle(result.object) as dom.ElementHandle<T>;
}
}

View file

@ -36,7 +36,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
await page.click('circle');
expect(await page.evaluate(() => window.__CLICKED)).toBe(42);
});
it.skip(FFOX || WEBKIT)('should click the button if window.Node is removed', async({page, server}) => {
it.skip(FFOX)('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');