chore: exposeBinding/exposeFunction in bidi (#32669)
This commit is contained in:
parent
ad70e7a783
commit
375a1c4982
|
|
@ -72,7 +72,7 @@ export class BidiConnection {
|
||||||
let context;
|
let context;
|
||||||
if ('context' in object.params)
|
if ('context' in object.params)
|
||||||
context = object.params.context;
|
context = object.params.context;
|
||||||
else if (object.method === 'log.entryAdded')
|
else if (object.method === 'log.entryAdded' || object.method === 'script.message')
|
||||||
context = object.params.source?.context;
|
context = object.params.source?.context;
|
||||||
if (context) {
|
if (context) {
|
||||||
const session = this._browsingContextToSession.get(context);
|
const session = this._browsingContextToSession.get(context);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import { BidiSerializer } from './third_party/bidiSerializer';
|
||||||
|
|
||||||
export class BidiExecutionContext implements js.ExecutionContextDelegate {
|
export class BidiExecutionContext implements js.ExecutionContextDelegate {
|
||||||
private readonly _session: BidiSession;
|
private readonly _session: BidiSession;
|
||||||
private readonly _target: bidi.Script.Target;
|
readonly _target: bidi.Script.Target;
|
||||||
|
|
||||||
constructor(session: BidiSession, realmInfo: bidi.Script.RealmInfo) {
|
constructor(session: BidiSession, realmInfo: bidi.Script.RealmInfo) {
|
||||||
this._session = session;
|
this._session = session;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ import type * as accessibility from '../accessibility';
|
||||||
import * as dom from '../dom';
|
import * as dom from '../dom';
|
||||||
import * as dialog from '../dialog';
|
import * as dialog from '../dialog';
|
||||||
import type * as frames from '../frames';
|
import type * as frames from '../frames';
|
||||||
import { type InitScript, Page, type PageDelegate } from '../page';
|
import { Page } from '../page';
|
||||||
|
import type { InitScript, PageDelegate } from '../page';
|
||||||
import type { Progress } from '../progress';
|
import type { Progress } from '../progress';
|
||||||
import type * as types from '../types';
|
import type * as types from '../types';
|
||||||
import type { BidiBrowserContext } from './bidiBrowser';
|
import type { BidiBrowserContext } from './bidiBrowser';
|
||||||
|
|
@ -33,6 +34,7 @@ import { BidiNetworkManager } from './bidiNetworkManager';
|
||||||
import { BrowserContext } from '../browserContext';
|
import { BrowserContext } from '../browserContext';
|
||||||
|
|
||||||
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
|
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
|
||||||
|
const kPlaywrightBindingChannel = 'playwrightChannel';
|
||||||
|
|
||||||
export class BidiPage implements PageDelegate {
|
export class BidiPage implements PageDelegate {
|
||||||
readonly rawMouse: RawMouseImpl;
|
readonly rawMouse: RawMouseImpl;
|
||||||
|
|
@ -62,6 +64,7 @@ export class BidiPage implements PageDelegate {
|
||||||
this._page.on(Page.Events.FrameDetached, (frame: frames.Frame) => this._removeContextsForFrame(frame, false));
|
this._page.on(Page.Events.FrameDetached, (frame: frames.Frame) => this._removeContextsForFrame(frame, false));
|
||||||
this._sessionListeners = [
|
this._sessionListeners = [
|
||||||
eventsHelper.addEventListener(bidiSession, 'script.realmCreated', this._onRealmCreated.bind(this)),
|
eventsHelper.addEventListener(bidiSession, 'script.realmCreated', this._onRealmCreated.bind(this)),
|
||||||
|
eventsHelper.addEventListener(bidiSession, 'script.message', this._onScriptMessage.bind(this)),
|
||||||
eventsHelper.addEventListener(bidiSession, 'browsingContext.contextDestroyed', this._onBrowsingContextDestroyed.bind(this)),
|
eventsHelper.addEventListener(bidiSession, 'browsingContext.contextDestroyed', this._onBrowsingContextDestroyed.bind(this)),
|
||||||
eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationStarted', this._onNavigationStarted.bind(this)),
|
eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationStarted', this._onNavigationStarted.bind(this)),
|
||||||
eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationAborted', this._onNavigationAborted.bind(this)),
|
eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationAborted', this._onNavigationAborted.bind(this)),
|
||||||
|
|
@ -93,6 +96,7 @@ export class BidiPage implements PageDelegate {
|
||||||
this.updateHttpCredentials(),
|
this.updateHttpCredentials(),
|
||||||
this.updateRequestInterception(),
|
this.updateRequestInterception(),
|
||||||
this._updateViewport(),
|
this._updateViewport(),
|
||||||
|
this._installMainBinding(),
|
||||||
this._addAllInitScripts(),
|
this._addAllInitScripts(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -327,6 +331,45 @@ export class BidiPage implements PageDelegate {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: consider calling this only when bindings are added.
|
||||||
|
private async _installMainBinding() {
|
||||||
|
const functionDeclaration = addMainBinding.toString();
|
||||||
|
const args: bidi.Script.ChannelValue[] = [{
|
||||||
|
type: 'channel',
|
||||||
|
value: {
|
||||||
|
channel: kPlaywrightBindingChannel,
|
||||||
|
ownership: bidi.Script.ResultOwnership.Root,
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
const promises = [];
|
||||||
|
promises.push(this._session.send('script.addPreloadScript', {
|
||||||
|
functionDeclaration,
|
||||||
|
arguments: args,
|
||||||
|
}));
|
||||||
|
promises.push(this._session.send('script.callFunction', {
|
||||||
|
functionDeclaration,
|
||||||
|
arguments: args,
|
||||||
|
target: toBidiExecutionContext(await this._page.mainFrame()._mainContext())._target,
|
||||||
|
awaitPromise: false,
|
||||||
|
userActivation: false,
|
||||||
|
}));
|
||||||
|
await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _onScriptMessage(event: bidi.Script.MessageParameters) {
|
||||||
|
if (event.channel !== kPlaywrightBindingChannel)
|
||||||
|
return;
|
||||||
|
const pageOrError = await this.pageOrError();
|
||||||
|
if (pageOrError instanceof Error)
|
||||||
|
return;
|
||||||
|
const context = this._realmToContext.get(event.source.realm);
|
||||||
|
if (!context)
|
||||||
|
return;
|
||||||
|
if (event.data.type !== 'string')
|
||||||
|
return;
|
||||||
|
await this._page._onBindingCalled(event.data.value, context);
|
||||||
|
}
|
||||||
|
|
||||||
async addInitScript(initScript: InitScript): Promise<void> {
|
async addInitScript(initScript: InitScript): Promise<void> {
|
||||||
const { script } = await this._session.send('script.addPreloadScript', {
|
const { script } = await this._session.send('script.addPreloadScript', {
|
||||||
// TODO: remove function call from the source.
|
// TODO: remove function call from the source.
|
||||||
|
|
@ -522,6 +565,10 @@ export class BidiPage implements PageDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addMainBinding(callback: (arg: any) => void) {
|
||||||
|
(globalThis as any)['__playwright__binding__'] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
function toBidiExecutionContext(executionContext: dom.FrameExecutionContext): BidiExecutionContext {
|
function toBidiExecutionContext(executionContext: dom.FrameExecutionContext): BidiExecutionContext {
|
||||||
return (executionContext as any)[contextDelegateSymbol] as BidiExecutionContext;
|
return (executionContext as any)[contextDelegateSymbol] as BidiExecutionContext;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue