chore: inherit FrameExecutionContext from ExecutionContext (#234)
This commit is contained in:
parent
5822de844a
commit
97c50c22ab
|
|
@ -350,16 +350,17 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
const frame = this._frames.get(frameId) || null;
|
||||
if (contextPayload.auxData && contextPayload.auxData.type === 'isolated')
|
||||
this._isolatedWorlds.add(contextPayload.name);
|
||||
const context = new js.ExecutionContext(new ExecutionContextDelegate(this._client, contextPayload));
|
||||
if (frame)
|
||||
context._domWorld = new dom.DOMWorld(context, frame);
|
||||
const delegate = new ExecutionContextDelegate(this._client, contextPayload);
|
||||
if (frame) {
|
||||
const context = new dom.FrameExecutionContext(delegate, frame);
|
||||
if (contextPayload.auxData && !!contextPayload.auxData.isDefault)
|
||||
frame._contextCreated('main', context);
|
||||
else if (contextPayload.name === UTILITY_WORLD_NAME)
|
||||
frame._contextCreated('utility', context);
|
||||
this._contextIdToContext.set(contextPayload.id, context);
|
||||
} else {
|
||||
this._contextIdToContext.set(contextPayload.id, new js.ExecutionContext(delegate));
|
||||
}
|
||||
this._contextIdToContext.set(contextPayload.id, context);
|
||||
}
|
||||
|
||||
_onExecutionContextDestroyed(executionContextId: number) {
|
||||
|
|
@ -368,7 +369,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
return;
|
||||
this._contextIdToContext.delete(executionContextId);
|
||||
if (context.frame())
|
||||
context.frame()._contextDestroyed(context);
|
||||
context.frame()._contextDestroyed(context as dom.FrameExecutionContext);
|
||||
}
|
||||
|
||||
_onExecutionContextsCleared() {
|
||||
|
|
@ -452,8 +453,8 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
|
||||
async _onFileChooserOpened(event: Protocol.Page.fileChooserOpenedPayload) {
|
||||
const frame = this.frame(event.frameId);
|
||||
const utilityWorld = await frame._utilityDOMWorld();
|
||||
const handle = await this.adoptBackendNodeId(event.backendNodeId, utilityWorld);
|
||||
const utilityContext = await frame._utilityContext();
|
||||
const handle = await this.adoptBackendNodeId(event.backendNodeId, utilityContext);
|
||||
this._page._onFileChooserOpened(handle);
|
||||
}
|
||||
|
||||
|
|
@ -617,21 +618,21 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
await handle.evaluate(input.setFileInputFunction, files);
|
||||
}
|
||||
|
||||
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.DOMWorld): Promise<dom.ElementHandle<T>> {
|
||||
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {
|
||||
const nodeInfo = await this._client.send('DOM.describeNode', {
|
||||
objectId: toRemoteObject(handle).objectId,
|
||||
});
|
||||
return this.adoptBackendNodeId(nodeInfo.node.backendNodeId, to) as Promise<dom.ElementHandle<T>>;
|
||||
}
|
||||
|
||||
async adoptBackendNodeId(backendNodeId: Protocol.DOM.BackendNodeId, to: dom.DOMWorld): Promise<dom.ElementHandle> {
|
||||
async adoptBackendNodeId(backendNodeId: Protocol.DOM.BackendNodeId, to: dom.FrameExecutionContext): Promise<dom.ElementHandle> {
|
||||
const result = await this._client.send('DOM.resolveNode', {
|
||||
backendNodeId,
|
||||
executionContextId: (to.context._delegate as ExecutionContextDelegate)._contextId,
|
||||
executionContextId: (to._delegate as ExecutionContextDelegate)._contextId,
|
||||
}).catch(debugError);
|
||||
if (!result)
|
||||
throw new Error('Unable to adopt element handle from a different document');
|
||||
return to.context._createHandle(result.object).asElement()!;
|
||||
return to._createHandle(result.object).asElement()!;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
134
src/dom.ts
134
src/dom.ts
|
|
@ -11,28 +11,32 @@ import * as xpathSelectorEngineSource from './generated/xpathSelectorEngineSourc
|
|||
import * as zsSelectorEngineSource from './generated/zsSelectorEngineSource';
|
||||
import { assert, helper, debugError } from './helper';
|
||||
import Injected from './injected/injected';
|
||||
import { Page } from './page';
|
||||
|
||||
type ScopedSelector = types.Selector & { scope?: ElementHandle };
|
||||
type ResolvedSelector = { scope?: ElementHandle, selector: string, visible?: boolean, disposeScope?: boolean };
|
||||
|
||||
export class DOMWorld {
|
||||
readonly context: js.ExecutionContext;
|
||||
readonly frame: frames.Frame;
|
||||
export class FrameExecutionContext extends js.ExecutionContext {
|
||||
private readonly _frame: frames.Frame;
|
||||
|
||||
private _injectedPromise?: Promise<js.JSHandle>;
|
||||
|
||||
constructor(context: js.ExecutionContext, frame: frames.Frame) {
|
||||
this.context = context;
|
||||
this.frame = frame;
|
||||
constructor(delegate: js.ExecutionContextDelegate, frame: frames.Frame) {
|
||||
super(delegate);
|
||||
this._frame = frame;
|
||||
}
|
||||
|
||||
createHandle(remoteObject: any): ElementHandle | null {
|
||||
if (this.frame._page._delegate.isElementHandle(remoteObject))
|
||||
return new ElementHandle(this.context, remoteObject);
|
||||
return null;
|
||||
frame(): frames.Frame | null {
|
||||
return this._frame;
|
||||
}
|
||||
|
||||
injected(): Promise<js.JSHandle> {
|
||||
_createHandle(remoteObject: any): js.JSHandle | null {
|
||||
if (this._frame._page._delegate.isElementHandle(remoteObject))
|
||||
return new ElementHandle(this, remoteObject);
|
||||
return super._createHandle(remoteObject);
|
||||
}
|
||||
|
||||
_injected(): Promise<js.JSHandle> {
|
||||
if (!this._injectedPromise) {
|
||||
const engineSources = [cssSelectorEngineSource.source, xpathSelectorEngineSource.source, zsSelectorEngineSource.source];
|
||||
const source = `
|
||||
|
|
@ -40,36 +44,36 @@ export class DOMWorld {
|
|||
${engineSources.join(',\n')}
|
||||
])
|
||||
`;
|
||||
this._injectedPromise = this.context.evaluateHandle(source);
|
||||
this._injectedPromise = this.evaluateHandle(source);
|
||||
}
|
||||
return this._injectedPromise;
|
||||
}
|
||||
|
||||
async adoptElementHandle<T extends Node>(handle: ElementHandle<T>): Promise<ElementHandle<T>> {
|
||||
assert(handle.executionContext() !== this.context, 'Should not adopt to the same context');
|
||||
return this.frame._page._delegate.adoptElementHandle(handle, this);
|
||||
async _adoptElementHandle<T extends Node>(handle: ElementHandle<T>): Promise<ElementHandle<T>> {
|
||||
assert(handle.executionContext() !== this, 'Should not adopt to the same context');
|
||||
return this._frame._page._delegate.adoptElementHandle(handle, this);
|
||||
}
|
||||
|
||||
async resolveSelector(selector: string | ScopedSelector): Promise<ResolvedSelector> {
|
||||
async _resolveSelector(selector: string | ScopedSelector): Promise<ResolvedSelector> {
|
||||
if (helper.isString(selector))
|
||||
return { selector: normalizeSelector(selector) };
|
||||
if (selector.scope && selector.scope.executionContext() !== this.context) {
|
||||
const scope = await this.adoptElementHandle(selector.scope);
|
||||
if (selector.scope && selector.scope.executionContext() !== this) {
|
||||
const scope = await this._adoptElementHandle(selector.scope);
|
||||
return { scope, selector: normalizeSelector(selector.selector), disposeScope: true, visible: selector.visible };
|
||||
}
|
||||
return { scope: selector.scope, selector: normalizeSelector(selector.selector), visible: selector.visible };
|
||||
}
|
||||
|
||||
async $(selector: string | ScopedSelector): Promise<ElementHandle<Element> | null> {
|
||||
const resolved = await this.resolveSelector(selector);
|
||||
const handle = await this.context.evaluateHandle(
|
||||
async _$(selector: string | ScopedSelector): Promise<ElementHandle<Element> | null> {
|
||||
const resolved = await this._resolveSelector(selector);
|
||||
const handle = await this.evaluateHandle(
|
||||
(injected: Injected, selector: string, scope?: Node, visible?: boolean) => {
|
||||
const element = injected.querySelector(selector, scope || document);
|
||||
if (visible === undefined || !element)
|
||||
return element;
|
||||
return injected.isVisible(element) === visible ? element : undefined;
|
||||
},
|
||||
await this.injected(), resolved.selector, resolved.scope, resolved.visible
|
||||
await this._injected(), resolved.selector, resolved.scope, resolved.visible
|
||||
);
|
||||
if (resolved.disposeScope)
|
||||
await resolved.scope.dispose();
|
||||
|
|
@ -78,16 +82,16 @@ export class DOMWorld {
|
|||
return handle.asElement();
|
||||
}
|
||||
|
||||
async $$(selector: string | ScopedSelector): Promise<ElementHandle<Element>[]> {
|
||||
const resolved = await this.resolveSelector(selector);
|
||||
const arrayHandle = await this.context.evaluateHandle(
|
||||
async _$$(selector: string | ScopedSelector): Promise<ElementHandle<Element>[]> {
|
||||
const resolved = await this._resolveSelector(selector);
|
||||
const arrayHandle = await this.evaluateHandle(
|
||||
(injected: Injected, selector: string, scope?: Node, visible?: boolean) => {
|
||||
const elements = injected.querySelectorAll(selector, scope || document);
|
||||
if (visible !== undefined)
|
||||
return elements.filter(element => injected.isVisible(element) === visible);
|
||||
return elements;
|
||||
},
|
||||
await this.injected(), resolved.selector, resolved.scope, resolved.visible
|
||||
await this._injected(), resolved.selector, resolved.scope, resolved.visible
|
||||
);
|
||||
if (resolved.disposeScope)
|
||||
await resolved.scope.dispose();
|
||||
|
|
@ -104,8 +108,8 @@ export class DOMWorld {
|
|||
return result;
|
||||
}
|
||||
|
||||
$eval: types.$Eval<string | ScopedSelector> = async (selector, pageFunction, ...args) => {
|
||||
const elementHandle = await this.$(selector);
|
||||
_$eval: types.$Eval<string | ScopedSelector> = async (selector, pageFunction, ...args) => {
|
||||
const elementHandle = await this._$(selector);
|
||||
if (!elementHandle)
|
||||
throw new Error(`Error: failed to find element matching selector "${types.selectorToString(selector)}"`);
|
||||
const result = await elementHandle.evaluate(pageFunction, ...args as any);
|
||||
|
|
@ -113,16 +117,16 @@ export class DOMWorld {
|
|||
return result;
|
||||
}
|
||||
|
||||
$$eval: types.$$Eval<string | ScopedSelector> = async (selector, pageFunction, ...args) => {
|
||||
const resolved = await this.resolveSelector(selector);
|
||||
const arrayHandle = await this.context.evaluateHandle(
|
||||
_$$eval: types.$$Eval<string | ScopedSelector> = async (selector, pageFunction, ...args) => {
|
||||
const resolved = await this._resolveSelector(selector);
|
||||
const arrayHandle = await this.evaluateHandle(
|
||||
(injected: Injected, selector: string, scope?: Node, visible?: boolean) => {
|
||||
const elements = injected.querySelectorAll(selector, scope || document);
|
||||
if (visible !== undefined)
|
||||
return elements.filter(element => injected.isVisible(element) === visible);
|
||||
return elements;
|
||||
},
|
||||
await this.injected(), resolved.selector, resolved.scope, resolved.visible
|
||||
await this._injected(), resolved.selector, resolved.scope, resolved.visible
|
||||
);
|
||||
const result = await arrayHandle.evaluate(pageFunction, ...args as any);
|
||||
await arrayHandle.dispose();
|
||||
|
|
@ -131,12 +135,12 @@ export class DOMWorld {
|
|||
}
|
||||
|
||||
export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||
readonly _world: DOMWorld;
|
||||
readonly _context: FrameExecutionContext;
|
||||
readonly _page: Page;
|
||||
|
||||
constructor(context: js.ExecutionContext, remoteObject: any) {
|
||||
constructor(context: FrameExecutionContext, remoteObject: any) {
|
||||
super(context, remoteObject);
|
||||
assert(context._domWorld, 'Element handle should have a dom world');
|
||||
this._world = context._domWorld;
|
||||
this._page = context.frame()._page;
|
||||
}
|
||||
|
||||
asElement(): ElementHandle<T> | null {
|
||||
|
|
@ -144,7 +148,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
}
|
||||
|
||||
async contentFrame(): Promise<frames.Frame | null> {
|
||||
return this._world.frame._page._delegate.getContentFrame(this);
|
||||
return this._page._delegate.getContentFrame(this);
|
||||
}
|
||||
|
||||
async _scrollIntoViewIfNeeded() {
|
||||
|
|
@ -175,7 +179,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
element.scrollIntoView({block: 'center', inline: 'center', behavior: 'instant'});
|
||||
}
|
||||
return false;
|
||||
}, !!this._world.frame._page._state.javascriptEnabled);
|
||||
}, !!this._page._state.javascriptEnabled);
|
||||
if (error)
|
||||
throw new Error(error);
|
||||
}
|
||||
|
|
@ -222,8 +226,8 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
};
|
||||
|
||||
const [quads, metrics] = await Promise.all([
|
||||
this._world.frame._page._delegate.getContentQuads(this),
|
||||
this._world.frame._page._delegate.layoutViewport(),
|
||||
this._page._delegate.getContentQuads(this),
|
||||
this._page._delegate.layoutViewport(),
|
||||
]);
|
||||
if (!quads || !quads.length)
|
||||
throw new Error('Node is either not visible or not an HTMLElement');
|
||||
|
|
@ -260,7 +264,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
point.x += border.x;
|
||||
point.y += border.y;
|
||||
}
|
||||
const metrics = await this._world.frame._page._delegate.layoutViewport();
|
||||
const metrics = await this._page._delegate.layoutViewport();
|
||||
// Give 20 extra pixels to avoid any issues on viewport edge.
|
||||
let scrollX = 0;
|
||||
if (point.x < 20)
|
||||
|
|
@ -279,26 +283,26 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
const point = await this._ensurePointerActionPoint(options ? options.relativePoint : undefined);
|
||||
let restoreModifiers: input.Modifier[] | undefined;
|
||||
if (options && options.modifiers)
|
||||
restoreModifiers = await this._world.frame._page.keyboard._ensureModifiers(options.modifiers);
|
||||
restoreModifiers = await this._page.keyboard._ensureModifiers(options.modifiers);
|
||||
await action(point);
|
||||
if (restoreModifiers)
|
||||
await this._world.frame._page.keyboard._ensureModifiers(restoreModifiers);
|
||||
await this._page.keyboard._ensureModifiers(restoreModifiers);
|
||||
}
|
||||
|
||||
hover(options?: input.PointerActionOptions): Promise<void> {
|
||||
return this._performPointerAction(point => this._world.frame._page.mouse.move(point.x, point.y), options);
|
||||
return this._performPointerAction(point => this._page.mouse.move(point.x, point.y), options);
|
||||
}
|
||||
|
||||
click(options?: input.ClickOptions): Promise<void> {
|
||||
return this._performPointerAction(point => this._world.frame._page.mouse.click(point.x, point.y, options), options);
|
||||
return this._performPointerAction(point => this._page.mouse.click(point.x, point.y, options), options);
|
||||
}
|
||||
|
||||
dblclick(options?: input.MultiClickOptions): Promise<void> {
|
||||
return this._performPointerAction(point => this._world.frame._page.mouse.dblclick(point.x, point.y, options), options);
|
||||
return this._performPointerAction(point => this._page.mouse.dblclick(point.x, point.y, options), options);
|
||||
}
|
||||
|
||||
tripleclick(options?: input.MultiClickOptions): Promise<void> {
|
||||
return this._performPointerAction(point => this._world.frame._page.mouse.tripleclick(point.x, point.y, options), options);
|
||||
return this._performPointerAction(point => this._page.mouse.tripleclick(point.x, point.y, options), options);
|
||||
}
|
||||
|
||||
async select(...values: (string | ElementHandle | input.SelectOption)[]): Promise<string[]> {
|
||||
|
|
@ -321,7 +325,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
const error = await this.evaluate(input.fillFunction);
|
||||
if (error)
|
||||
throw new Error(error);
|
||||
await this._world.frame._page.keyboard.sendCharacters(value);
|
||||
await this._page.keyboard.sendCharacters(value);
|
||||
}
|
||||
|
||||
async setInputFiles(...files: (string|input.FilePayload)[]) {
|
||||
|
|
@ -332,7 +336,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
return input.multiple;
|
||||
});
|
||||
assert(multiple || files.length <= 1, 'Non-multiple file input can only accept single file!');
|
||||
await this._world.frame._page._delegate.setInputFiles(this, await input.loadFiles(files));
|
||||
await this._page._delegate.setInputFiles(this, await input.loadFiles(files));
|
||||
}
|
||||
|
||||
async focus() {
|
||||
|
|
@ -348,20 +352,20 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
|
||||
async type(text: string, options: { delay: (number | undefined); } | undefined) {
|
||||
await this.focus();
|
||||
await this._world.frame._page.keyboard.type(text, options);
|
||||
await this._page.keyboard.type(text, options);
|
||||
}
|
||||
|
||||
async press(key: string, options: { delay?: number; text?: string; } | undefined) {
|
||||
await this.focus();
|
||||
await this._world.frame._page.keyboard.press(key, options);
|
||||
await this._page.keyboard.press(key, options);
|
||||
}
|
||||
|
||||
async boundingBox(): Promise<types.Rect | null> {
|
||||
return this._world.frame._page._delegate.getBoundingBox(this);
|
||||
return this._page._delegate.getBoundingBox(this);
|
||||
}
|
||||
|
||||
async screenshot(options?: types.ElementScreenshotOptions): Promise<string | Buffer> {
|
||||
return this._world.frame._page._screenshotter.screenshotElement(this, options);
|
||||
return this._page._screenshotter.screenshotElement(this, options);
|
||||
}
|
||||
|
||||
private _scopedSelector(selector: string | types.Selector): string | ScopedSelector {
|
||||
|
|
@ -372,23 +376,23 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
}
|
||||
|
||||
$(selector: string | types.Selector): Promise<ElementHandle | null> {
|
||||
return this._world.$(this._scopedSelector(selector));
|
||||
return this._context._$(this._scopedSelector(selector));
|
||||
}
|
||||
|
||||
$$(selector: string | types.Selector): Promise<ElementHandle<Element>[]> {
|
||||
return this._world.$$(this._scopedSelector(selector));
|
||||
return this._context._$$(this._scopedSelector(selector));
|
||||
}
|
||||
|
||||
$eval: types.$Eval<string | types.Selector> = (selector, pageFunction, ...args) => {
|
||||
return this._world.$eval(this._scopedSelector(selector), pageFunction, ...args as any);
|
||||
return this._context._$eval(this._scopedSelector(selector), pageFunction, ...args as any);
|
||||
}
|
||||
|
||||
$$eval: types.$$Eval<string | types.Selector> = (selector, pageFunction, ...args) => {
|
||||
return this._world.$$eval(this._scopedSelector(selector), pageFunction, ...args as any);
|
||||
return this._context._$$eval(this._scopedSelector(selector), pageFunction, ...args as any);
|
||||
}
|
||||
|
||||
$x(expression: string): Promise<ElementHandle<Element>[]> {
|
||||
return this._world.$$({ scope: this, selector: 'xpath=' + expression });
|
||||
return this._context._$$({ scope: this, selector: 'xpath=' + expression });
|
||||
}
|
||||
|
||||
isIntersectingViewport(): Promise<boolean> {
|
||||
|
|
@ -422,7 +426,7 @@ function normalizeSelector(selector: string): string {
|
|||
return 'css=' + selector;
|
||||
}
|
||||
|
||||
export type Task = (domWorld: DOMWorld) => Promise<js.JSHandle>;
|
||||
export type Task = (context: FrameExecutionContext) => Promise<js.JSHandle>;
|
||||
|
||||
export function waitForFunctionTask(pageFunction: Function | string, options: types.WaitForFunctionOptions, ...args: any[]) {
|
||||
const { polling = 'raf' } = options;
|
||||
|
|
@ -434,20 +438,20 @@ export function waitForFunctionTask(pageFunction: Function | string, options: ty
|
|||
throw new Error('Unknown polling options: ' + polling);
|
||||
const predicateBody = helper.isString(pageFunction) ? 'return (' + pageFunction + ')' : 'return (' + pageFunction + ')(...args)';
|
||||
|
||||
return async (domWorld: DOMWorld) => domWorld.context.evaluateHandle((injected: Injected, predicateBody: string, polling: types.Polling, timeout: number, ...args) => {
|
||||
return async (context: FrameExecutionContext) => context.evaluateHandle((injected: Injected, predicateBody: string, polling: types.Polling, timeout: number, ...args) => {
|
||||
const predicate = new Function('...args', predicateBody);
|
||||
if (polling === 'raf')
|
||||
return injected.pollRaf(predicate, timeout, ...args);
|
||||
if (polling === 'mutation')
|
||||
return injected.pollMutation(predicate, timeout, ...args);
|
||||
return injected.pollInterval(polling, predicate, timeout, ...args);
|
||||
}, await domWorld.injected(), predicateBody, polling, options.timeout, ...args);
|
||||
}, await context._injected(), predicateBody, polling, options.timeout, ...args);
|
||||
}
|
||||
|
||||
export function waitForSelectorTask(selector: string | types.Selector, timeout: number): Task {
|
||||
return async (domWorld: DOMWorld) => {
|
||||
const resolved = await domWorld.resolveSelector(selector);
|
||||
return domWorld.context.evaluateHandle((injected: Injected, selector: string, scope: Node | undefined, visible: boolean | undefined, timeout: number) => {
|
||||
return async (context: FrameExecutionContext) => {
|
||||
const resolved = await context._resolveSelector(selector);
|
||||
return context.evaluateHandle((injected: Injected, selector: string, scope: Node | undefined, visible: boolean | undefined, timeout: number) => {
|
||||
if (visible !== undefined)
|
||||
return injected.pollRaf(predicate, timeout);
|
||||
return injected.pollMutation(predicate, timeout);
|
||||
|
|
@ -460,6 +464,6 @@ export function waitForSelectorTask(selector: string | types.Selector, timeout:
|
|||
return element;
|
||||
return injected.isVisible(element) === visible ? element : false;
|
||||
}
|
||||
}, await domWorld.injected(), resolved.selector, resolved.scope, resolved.visible, timeout);
|
||||
}, await context._injected(), resolved.selector, resolved.scope, resolved.visible, timeout);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,13 +109,15 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
_onExecutionContextCreated({executionContextId, auxData}) {
|
||||
const frameId = auxData ? auxData.frameId : null;
|
||||
const frame = this._frames.get(frameId) || null;
|
||||
const context = new js.ExecutionContext(new ExecutionContextDelegate(this._session, executionContextId));
|
||||
const delegate = new ExecutionContextDelegate(this._session, executionContextId);
|
||||
if (frame) {
|
||||
context._domWorld = new dom.DOMWorld(context, frame);
|
||||
const context = new dom.FrameExecutionContext(delegate, frame);
|
||||
frame._contextCreated('main', context);
|
||||
frame._contextCreated('utility', context);
|
||||
this._contextIdToContext.set(executionContextId, context);
|
||||
} else {
|
||||
this._contextIdToContext.set(executionContextId, new js.ExecutionContext(delegate));
|
||||
}
|
||||
this._contextIdToContext.set(executionContextId, context);
|
||||
}
|
||||
|
||||
_onExecutionContextDestroyed({executionContextId}) {
|
||||
|
|
@ -124,7 +126,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
return;
|
||||
this._contextIdToContext.delete(executionContextId);
|
||||
if (context.frame())
|
||||
context.frame()._contextDestroyed(context);
|
||||
context.frame()._contextDestroyed(context as dom.FrameExecutionContext);
|
||||
}
|
||||
|
||||
_frameData(frame: frames.Frame): FrameData {
|
||||
|
|
@ -440,7 +442,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
|
||||
async getContentFrame(handle: dom.ElementHandle): Promise<frames.Frame | null> {
|
||||
const { frameId } = await this._session.send('Page.contentFrame', {
|
||||
frameId: this._frameData(handle._world.frame).frameId,
|
||||
frameId: this._frameData(handle._context.frame()).frameId,
|
||||
objectId: toRemoteObject(handle).objectId,
|
||||
});
|
||||
if (!frameId)
|
||||
|
|
@ -473,7 +475,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
|
||||
async getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null> {
|
||||
const result = await this._session.send('Page.getContentQuads', {
|
||||
frameId: this._frameData(handle._world.frame).frameId,
|
||||
frameId: this._frameData(handle._context.frame()).frameId,
|
||||
objectId: toRemoteObject(handle).objectId,
|
||||
}).catch(debugError);
|
||||
if (!result)
|
||||
|
|
@ -489,7 +491,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
await handle.evaluate(input.setFileInputFunction, files);
|
||||
}
|
||||
|
||||
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.DOMWorld): Promise<dom.ElementHandle<T>> {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
167
src/frames.ts
167
src/frames.ts
|
|
@ -29,11 +29,11 @@ import { ConsoleMessage } from './console';
|
|||
|
||||
const readFileAsync = helper.promisify(fs.readFile);
|
||||
|
||||
type WorldType = 'main' | 'utility';
|
||||
type World = {
|
||||
contextPromise: Promise<js.ExecutionContext>;
|
||||
contextResolveCallback: (c: js.ExecutionContext) => void;
|
||||
context: js.ExecutionContext | null;
|
||||
type ContextType = 'main' | 'utility';
|
||||
type ContextData = {
|
||||
contextPromise: Promise<dom.FrameExecutionContext>;
|
||||
contextResolveCallback: (c: dom.FrameExecutionContext) => void;
|
||||
context: dom.FrameExecutionContext | null;
|
||||
rerunnableTasks: Set<RerunnableTask>;
|
||||
};
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ export class Frame {
|
|||
private _parentFrame: Frame;
|
||||
private _url = '';
|
||||
private _detached = false;
|
||||
private _worlds = new Map<WorldType, World>();
|
||||
private _contextData = new Map<ContextType, ContextData>();
|
||||
private _childFrames = new Set<Frame>();
|
||||
private _name: string;
|
||||
|
||||
|
|
@ -65,8 +65,8 @@ export class Frame {
|
|||
this._page = page;
|
||||
this._parentFrame = parentFrame;
|
||||
|
||||
this._worlds.set('main', { contextPromise: new Promise(() => {}), contextResolveCallback: () => {}, context: null, rerunnableTasks: new Set() });
|
||||
this._worlds.set('utility', { contextPromise: new Promise(() => {}), contextResolveCallback: () => {}, context: null, rerunnableTasks: new Set() });
|
||||
this._contextData.set('main', { contextPromise: new Promise(() => {}), contextResolveCallback: () => {}, context: null, rerunnableTasks: new Set() });
|
||||
this._contextData.set('utility', { contextPromise: new Promise(() => {}), contextResolveCallback: () => {}, context: null, rerunnableTasks: new Set() });
|
||||
this._setContext('main', null);
|
||||
this._setContext('utility', null);
|
||||
|
||||
|
|
@ -82,33 +82,19 @@ export class Frame {
|
|||
return this._page._delegate.waitForFrameNavigation(this, options);
|
||||
}
|
||||
|
||||
_mainContext(): Promise<js.ExecutionContext> {
|
||||
_mainContext(): Promise<dom.FrameExecutionContext> {
|
||||
if (this._detached)
|
||||
throw new Error(`Execution Context is not available in detached frame "${this.url()}" (are you trying to evaluate?)`);
|
||||
return this._worlds.get('main').contextPromise;
|
||||
return this._contextData.get('main').contextPromise;
|
||||
}
|
||||
|
||||
async _mainDOMWorld(): Promise<dom.DOMWorld> {
|
||||
const context = await this._mainContext();
|
||||
if (!context._domWorld)
|
||||
throw new Error(`Execution Context does not belong to frame`);
|
||||
return context._domWorld;
|
||||
}
|
||||
|
||||
_utilityContext(): Promise<js.ExecutionContext> {
|
||||
_utilityContext(): Promise<dom.FrameExecutionContext> {
|
||||
if (this._detached)
|
||||
throw new Error(`Execution Context is not available in detached frame "${this.url()}" (are you trying to evaluate?)`);
|
||||
return this._worlds.get('utility').contextPromise;
|
||||
return this._contextData.get('utility').contextPromise;
|
||||
}
|
||||
|
||||
async _utilityDOMWorld(): Promise<dom.DOMWorld> {
|
||||
const context = await this._utilityContext();
|
||||
if (!context._domWorld)
|
||||
throw new Error(`Execution Context does not belong to frame`);
|
||||
return context._domWorld;
|
||||
}
|
||||
|
||||
executionContext(): Promise<js.ExecutionContext> {
|
||||
executionContext(): Promise<dom.FrameExecutionContext> {
|
||||
return this._mainContext();
|
||||
}
|
||||
|
||||
|
|
@ -123,28 +109,28 @@ export class Frame {
|
|||
}
|
||||
|
||||
async $(selector: string | types.Selector): Promise<dom.ElementHandle<Element> | null> {
|
||||
const domWorld = await this._mainDOMWorld();
|
||||
return domWorld.$(types.clearSelector(selector));
|
||||
const context = await this._mainContext();
|
||||
return context._$(types.clearSelector(selector));
|
||||
}
|
||||
|
||||
async $x(expression: string): Promise<dom.ElementHandle<Element>[]> {
|
||||
const domWorld = await this._mainDOMWorld();
|
||||
return domWorld.$$('xpath=' + expression);
|
||||
const context = await this._mainContext();
|
||||
return context._$$('xpath=' + expression);
|
||||
}
|
||||
|
||||
$eval: types.$Eval = async (selector, pageFunction, ...args) => {
|
||||
const domWorld = await this._mainDOMWorld();
|
||||
return domWorld.$eval(selector, pageFunction, ...args as any);
|
||||
const context = await this._mainContext();
|
||||
return context._$eval(selector, pageFunction, ...args as any);
|
||||
}
|
||||
|
||||
$$eval: types.$$Eval = async (selector, pageFunction, ...args) => {
|
||||
const domWorld = await this._mainDOMWorld();
|
||||
return domWorld.$$eval(selector, pageFunction, ...args as any);
|
||||
const context = await this._mainContext();
|
||||
return context._$$eval(selector, pageFunction, ...args as any);
|
||||
}
|
||||
|
||||
async $$(selector: string | types.Selector): Promise<dom.ElementHandle<Element>[]> {
|
||||
const domWorld = await this._mainDOMWorld();
|
||||
return domWorld.$$(types.clearSelector(selector));
|
||||
const context = await this._mainContext();
|
||||
return context._$$(types.clearSelector(selector));
|
||||
}
|
||||
|
||||
async content(): Promise<string> {
|
||||
|
|
@ -319,61 +305,61 @@ export class Frame {
|
|||
}
|
||||
|
||||
async click(selector: string | types.Selector, options?: ClickOptions) {
|
||||
const domWorld = await this._utilityDOMWorld();
|
||||
const handle = await domWorld.$(types.clearSelector(selector));
|
||||
const context = await this._utilityContext();
|
||||
const handle = await context._$(types.clearSelector(selector));
|
||||
assert(handle, 'No node found for selector: ' + types.selectorToString(selector));
|
||||
await handle.click(options);
|
||||
await handle.dispose();
|
||||
}
|
||||
|
||||
async dblclick(selector: string | types.Selector, options?: MultiClickOptions) {
|
||||
const domWorld = await this._utilityDOMWorld();
|
||||
const handle = await domWorld.$(types.clearSelector(selector));
|
||||
const context = await this._utilityContext();
|
||||
const handle = await context._$(types.clearSelector(selector));
|
||||
assert(handle, 'No node found for selector: ' + types.selectorToString(selector));
|
||||
await handle.dblclick(options);
|
||||
await handle.dispose();
|
||||
}
|
||||
|
||||
async tripleclick(selector: string | types.Selector, options?: MultiClickOptions) {
|
||||
const domWorld = await this._utilityDOMWorld();
|
||||
const handle = await domWorld.$(types.clearSelector(selector));
|
||||
const context = await this._utilityContext();
|
||||
const handle = await context._$(types.clearSelector(selector));
|
||||
assert(handle, 'No node found for selector: ' + types.selectorToString(selector));
|
||||
await handle.tripleclick(options);
|
||||
await handle.dispose();
|
||||
}
|
||||
|
||||
async fill(selector: string | types.Selector, value: string) {
|
||||
const domWorld = await this._utilityDOMWorld();
|
||||
const handle = await domWorld.$(types.clearSelector(selector));
|
||||
const context = await this._utilityContext();
|
||||
const handle = await context._$(types.clearSelector(selector));
|
||||
assert(handle, 'No node found for selector: ' + types.selectorToString(selector));
|
||||
await handle.fill(value);
|
||||
await handle.dispose();
|
||||
}
|
||||
|
||||
async focus(selector: string | types.Selector) {
|
||||
const domWorld = await this._utilityDOMWorld();
|
||||
const handle = await domWorld.$(types.clearSelector(selector));
|
||||
const context = await this._utilityContext();
|
||||
const handle = await context._$(types.clearSelector(selector));
|
||||
assert(handle, 'No node found for selector: ' + types.selectorToString(selector));
|
||||
await handle.focus();
|
||||
await handle.dispose();
|
||||
}
|
||||
|
||||
async hover(selector: string | types.Selector, options?: PointerActionOptions) {
|
||||
const domWorld = await this._utilityDOMWorld();
|
||||
const handle = await domWorld.$(types.clearSelector(selector));
|
||||
const context = await this._utilityContext();
|
||||
const handle = await context._$(types.clearSelector(selector));
|
||||
assert(handle, 'No node found for selector: ' + types.selectorToString(selector));
|
||||
await handle.hover(options);
|
||||
await handle.dispose();
|
||||
}
|
||||
|
||||
async select(selector: string | types.Selector, ...values: (string | dom.ElementHandle | SelectOption)[]): Promise<string[]> {
|
||||
const domWorld = await this._utilityDOMWorld();
|
||||
const handle = await domWorld.$(types.clearSelector(selector));
|
||||
const context = await this._utilityContext();
|
||||
const handle = await context._$(types.clearSelector(selector));
|
||||
assert(handle, 'No node found for selector: ' + types.selectorToString(selector));
|
||||
const toDispose: Promise<dom.ElementHandle>[] = [];
|
||||
const adoptedValues = await Promise.all(values.map(async value => {
|
||||
if (value instanceof dom.ElementHandle && value.executionContext() !== domWorld.context) {
|
||||
const adopted = domWorld.adoptElementHandle(value);
|
||||
if (value instanceof dom.ElementHandle && value.executionContext() !== context) {
|
||||
const adopted = context._adoptElementHandle(value);
|
||||
toDispose.push(adopted);
|
||||
return adopted;
|
||||
}
|
||||
|
|
@ -386,8 +372,8 @@ export class Frame {
|
|||
}
|
||||
|
||||
async type(selector: string | types.Selector, text: string, options: { delay: (number | undefined); } | undefined) {
|
||||
const domWorld = await this._utilityDOMWorld();
|
||||
const handle = await domWorld.$(types.clearSelector(selector));
|
||||
const context = await this._utilityContext();
|
||||
const handle = await context._$(types.clearSelector(selector));
|
||||
assert(handle, 'No node found for selector: ' + types.selectorToString(selector));
|
||||
await handle.type(text, options);
|
||||
await handle.dispose();
|
||||
|
|
@ -411,10 +397,10 @@ export class Frame {
|
|||
await handle.dispose();
|
||||
return null;
|
||||
}
|
||||
const mainDOMWorld = await this._mainDOMWorld();
|
||||
if (handle.executionContext() === mainDOMWorld.context)
|
||||
const maincontext = await this._mainContext();
|
||||
if (handle.executionContext() === maincontext)
|
||||
return handle.asElement();
|
||||
const adopted = await mainDOMWorld.adoptElementHandle(handle.asElement());
|
||||
const adopted = await maincontext._adoptElementHandle(handle.asElement());
|
||||
await handle.dispose();
|
||||
return adopted;
|
||||
}
|
||||
|
|
@ -465,8 +451,8 @@ export class Frame {
|
|||
|
||||
_onDetached() {
|
||||
this._detached = true;
|
||||
for (const world of this._worlds.values()) {
|
||||
for (const rerunnableTask of world.rerunnableTasks)
|
||||
for (const data of this._contextData.values()) {
|
||||
for (const rerunnableTask of data.rerunnableTasks)
|
||||
rerunnableTask.terminate(new Error('waitForFunction failed: frame got detached.'));
|
||||
}
|
||||
if (this._parentFrame)
|
||||
|
|
@ -476,51 +462,50 @@ export class Frame {
|
|||
watcher._onFrameDetached(this);
|
||||
}
|
||||
|
||||
private _scheduleRerunnableTask(task: dom.Task, worldType: WorldType, timeout?: number, title?: string): Promise<js.JSHandle> {
|
||||
const world = this._worlds.get(worldType);
|
||||
const rerunnableTask = new RerunnableTask(world, task, timeout, title);
|
||||
world.rerunnableTasks.add(rerunnableTask);
|
||||
if (world.context)
|
||||
rerunnableTask.rerun(world.context._domWorld);
|
||||
private _scheduleRerunnableTask(task: dom.Task, contextType: ContextType, timeout?: number, title?: string): Promise<js.JSHandle> {
|
||||
const data = this._contextData.get(contextType);
|
||||
const rerunnableTask = new RerunnableTask(data, task, timeout, title);
|
||||
data.rerunnableTasks.add(rerunnableTask);
|
||||
if (data.context)
|
||||
rerunnableTask.rerun(data.context);
|
||||
return rerunnableTask.promise;
|
||||
}
|
||||
|
||||
private _setContext(worldType: WorldType, context: js.ExecutionContext | null) {
|
||||
const world = this._worlds.get(worldType);
|
||||
world.context = context;
|
||||
private _setContext(contextType: ContextType, context: dom.FrameExecutionContext | null) {
|
||||
const data = this._contextData.get(contextType);
|
||||
data.context = context;
|
||||
if (context) {
|
||||
assert(context._domWorld, 'Frame context must have a dom world');
|
||||
world.contextResolveCallback.call(null, context);
|
||||
for (const rerunnableTask of world.rerunnableTasks)
|
||||
rerunnableTask.rerun(context._domWorld);
|
||||
data.contextResolveCallback.call(null, context);
|
||||
for (const rerunnableTask of data.rerunnableTasks)
|
||||
rerunnableTask.rerun(context);
|
||||
} else {
|
||||
world.contextPromise = new Promise(fulfill => {
|
||||
world.contextResolveCallback = fulfill;
|
||||
data.contextPromise = new Promise(fulfill => {
|
||||
data.contextResolveCallback = fulfill;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_contextCreated(worldType: WorldType, context: js.ExecutionContext) {
|
||||
const world = this._worlds.get(worldType);
|
||||
_contextCreated(contextType: ContextType, context: dom.FrameExecutionContext) {
|
||||
const data = this._contextData.get(contextType);
|
||||
// In case of multiple sessions to the same target, there's a race between
|
||||
// connections so we might end up creating multiple isolated worlds.
|
||||
// We can use either.
|
||||
if (world.context)
|
||||
this._setContext(worldType, null);
|
||||
this._setContext(worldType, context);
|
||||
if (data.context)
|
||||
this._setContext(contextType, null);
|
||||
this._setContext(contextType, context);
|
||||
}
|
||||
|
||||
_contextDestroyed(context: js.ExecutionContext) {
|
||||
for (const [worldType, world] of this._worlds) {
|
||||
if (world.context === context)
|
||||
this._setContext(worldType, null);
|
||||
_contextDestroyed(context: dom.FrameExecutionContext) {
|
||||
for (const [contextType, data] of this._contextData) {
|
||||
if (data.context === context)
|
||||
this._setContext(contextType, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RerunnableTask {
|
||||
readonly promise: Promise<js.JSHandle>;
|
||||
private _world: World;
|
||||
private _contextData: ContextData;
|
||||
private _task: dom.Task;
|
||||
private _runCount: number;
|
||||
private _resolve: (result: js.JSHandle) => void;
|
||||
|
|
@ -528,8 +513,8 @@ class RerunnableTask {
|
|||
private _timeoutTimer: NodeJS.Timer;
|
||||
private _terminated: boolean;
|
||||
|
||||
constructor(world: World, task: dom.Task, timeout?: number, title?: string) {
|
||||
this._world = world;
|
||||
constructor(data: ContextData, task: dom.Task, timeout?: number, title?: string) {
|
||||
this._contextData = data;
|
||||
this._task = task;
|
||||
this._runCount = 0;
|
||||
this.promise = new Promise<js.JSHandle>((resolve, reject) => {
|
||||
|
|
@ -550,12 +535,12 @@ class RerunnableTask {
|
|||
this._doCleanup();
|
||||
}
|
||||
|
||||
async rerun(domWorld: dom.DOMWorld) {
|
||||
async rerun(context: dom.FrameExecutionContext) {
|
||||
const runCount = ++this._runCount;
|
||||
let success: js.JSHandle | null = null;
|
||||
let error = null;
|
||||
try {
|
||||
success = await this._task(domWorld);
|
||||
success = await this._task(context);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
|
@ -569,7 +554,7 @@ class RerunnableTask {
|
|||
// Ignore timeouts in pageScript - we track timeouts ourselves.
|
||||
// If execution context has been already destroyed, `context.evaluate` will
|
||||
// throw an error - ignore this predicate run altogether.
|
||||
if (!error && await domWorld.context.evaluate(s => !s, success).catch(e => true)) {
|
||||
if (!error && await context.evaluate(s => !s, success).catch(e => true)) {
|
||||
await success.dispose();
|
||||
return;
|
||||
}
|
||||
|
|
@ -594,7 +579,7 @@ class RerunnableTask {
|
|||
|
||||
_doCleanup() {
|
||||
clearTimeout(this._timeoutTimer);
|
||||
this._world.rerunnableTasks.delete(this);
|
||||
this._contextData.rerunnableTasks.delete(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,14 +15,13 @@ export interface ExecutionContextDelegate {
|
|||
|
||||
export class ExecutionContext {
|
||||
readonly _delegate: ExecutionContextDelegate;
|
||||
_domWorld?: dom.DOMWorld;
|
||||
|
||||
constructor(delegate: ExecutionContextDelegate) {
|
||||
this._delegate = delegate;
|
||||
}
|
||||
|
||||
frame(): frames.Frame | null {
|
||||
return this._domWorld ? this._domWorld.frame : null;
|
||||
return null;
|
||||
}
|
||||
|
||||
evaluate: types.Evaluate = (pageFunction, ...args) => {
|
||||
|
|
@ -34,7 +33,7 @@ export class ExecutionContext {
|
|||
}
|
||||
|
||||
_createHandle(remoteObject: any): JSHandle {
|
||||
return (this._domWorld && this._domWorld.createHandle(remoteObject)) || new JSHandle(this, remoteObject);
|
||||
return new JSHandle(this, remoteObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export interface PageDelegate {
|
|||
resetViewport(oldSize: types.Size): Promise<void>;
|
||||
|
||||
isElementHandle(remoteObject: any): boolean;
|
||||
adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.DOMWorld): Promise<dom.ElementHandle<T>>;
|
||||
adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>>;
|
||||
getContentFrame(handle: dom.ElementHandle): Promise<frames.Frame | null>;
|
||||
getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null>;
|
||||
layoutViewport(): Promise<{ width: number, height: number }>;
|
||||
|
|
@ -198,10 +198,10 @@ export class Page extends EventEmitter {
|
|||
}
|
||||
|
||||
async _createSelector(name: string, handle: dom.ElementHandle<Element>): Promise<string> {
|
||||
const mainWorld = await this.mainFrame()._mainDOMWorld();
|
||||
return mainWorld.context.evaluate((injected: Injected, target: Element, name: string) => {
|
||||
const mainContext = await this.mainFrame()._mainContext();
|
||||
return mainContext.evaluate((injected: Injected, target: Element, name: string) => {
|
||||
return injected.engines.get(name).create(document.documentElement, target);
|
||||
}, await mainWorld.injected(), handle, name);
|
||||
}, await mainContext._injected(), handle, name);
|
||||
}
|
||||
|
||||
evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => {
|
||||
|
|
|
|||
|
|
@ -146,7 +146,8 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
disconnectFromTarget() {
|
||||
for (const context of this._contextIdToContext.values()) {
|
||||
(context._delegate as ExecutionContextDelegate)._dispose();
|
||||
context.frame()._contextDestroyed(context);
|
||||
if (context.frame())
|
||||
context.frame()._contextDestroyed(context as dom.FrameExecutionContext);
|
||||
}
|
||||
// this._mainFrame = null;
|
||||
}
|
||||
|
|
@ -250,7 +251,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
const delegate = context._delegate as ExecutionContextDelegate;
|
||||
delegate._dispose();
|
||||
this._contextIdToContext.delete(delegate._contextId);
|
||||
frame._contextDestroyed(context);
|
||||
frame._contextDestroyed(context as dom.FrameExecutionContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,15 +290,17 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
const frame = this._frames.get(frameId) || null;
|
||||
if (!frame)
|
||||
return;
|
||||
const context = new js.ExecutionContext(new ExecutionContextDelegate(this._session, contextPayload));
|
||||
const delegate = new ExecutionContextDelegate(this._session, contextPayload);
|
||||
if (frame) {
|
||||
context._domWorld = new dom.DOMWorld(context, frame);
|
||||
const context = new dom.FrameExecutionContext(delegate, 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);
|
||||
} else {
|
||||
this._contextIdToContext.set(contextPayload.id, new js.ExecutionContext(delegate));
|
||||
}
|
||||
this._contextIdToContext.set(contextPayload.id, context);
|
||||
}
|
||||
|
||||
executionContextById(contextId: number): js.ExecutionContext {
|
||||
|
|
@ -593,12 +596,12 @@ export class FrameManager extends EventEmitter implements PageDelegate {
|
|||
await this._session.send('DOM.setInputFiles', { objectId, files });
|
||||
}
|
||||
|
||||
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.DOMWorld): Promise<dom.ElementHandle<T>> {
|
||||
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {
|
||||
const result = await this._session.send('DOM.resolveNode', {
|
||||
objectId: toRemoteObject(handle).objectId,
|
||||
executionContextId: (to.context._delegate as ExecutionContextDelegate)._contextId
|
||||
executionContextId: (to._delegate as ExecutionContextDelegate)._contextId
|
||||
});
|
||||
return to.context._createHandle(result.object) as dom.ElementHandle<T>;
|
||||
return to._createHandle(result.object) as dom.ElementHandle<T>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue