chore: move adoption to DOMWorld (#8760)

This commit is contained in:
jrandolf 2022-08-09 14:55:18 +02:00 committed by GitHub
parent 6934b94f23
commit 932a053d02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 48 deletions

View File

@ -95,7 +95,9 @@ const queryOne = async (
if (!res[0] || !res[0].backendDOMNodeId) {
return null;
}
return exeCtx._adoptBackendNodeId(res[0].backendDOMNodeId);
return (await exeCtx._world!.adoptBackendNode(
res[0].backendDOMNodeId
)) as ElementHandle<Node>;
};
const waitFor = async (
@ -132,11 +134,12 @@ const queryAll = async (
const exeCtx = element.executionContext();
const {name, role} = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
return Promise.all(
const world = exeCtx._world!;
return (await Promise.all(
res.map(axNode => {
return exeCtx._adoptBackendNodeId(axNode.backendDOMNodeId);
return world.adoptBackendNode(axNode.backendDOMNodeId);
})
);
)) as Array<ElementHandle<Node>>;
};
const queryAllArray = async (

View File

@ -29,6 +29,7 @@ import {TimeoutSettings} from './TimeoutSettings.js';
import {EvaluateFunc, HandleFor, NodeFor} from './types.js';
import {
createDeferredPromise,
createJSHandle,
debugError,
DeferredPromise,
importFS,
@ -739,6 +740,29 @@ export class DOMWorld {
return document.title;
});
}
async adoptBackendNode(
backendNodeId?: Protocol.DOM.BackendNodeId
): Promise<JSHandle<Node>> {
const executionContext = await this.executionContext();
const {object} = await this.#client.send('DOM.resolveNode', {
backendNodeId: backendNodeId,
executionContextId: executionContext._contextId,
});
return createJSHandle(executionContext, object) as JSHandle<Node>;
}
async adoptHandle<T extends JSHandle<Node>>(handle: T): Promise<T> {
const executionContext = await this.executionContext();
assert(
handle.executionContext() !== executionContext,
'Cannot adopt handle that already belongs to this execution context'
);
const nodeInfo = await this.#client.send('DOM.describeNode', {
objectId: handle._remoteObject.objectId,
});
return (await this.adoptBackendNode(nodeInfo.node.backendNodeId)) as T;
}
}
/**

View File

@ -123,8 +123,7 @@ export class ElementHandle<
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const frame = this._context.frame();
assert(frame);
const secondaryContext = await frame._secondaryWorld.executionContext();
const adoptedRoot = await secondaryContext._adoptElementHandle(this);
const adoptedRoot = await frame._secondaryWorld.adoptHandle(this);
const handle = await frame._secondaryWorld.waitForSelector(selector, {
...options,
root: adoptedRoot,
@ -133,8 +132,9 @@ export class ElementHandle<
if (!handle) {
return null;
}
const mainExecutionContext = await frame._mainWorld.executionContext();
const result = await mainExecutionContext._adoptElementHandle(handle);
const result = (await frame._mainWorld.adoptHandle(
handle
)) as ElementHandle<NodeFor<Selector>>;
await handle.dispose();
return result;
}

View File

@ -38,19 +38,16 @@ const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;
/**
* This class represents a context for JavaScript execution. A [Page] might have
* many execution contexts:
* - each
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe |
* frame } has "default" execution context that is always created after frame is
* - each {@link
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe | frame}
* has "default" execution context that is always created after frame is
* attached to DOM. This context is returned by the
* {@link Frame.executionContext} method.
* - {@link https://developer.chrome.com/extensions | Extension}'s content scripts
* create additional execution contexts.
* - {@link https://developer.chrome.com/extensions | Extension}'s content
* scripts create additional execution contexts.
*
* Besides pages, execution contexts can be found in
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API |
* workers }.
*
* @public
* Besides pages, execution contexts can be found in {@link
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API | workers}.
*/
export class ExecutionContext {
/**
@ -87,9 +84,9 @@ export class ExecutionContext {
/**
* @remarks
*
* Not every execution context is associated with a frame. For
* example, workers and extensions have execution contexts that are not
* associated with frames.
* Not every execution context is associated with a frame. For example,
* workers and extensions have execution contexts that are not associated with
* frames.
*
* @returns The frame associated with this execution context.
*/
@ -422,21 +419,4 @@ export class ExecutionContext {
});
return createJSHandle(this, object) as ElementHandle<Node>;
}
/**
* @internal
*/
async _adoptElementHandle<T extends ElementHandle<Node>>(
elementHandle: T
): Promise<T> {
assert(
elementHandle.executionContext() !== this,
'Cannot adopt handle that already belongs to this execution context'
);
assert(this._world, 'Cannot adopt handle without DOMWorld');
const nodeInfo = await this._client.send('DOM.describeNode', {
objectId: elementHandle._remoteObject.objectId,
});
return (await this._adoptBackendNodeId(nodeInfo.node.backendNodeId)) as T;
}
}

View File

@ -1369,10 +1369,11 @@ export class Frame {
if (!handle) {
return null;
}
const mainExecutionContext = await this._mainWorld.executionContext();
const result = await mainExecutionContext._adoptElementHandle(handle);
const mainHandle = (await this._mainWorld.adoptHandle(
handle
)) as ElementHandle<NodeFor<Selector>>;
await handle.dispose();
return result;
return mainHandle;
}
/**

View File

@ -644,15 +644,13 @@ export class Page extends EventEmitter {
}
const frame = this.#frameManager.frame(event.frameId);
assert(frame);
const context = await frame.executionContext();
const element = await context._adoptBackendNodeId(event.backendNodeId);
// This is guaranteed to be an HTMLInputElement handle by the event.
const handle = (await frame._mainWorld.adoptBackendNode(
event.backendNodeId
)) as ElementHandle<HTMLInputElement>;
const interceptors = Array.from(this.#fileChooserInterceptors);
this.#fileChooserInterceptors.clear();
const fileChooser = new FileChooser(
// This is guaranteed by the event.
element as ElementHandle<HTMLInputElement>,
event
);
const fileChooser = new FileChooser(handle, event);
for (const interceptor of interceptors) {
interceptor.call(undefined, fileChooser);
}