Skip to content

Commit

Permalink
chore(bidi): move private handle conversion to execution context (#34765
Browse files Browse the repository at this point in the history
)
  • Loading branch information
yury-s authored Feb 13, 2025
1 parent bab197b commit 6951e6a
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 31 deletions.
41 changes: 40 additions & 1 deletion packages/playwright-core/src/server/bidi/bidiExecutionContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import { parseEvaluationResultValue } from '../isomorphic/utilityScriptSerializers';
import * as js from '../javascript';
import * as dom from '../dom';
import { BidiDeserializer } from './third_party/bidiDeserializer';
import * as bidi from './third_party/bidiProtocol';
import { BidiSerializer } from './third_party/bidiSerializer';
Expand Down Expand Up @@ -137,7 +138,45 @@ export class BidiExecutionContext implements js.ExecutionContextDelegate {
});
}

async rawCallFunction(functionDeclaration: string, arg: bidi.Script.LocalValue): Promise<bidi.Script.RemoteValue> {

async nodeIdForElementHandle(handle: dom.ElementHandle): Promise<bidi.Script.SharedReference> {
const shared = await this._remoteValueForReference({ handle: handle._objectId });
// TODO: store sharedId in the handle.
if (!('sharedId' in shared))
throw new Error('Element is not a node');
return {
sharedId: shared.sharedId!,
};
}

async remoteObjectForNodeId(nodeId: bidi.Script.SharedReference): Promise<js.RemoteObject> {
const result = await this._remoteValueForReference(nodeId);
if ('handle' in result)
return { objectId: result.handle!, ...result };
throw new Error('Can\'t get remote object for nodeId');
}

async contentFrameIdForFrame(handle: dom.ElementHandle) {
const contentWindow = await this._rawCallFunction('e => e.contentWindow', { handle: handle._objectId });
if (contentWindow?.type === 'window')
return contentWindow.value.context;
return null;
}

async frameIdForWindowHandle(handle: js.JSHandle): Promise<string | null> {
if (!handle._objectId)
throw new Error('JSHandle is not a DOM node handle');
const contentWindow = await this._remoteValueForReference({ handle: handle._objectId });
if (contentWindow.type === 'window')
return contentWindow.value.context;
return null;
}

private async _remoteValueForReference(reference: bidi.Script.RemoteReference) {
return await this._rawCallFunction('e => e', reference);
}

private async _rawCallFunction(functionDeclaration: string, arg: bidi.Script.LocalValue): Promise<bidi.Script.RemoteValue> {
const response = await this._session.send('script.callFunction', {
functionDeclaration,
target: this._target,
Expand Down
41 changes: 11 additions & 30 deletions packages/playwright-core/src/server/bidi/bidiPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,13 +413,10 @@ export class BidiPage implements PageDelegate {

async getContentFrame(handle: dom.ElementHandle): Promise<frames.Frame | null> {
const executionContext = toBidiExecutionContext(handle._context);
const contentWindow = await executionContext.rawCallFunction('e => e.contentWindow', { handle: handle._objectId });
if (contentWindow.type === 'window') {
const frameId = contentWindow.value.context;
const result = this._page._frameManager.frame(frameId);
return result;
}
return null;
const frameId = await executionContext.contentFrameIdForFrame(handle);
if (!frameId)
return null;
return this._page._frameManager.frame(frameId);
}

async getOwnerFrame(handle: dom.ElementHandle): Promise<string | null> {
Expand All @@ -430,15 +427,8 @@ export class BidiPage implements PageDelegate {
});
if (!windowHandle)
return null;
if (!windowHandle._objectId)
return null;
const executionContext = toBidiExecutionContext(windowHandle._context as dom.FrameExecutionContext);
const contentWindow = await executionContext.rawCallFunction('e => e', { handle: windowHandle._objectId });
if (contentWindow.type === 'window') {
const frameId = contentWindow.value.context;
return frameId;
}
return null;
const executionContext = toBidiExecutionContext(handle._context);
return executionContext.frameIdForWindowHandle(windowHandle);
}

isElementHandle(remoteObject: bidi.Script.RemoteValue): boolean {
Expand Down Expand Up @@ -535,29 +525,20 @@ export class BidiPage implements PageDelegate {

async setInputFilePaths(handle: dom.ElementHandle<HTMLInputElement>, paths: string[]): Promise<void> {
const fromContext = toBidiExecutionContext(handle._context);
const shared = await fromContext.rawCallFunction('x => x', { handle: handle._objectId });
// TODO: store sharedId in the handle.
if (!('sharedId' in shared))
throw new Error('Element is not a node');
const sharedId = shared.sharedId!;
await this._session.send('input.setFiles', {
context: this._session.sessionId,
element: { sharedId },
element: await fromContext.nodeIdForElementHandle(handle),
files: paths,
});
}

async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {
const fromContext = toBidiExecutionContext(handle._context);
const shared = await fromContext.rawCallFunction('x => x', { handle: handle._objectId });
// TODO: store sharedId in the handle.
if (!('sharedId' in shared))
throw new Error('Element is not a node');
const sharedId = shared.sharedId!;
const nodeId = await fromContext.nodeIdForElementHandle(handle);
const executionContext = toBidiExecutionContext(to);
const result = await executionContext.rawCallFunction('x => x', { sharedId });
if ('handle' in result)
return to.createHandle({ objectId: result.handle!, ...result }) as dom.ElementHandle<T>;
const objectId = await executionContext.remoteObjectForNodeId(nodeId);
if (objectId)
return to.createHandle(objectId) as dom.ElementHandle<T>;
throw new Error('Failed to adopt element handle.');
}

Expand Down

0 comments on commit 6951e6a

Please sign in to comment.