diff --git a/src/dispatchers/electronDispatcher.ts b/src/dispatchers/electronDispatcher.ts index 1bd167b843d6c..74bbc43b18545 100644 --- a/src/dispatchers/electronDispatcher.ts +++ b/src/dispatchers/electronDispatcher.ts @@ -51,12 +51,12 @@ export class ElectronApplicationDispatcher extends Dispatcher { const handle = this._object._nodeElectronHandle!; - return { value: serializeResult(await handle._evaluateExpression(params.expression, params.isFunction, true /* returnByValue */, parseArgument(params.arg))) }; + return { value: serializeResult(await handle.evaluateExpression(params.expression, params.isFunction, true /* returnByValue */, parseArgument(params.arg))) }; } async evaluateExpressionHandle(params: channels.ElectronApplicationEvaluateExpressionHandleParams): Promise { const handle = this._object._nodeElectronHandle!; - const result = await handle._evaluateExpression(params.expression, params.isFunction, false /* returnByValue */, parseArgument(params.arg)); + const result = await handle.evaluateExpression(params.expression, params.isFunction, false /* returnByValue */, parseArgument(params.arg)); return { handle: createHandle(this._scope, result) }; } diff --git a/src/dispatchers/elementHandlerDispatcher.ts b/src/dispatchers/elementHandlerDispatcher.ts index ef52de85459f2..a66d890bc0919 100644 --- a/src/dispatchers/elementHandlerDispatcher.ts +++ b/src/dispatchers/elementHandlerDispatcher.ts @@ -171,11 +171,11 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements chann } async evalOnSelector(params: channels.ElementHandleEvalOnSelectorParams, metadata: CallMetadata): Promise { - return { value: serializeResult(await this._elementHandle._$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg))) }; + return { value: serializeResult(await this._elementHandle.$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg))) }; } async evalOnSelectorAll(params: channels.ElementHandleEvalOnSelectorAllParams, metadata: CallMetadata): Promise { - return { value: serializeResult(await this._elementHandle._$$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg))) }; + return { value: serializeResult(await this._elementHandle.$$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg))) }; } async waitForElementState(params: channels.ElementHandleWaitForElementStateParams, metadata: CallMetadata): Promise { diff --git a/src/dispatchers/frameDispatcher.ts b/src/dispatchers/frameDispatcher.ts index 08482612a9508..d71f135f31991 100644 --- a/src/dispatchers/frameDispatcher.ts +++ b/src/dispatchers/frameDispatcher.ts @@ -61,11 +61,11 @@ export class FrameDispatcher extends Dispatcher { - return { value: serializeResult(await this._frame._evaluateExpression(params.expression, params.isFunction, parseArgument(params.arg), params.world)) }; + return { value: serializeResult(await this._frame.evaluateExpressionAndWaitForSignals(params.expression, params.isFunction, parseArgument(params.arg), params.world)) }; } async evaluateExpressionHandle(params: channels.FrameEvaluateExpressionHandleParams, metadata: CallMetadata): Promise { - return { handle: createHandle(this._scope, await this._frame._evaluateExpressionHandle(params.expression, params.isFunction, parseArgument(params.arg), params.world)) }; + return { handle: createHandle(this._scope, await this._frame.evaluateExpressionHandleAndWaitForSignals(params.expression, params.isFunction, parseArgument(params.arg), params.world)) }; } async waitForSelector(params: channels.FrameWaitForSelectorParams, metadata: CallMetadata): Promise { diff --git a/src/dispatchers/jsHandleDispatcher.ts b/src/dispatchers/jsHandleDispatcher.ts index 0901af2971f46..65a48998d2577 100644 --- a/src/dispatchers/jsHandleDispatcher.ts +++ b/src/dispatchers/jsHandleDispatcher.ts @@ -31,11 +31,11 @@ export class JSHandleDispatcher extends Dispatcher { - return { value: serializeResult(await this._object._evaluateExpression(params.expression, params.isFunction, true /* returnByValue */, parseArgument(params.arg))) }; + return { value: serializeResult(await this._object.evaluateExpression(params.expression, params.isFunction, true /* returnByValue */, parseArgument(params.arg))) }; } async evaluateExpressionHandle(params: channels.JSHandleEvaluateExpressionHandleParams): Promise { - const jsHandle = await this._object._evaluateExpression(params.expression, params.isFunction, false /* returnByValue */, parseArgument(params.arg)); + const jsHandle = await this._object.evaluateExpression(params.expression, params.isFunction, false /* returnByValue */, parseArgument(params.arg)); return { handle: createHandle(this._scope, jsHandle) }; } diff --git a/src/server/browserContext.ts b/src/server/browserContext.ts index 3996bf5d5bfdd..3bd692204c262 100644 --- a/src/server/browserContext.ts +++ b/src/server/browserContext.ts @@ -316,7 +316,7 @@ export abstract class BrowserContext extends SdkObject { const originStorage: types.OriginStorage = { origin, localStorage: [] }; const frame = page.mainFrame(); await frame.goto(internalMetadata, origin); - const storage = await frame._evaluateExpression(`({ + const storage = await frame.evaluateExpression(`({ localStorage: Object.keys(localStorage).map(name => ({ name, value: localStorage.getItem(name) })), })`, false, undefined, 'utility'); originStorage.localStorage = storage.localStorage; @@ -340,7 +340,7 @@ export abstract class BrowserContext extends SdkObject { for (const originState of state.origins) { const frame = page.mainFrame(); await frame.goto(metadata, originState.origin); - await frame._evaluateExpression(` + await frame.evaluateExpression(` originState => { for (const { name, value } of (originState.localStorage || [])) localStorage.setItem(name, value); diff --git a/src/server/chromium/crPage.ts b/src/server/chromium/crPage.ts index c90b1bc1bf222..a9446ab1e8181 100644 --- a/src/server/chromium/crPage.ts +++ b/src/server/chromium/crPage.ts @@ -143,7 +143,7 @@ export class CRPage implements PageDelegate { async exposeBinding(binding: PageBinding) { await this._forAllFrameSessions(frame => frame._initBinding(binding)); - await Promise.all(this._page.frames().map(frame => frame._evaluateExpression(binding.source, false, {}, binding.world).catch(e => {}))); + await Promise.all(this._page.frames().map(frame => frame.evaluateExpression(binding.source, false, {}, binding.world).catch(e => {}))); } async updateExtraHTTPHeaders(): Promise { @@ -284,7 +284,7 @@ export class CRPage implements PageDelegate { } async setInputFiles(handle: dom.ElementHandle, files: types.FilePayload[]): Promise { - await handle._evaluateInUtility(([injected, node, files]) => + await handle.evaluateInUtility(([injected, node, files]) => injected.setInputFiles(node, files), files); } @@ -421,9 +421,9 @@ class FrameSession { worldName: UTILITY_WORLD_NAME, }); for (const binding of this._crPage._browserContext._pageBindings.values()) - frame._evaluateExpression(binding.source, false, undefined, binding.world).catch(e => {}); + frame.evaluateExpression(binding.source, false, undefined, binding.world).catch(e => {}); for (const source of this._crPage._browserContext._evaluateOnNewDocumentSources) - frame._evaluateExpression(source, false, undefined, 'main').catch(e => {}); + frame.evaluateExpression(source, false, undefined, 'main').catch(e => {}); } const isInitialEmptyPage = this._isMainFrame() && this._page.mainFrame().url() === ':'; if (isInitialEmptyPage) { diff --git a/src/server/dom.ts b/src/server/dom.ts index 72b151e52fd15..b7bb4dc469938 100644 --- a/src/server/dom.ts +++ b/src/server/dom.ts @@ -43,31 +43,33 @@ export class FrameExecutionContext extends js.ExecutionContext { return null; } - async evaluateInternal(pageFunction: js.Func0): Promise; - async evaluateInternal(pageFunction: js.Func1, arg: Arg): Promise; - async evaluateInternal(pageFunction: never, ...args: never[]): Promise { - return await this.frame._page._frameManager.waitForSignalsCreatedBy(null, false /* noWaitFor */, async () => { - return js.evaluate(this, true /* returnByValue */, pageFunction, ...args); - }); + async evaluate(pageFunction: js.Func1, arg?: Arg): Promise { + return js.evaluate(this, true /* returnByValue */, pageFunction, arg); + } + + async evaluateHandle(pageFunction: js.Func1, arg: Arg): Promise> { + return js.evaluate(this, false /* returnByValue */, pageFunction, arg); + } + + async evaluateExpression(expression: string, isFunction: boolean | undefined, arg?: any): Promise { + return js.evaluateExpression(this, true /* returnByValue */, expression, isFunction, arg); } - async evaluateExpressionInternal(expression: string, isFunction: boolean | undefined, ...args: any[]): Promise { + async evaluateAndWaitForSignals(pageFunction: js.Func1, arg?: Arg): Promise { return await this.frame._page._frameManager.waitForSignalsCreatedBy(null, false /* noWaitFor */, async () => { - return js.evaluateExpression(this, true /* returnByValue */, expression, isFunction, ...args); + return this.evaluate(pageFunction, arg); }); } - async evaluateHandleInternal(pageFunction: js.Func0): Promise>; - async evaluateHandleInternal(pageFunction: js.Func1, arg: Arg): Promise>; - async evaluateHandleInternal(pageFunction: never, ...args: never[]): Promise { + async evaluateExpressionAndWaitForSignals(expression: string, isFunction: boolean | undefined, arg?: any): Promise { return await this.frame._page._frameManager.waitForSignalsCreatedBy(null, false /* noWaitFor */, async () => { - return js.evaluate(this, false /* returnByValue */, pageFunction, ...args); + return this.evaluateExpression(expression, isFunction, arg); }); } - async evaluateExpressionHandleInternal(expression: string, isFunction: boolean | undefined, ...args: any[]): Promise { + async evaluateExpressionHandleAndWaitForSignals(expression: string, isFunction: boolean | undefined, arg: any): Promise { return await this.frame._page._frameManager.waitForSignalsCreatedBy(null, false /* noWaitFor */, async () => { - return js.evaluateExpression(this, false /* returnByValue */, expression, isFunction, ...args); + return js.evaluateExpression(this, false /* returnByValue */, expression, isFunction, arg); }); } @@ -124,19 +126,19 @@ export class ElementHandle extends js.JSHandle { return this; } - async _evaluateInMain(pageFunction: js.Func1<[js.JSHandle, ElementHandle, Arg], R>, arg: Arg): Promise { + private async _evaluateInMainAndWaitForSignals(pageFunction: js.Func1<[js.JSHandle, ElementHandle, Arg], R>, arg: Arg): Promise { const main = await this._context.frame._mainContext(); - return main.evaluateInternal(pageFunction, [await main.injectedScript(), this, arg]); + return main.evaluateAndWaitForSignals(pageFunction, [await main.injectedScript(), this, arg]); } - async _evaluateInUtility(pageFunction: js.Func1<[js.JSHandle, ElementHandle, Arg], R>, arg: Arg): Promise { + async evaluateInUtility(pageFunction: js.Func1<[js.JSHandle, ElementHandle, Arg], R>, arg: Arg): Promise { const utility = await this._context.frame._utilityContext(); - return utility.evaluateInternal(pageFunction, [await utility.injectedScript(), this, arg]); + return utility.evaluate(pageFunction, [await utility.injectedScript(), this, arg]); } - async _evaluateHandleInUtility(pageFunction: js.Func1<[js.JSHandle, ElementHandle, Arg], R>, arg: Arg): Promise> { + async evaluateHandleInUtility(pageFunction: js.Func1<[js.JSHandle, ElementHandle, Arg], R>, arg: Arg): Promise> { const utility = await this._context.frame._utilityContext(); - return utility.evaluateHandleInternal(pageFunction, [await utility.injectedScript(), this, arg]); + return utility.evaluateHandle(pageFunction, [await utility.injectedScript(), this, arg]); } async ownerFrame(): Promise { @@ -155,14 +157,14 @@ export class ElementHandle extends js.JSHandle { } async contentFrame(): Promise { - const isFrameElement = await this._evaluateInUtility(([injected, node]) => node && (node.nodeName === 'IFRAME' || node.nodeName === 'FRAME'), {}); + const isFrameElement = await this.evaluateInUtility(([injected, node]) => node && (node.nodeName === 'IFRAME' || node.nodeName === 'FRAME'), {}); if (!isFrameElement) return null; return this._page._delegate.getContentFrame(this); } async getAttribute(name: string): Promise { - return throwFatalDOMError(await this._evaluateInUtility(([injeced, node, name]) => { + return throwFatalDOMError(await this.evaluateInUtility(([injeced, node, name]) => { if (node.nodeType !== Node.ELEMENT_NODE) return 'error:notelement'; const element = node as unknown as Element; @@ -171,11 +173,11 @@ export class ElementHandle extends js.JSHandle { } async textContent(): Promise { - return this._evaluateInUtility(([injected, node]) => node.textContent, {}); + return this.evaluateInUtility(([injected, node]) => node.textContent, {}); } async innerText(): Promise { - return throwFatalDOMError(await this._evaluateInUtility(([injected, node]) => { + return throwFatalDOMError(await this.evaluateInUtility(([injected, node]) => { if (node.nodeType !== Node.ELEMENT_NODE) return 'error:notelement'; if (node.namespaceURI !== 'http://www.w3.org/1999/xhtml') @@ -186,7 +188,7 @@ export class ElementHandle extends js.JSHandle { } async innerHTML(): Promise { - return throwFatalDOMError(await this._evaluateInUtility(([injected, node]) => { + return throwFatalDOMError(await this.evaluateInUtility(([injected, node]) => { if (node.nodeType !== Node.ELEMENT_NODE) return 'error:notelement'; const element = node as unknown as Element; @@ -195,7 +197,7 @@ export class ElementHandle extends js.JSHandle { } async dispatchEvent(type: string, eventInit: Object = {}) { - await this._evaluateInMain(([injected, node, { type, eventInit }]) => + await this._evaluateInMainAndWaitForSignals(([injected, node, { type, eventInit }]) => injected.dispatchEvent(node, type, eventInit), { type, eventInit }); await this._page._doSlowMo(); } @@ -246,7 +248,7 @@ export class ElementHandle extends js.JSHandle { const [quads, metrics] = await Promise.all([ this._page._delegate.getContentQuads(this), - this._page.mainFrame()._utilityContext().then(utility => utility.evaluateInternal(() => ({width: innerWidth, height: innerHeight}))), + this._page.mainFrame()._utilityContext().then(utility => utility.evaluate(() => ({width: innerWidth, height: innerHeight}))), ] as const); if (!quads || !quads.length) return 'error:notvisible'; @@ -268,7 +270,7 @@ export class ElementHandle extends js.JSHandle { private async _offsetPoint(offset: types.Point): Promise { const [box, border] = await Promise.all([ this.boundingBox(), - this._evaluateInUtility(([injected, node]) => injected.getElementBorderWidth(node), {}).catch(e => {}), + this.evaluateInUtility(([injected, node]) => injected.getElementBorderWidth(node), {}).catch(e => {}), ]); if (!box || !border) return 'error:notvisible'; @@ -302,7 +304,7 @@ export class ElementHandle extends js.JSHandle { const timeout = waitTime[Math.min(retry - 1, waitTime.length - 1)]; if (timeout) { progress.log(` waiting ${timeout}ms`); - await this._evaluateInUtility(([injected, node, timeout]) => new Promise(f => setTimeout(f, timeout)), timeout); + await this.evaluateInUtility(([injected, node, timeout]) => new Promise(f => setTimeout(f, timeout)), timeout); } } else { progress.log(`attempting ${actionName} action`); @@ -348,7 +350,7 @@ export class ElementHandle extends js.JSHandle { progress.log(' scrolling into view if needed'); progress.throwIfAborted(); // Avoid action that has side-effects. if (forceScrollOptions) { - await this._evaluateInUtility(([injected, node, options]) => { + await this.evaluateInUtility(([injected, node, options]) => { if (node.nodeType === 1 /* Node.ELEMENT_NODE */) (node as Node as Element).scrollIntoView(options); }, forceScrollOptions); @@ -460,7 +462,7 @@ export class ElementHandle extends js.JSHandle { return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => { progress.throwIfAborted(); // Avoid action that has side-effects. progress.log(' selecting specified option(s)'); - const poll = await this._evaluateHandleInUtility(([injected, node, optionsToSelect]) => { + const poll = await this.evaluateHandleInUtility(([injected, node, optionsToSelect]) => { return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled'], injected.selectOptions.bind(injected, optionsToSelect)); }, optionsToSelect); const pollHandler = new InjectedScriptPollHandler(progress, poll); @@ -483,7 +485,7 @@ export class ElementHandle extends js.JSHandle { await progress.beforeInputAction(this); return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => { progress.log(' waiting for element to be visible, enabled and editable'); - const poll = await this._evaluateHandleInUtility(([injected, node, value]) => { + const poll = await this.evaluateHandleInUtility(([injected, node, value]) => { return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled', 'editable'], injected.fill.bind(injected, value)); }, value); const pollHandler = new InjectedScriptPollHandler(progress, poll); @@ -509,7 +511,7 @@ export class ElementHandle extends js.JSHandle { const controller = new ProgressController(metadata, this); return controller.run(async progress => { progress.throwIfAborted(); // Avoid action that has side-effects. - const poll = await this._evaluateHandleInUtility(([injected, node]) => { + const poll = await this.evaluateHandleInUtility(([injected, node]) => { return injected.waitForElementStatesAndPerformAction(node, ['visible'], injected.selectText.bind(injected)); }, {}); const pollHandler = new InjectedScriptPollHandler(progress, poll); @@ -527,7 +529,7 @@ export class ElementHandle extends js.JSHandle { } async _setInputFiles(progress: Progress, files: types.FilePayload[], options: types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> { - const multiple = throwFatalDOMError(await this._evaluateInUtility(([injected, node]): 'error:notinput' | 'error:notconnected' | boolean => { + const multiple = throwFatalDOMError(await this.evaluateInUtility(([injected, node]): 'error:notinput' | 'error:notconnected' | boolean => { if (node.nodeType !== Node.ELEMENT_NODE || (node as Node as Element).tagName !== 'INPUT') return 'error:notinput'; const input = node as Node as HTMLInputElement; @@ -556,7 +558,7 @@ export class ElementHandle extends js.JSHandle { async _focus(progress: Progress, resetSelectionIfNotFocused?: boolean): Promise<'error:notconnected' | 'done'> { progress.throwIfAborted(); // Avoid action that has side-effects. - const result = await this._evaluateInUtility(([injected, node, resetSelectionIfNotFocused]) => injected.focusNode(node, resetSelectionIfNotFocused), resetSelectionIfNotFocused); + const result = await this.evaluateInUtility(([injected, node, resetSelectionIfNotFocused]) => injected.focusNode(node, resetSelectionIfNotFocused), resetSelectionIfNotFocused); return throwFatalDOMError(result); } @@ -620,7 +622,7 @@ export class ElementHandle extends js.JSHandle { async _setChecked(progress: Progress, state: boolean, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> { const isChecked = async () => { - const result = await this._evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'checked'), {}); + const result = await this.evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'checked'), {}); return throwRetargetableDOMError(throwFatalDOMError(result)); }; if (await isChecked() === state) @@ -652,49 +654,49 @@ export class ElementHandle extends js.JSHandle { return this._page.selectors._queryAll(this._context.frame, selector, this, true /* adoptToMain */); } - async _$evalExpression(selector: string, expression: string, isFunction: boolean | undefined, arg: any): Promise { + async $evalExpression(selector: string, expression: string, isFunction: boolean | undefined, arg: any): Promise { const handle = await this._page.selectors._query(this._context.frame, selector, this); if (!handle) throw new Error(`Error: failed to find element matching selector "${selector}"`); - const result = await handle._evaluateExpression(expression, isFunction, true, arg); + const result = await handle.evaluateExpression(expression, isFunction, true, arg); handle.dispose(); return result; } - async _$$evalExpression(selector: string, expression: string, isFunction: boolean | undefined, arg: any): Promise { + async $$evalExpression(selector: string, expression: string, isFunction: boolean | undefined, arg: any): Promise { const arrayHandle = await this._page.selectors._queryArray(this._context.frame, selector, this); - const result = await arrayHandle._evaluateExpression(expression, isFunction, true, arg); + const result = await arrayHandle.evaluateExpression(expression, isFunction, true, arg); arrayHandle.dispose(); return result; } async isVisible(): Promise { - const result = await this._evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'visible'), {}); + const result = await this.evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'visible'), {}); return throwRetargetableDOMError(throwFatalDOMError(result)); } async isHidden(): Promise { - const result = await this._evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'hidden'), {}); + const result = await this.evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'hidden'), {}); return throwRetargetableDOMError(throwFatalDOMError(result)); } async isEnabled(): Promise { - const result = await this._evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'enabled'), {}); + const result = await this.evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'enabled'), {}); return throwRetargetableDOMError(throwFatalDOMError(result)); } async isDisabled(): Promise { - const result = await this._evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'disabled'), {}); + const result = await this.evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'disabled'), {}); return throwRetargetableDOMError(throwFatalDOMError(result)); } async isEditable(): Promise { - const result = await this._evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'editable'), {}); + const result = await this.evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'editable'), {}); return throwRetargetableDOMError(throwFatalDOMError(result)); } async isChecked(): Promise { - const result = await this._evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'checked'), {}); + const result = await this.evaluateInUtility(([injected, node]) => injected.checkElementState(node, 'checked'), {}); return throwRetargetableDOMError(throwFatalDOMError(result)); } @@ -702,7 +704,7 @@ export class ElementHandle extends js.JSHandle { const controller = new ProgressController(metadata, this); return controller.run(async progress => { progress.log(` waiting for element to be ${state}`); - const poll = await this._evaluateHandleInUtility(([injected, node, state]) => { + const poll = await this.evaluateHandleInUtility(([injected, node, state]) => { return injected.waitForElementStatesAndPerformAction(node, [state], () => 'done' as const); }, state); const pollHandler = new InjectedScriptPollHandler(progress, poll); @@ -746,7 +748,7 @@ export class ElementHandle extends js.JSHandle { progress.log(` waiting for element to be visible, enabled and stable`); else progress.log(` waiting for element to be visible and stable`); - const poll = this._evaluateHandleInUtility(([injected, node, waitForEnabled]) => { + const poll = this.evaluateHandleInUtility(([injected, node, waitForEnabled]) => { return injected.waitForElementStatesAndPerformAction(node, waitForEnabled ? ['visible', 'stable', 'enabled'] : ['visible', 'stable'], () => 'done' as const); }, waitForEnabled); @@ -769,7 +771,7 @@ export class ElementHandle extends js.JSHandle { // Translate from viewport coordinates to frame coordinates. point = { x: point.x - box.x, y: point.y - box.y }; } - return this._evaluateInUtility(([injected, node, point]) => injected.checkHitTargetAt(node, point), point); + return this.evaluateInUtility(([injected, node, point]) => injected.checkHitTargetAt(node, point), point); } } diff --git a/src/server/firefox/ffPage.ts b/src/server/firefox/ffPage.ts index 46352eaa1b058..1889d32319ecb 100644 --- a/src/server/firefox/ffPage.ts +++ b/src/server/firefox/ffPage.ts @@ -389,7 +389,7 @@ export class FFPage implements PageDelegate { async takeScreenshot(format: 'png' | 'jpeg', documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined): Promise { if (!documentRect) { const context = await this._page.mainFrame()._utilityContext(); - const scrollOffset = await context.evaluateInternal(() => ({ x: window.scrollX, y: window.scrollY })); + const scrollOffset = await context.evaluate(() => ({ x: window.scrollX, y: window.scrollY })); documentRect = { x: viewportRect!.x + scrollOffset.x, y: viewportRect!.y + scrollOffset.y, @@ -484,7 +484,7 @@ export class FFPage implements PageDelegate { } async setInputFiles(handle: dom.ElementHandle, files: types.FilePayload[]): Promise { - await handle._evaluateInUtility(([injected, node, files]) => + await handle.evaluateInUtility(([injected, node, files]) => injected.setInputFiles(node, files), files); } diff --git a/src/server/frames.ts b/src/server/frames.ts index 6b1ccaf8bb8ce..08fd97c5a0fc8 100644 --- a/src/server/frames.ts +++ b/src/server/frames.ts @@ -593,17 +593,25 @@ export class Frame extends SdkObject { return this._context('utility'); } - async _evaluateExpressionHandle(expression: string, isFunction: boolean | undefined, arg: any, world: types.World = 'main'): Promise { + async evaluateExpressionHandleAndWaitForSignals(expression: string, isFunction: boolean | undefined, arg: any, world: types.World = 'main'): Promise { const context = await this._context(world); - const handle = await context.evaluateExpressionHandleInternal(expression, isFunction, arg); + const handle = await context.evaluateExpressionHandleAndWaitForSignals(expression, isFunction, arg); if (world === 'main') await this._page._doSlowMo(); return handle; } - async _evaluateExpression(expression: string, isFunction: boolean | undefined, arg: any, world: types.World = 'main'): Promise { + async evaluateExpression(expression: string, isFunction: boolean | undefined, arg: any, world: types.World = 'main'): Promise { const context = await this._context(world); - const value = await context.evaluateExpressionInternal(expression, isFunction, arg); + const value = await context.evaluateExpression(expression, isFunction, arg); + if (world === 'main') + await this._page._doSlowMo(); + return value; + } + + async evaluateExpressionAndWaitForSignals(expression: string, isFunction: boolean | undefined, arg: any, world: types.World = 'main'): Promise { + const context = await this._context(world); + const value = await context.evaluateExpressionAndWaitForSignals(expression, isFunction, arg); if (world === 'main') await this._page._doSlowMo(); return value; @@ -652,14 +660,14 @@ export class Frame extends SdkObject { const handle = await this.$(selector); if (!handle) throw new Error(`Error: failed to find element matching selector "${selector}"`); - const result = await handle._evaluateExpression(expression, isFunction, true, arg); + const result = await handle.evaluateExpression(expression, isFunction, true, arg); handle.dispose(); return result; } async _$$evalExpression(selector: string, expression: string, isFunction: boolean | undefined, arg: any): Promise { const arrayHandle = await this._page.selectors._queryArray(this, selector); - const result = await arrayHandle._evaluateExpression(expression, isFunction, true, arg); + const result = await arrayHandle.evaluateExpression(expression, isFunction, true, arg); arrayHandle.dispose(); return result; } @@ -670,7 +678,7 @@ export class Frame extends SdkObject { async content(): Promise { const context = await this._utilityContext(); - return context.evaluateInternal(() => { + return context.evaluate(() => { let retVal = ''; if (document.doctype) retVal = new XMLSerializer().serializeToString(document.doctype); @@ -694,7 +702,7 @@ export class Frame extends SdkObject { this._waitForLoadState(progress, waitUntil).then(resolve).catch(reject); }); }); - const contentPromise = context.evaluateInternal(({ html, tag }) => { + const contentPromise = context.evaluate(({ html, tag }) => { window.stop(); document.open(); console.debug(tag); // eslint-disable-line no-console @@ -738,12 +746,12 @@ export class Frame extends SdkObject { const context = await this._mainContext(); return this._raceWithCSPError(async () => { if (url !== null) - return (await context.evaluateHandleInternal(addScriptUrl, { url, type })).asElement()!; - const result = (await context.evaluateHandleInternal(addScriptContent, { content: content!, type })).asElement()!; + return (await context.evaluateHandle(addScriptUrl, { url, type })).asElement()!; + const result = (await context.evaluateHandle(addScriptContent, { content: content!, type })).asElement()!; // Another round trip to the browser to ensure that we receive CSP error messages // (if any) logged asynchronously in a separate task on the content main thread. if (this._page._delegate.cspErrorsAsynchronousForInlineScipts) - await context.evaluateInternal(() => true); + await context.evaluate(() => true); return result; }); @@ -785,8 +793,8 @@ export class Frame extends SdkObject { const context = await this._mainContext(); return this._raceWithCSPError(async () => { if (url !== null) - return (await context.evaluateHandleInternal(addStyleUrl, url)).asElement()!; - return (await context.evaluateHandleInternal(addStyleContent, content!)).asElement()!; + return (await context.evaluateHandle(addStyleUrl, url)).asElement()!; + return (await context.evaluateHandle(addStyleContent, content!)).asElement()!; }); async function addStyleUrl(url: string): Promise { @@ -1075,7 +1083,7 @@ export class Frame extends SdkObject { async title(): Promise { const context = await this._utilityContext(); - return context.evaluateInternal(() => document.title); + return context.evaluate(() => document.title); } _onDetached() { diff --git a/src/server/javascript.ts b/src/server/javascript.ts index 22cff825b252d..7687cdd1d3359 100644 --- a/src/server/javascript.ts +++ b/src/server/javascript.ts @@ -114,19 +114,15 @@ export class JSHandle extends SdkObject { this._context._delegate.rawCallFunctionNoReply(func, this, arg); } - async evaluate(pageFunction: FuncOn, arg: Arg): Promise; - async evaluate(pageFunction: FuncOn, arg?: any): Promise; - async evaluate(pageFunction: FuncOn, arg: Arg): Promise { + async evaluate(pageFunction: FuncOn, arg?: Arg): Promise { return evaluate(this._context, true /* returnByValue */, pageFunction, this, arg); } - async evaluateHandle(pageFunction: FuncOn, arg: Arg): Promise>; - async evaluateHandle(pageFunction: FuncOn, arg?: any): Promise>; - async evaluateHandle(pageFunction: FuncOn, arg: Arg): Promise> { + async evaluateHandle(pageFunction: FuncOn, arg?: Arg): Promise> { return evaluate(this._context, false /* returnByValue */, pageFunction, this, arg); } - async _evaluateExpression(expression: string, isFunction: boolean | undefined, returnByValue: boolean, arg: any) { + async evaluateExpression(expression: string, isFunction: boolean | undefined, returnByValue: boolean, arg: any) { const value = await evaluateExpression(this._context, returnByValue, expression, isFunction, this, arg); await this._context.doSlowMo(); return value; diff --git a/src/server/page.ts b/src/server/page.ts index 1d6c91709b64d..16d5738ef9d5c 100644 --- a/src/server/page.ts +++ b/src/server/page.ts @@ -563,17 +563,17 @@ export class PageBinding { const binding = page.getBinding(name, context.world)!; let result: any; if (binding.needsHandle) { - const handle = await context.evaluateHandleInternal(takeHandle, { name, seq }).catch(e => null); + const handle = await context.evaluateHandle(takeHandle, { name, seq }).catch(e => null); result = await binding.playwrightFunction({ frame: context.frame, page, context: page._browserContext }, handle); } else { result = await binding.playwrightFunction({ frame: context.frame, page, context: page._browserContext }, ...args); } - context.evaluateInternal(deliverResult, { name, seq, result }).catch(e => debugLogger.log('error', e)); + context.evaluate(deliverResult, { name, seq, result }).catch(e => debugLogger.log('error', e)); } catch (error) { if (isError(error)) - context.evaluateInternal(deliverError, { name, seq, message: error.message, stack: error.stack }).catch(e => debugLogger.log('error', e)); + context.evaluate(deliverError, { name, seq, message: error.message, stack: error.stack }).catch(e => debugLogger.log('error', e)); else - context.evaluateInternal(deliverErrorValue, { name, seq, error }).catch(e => debugLogger.log('error', e)); + context.evaluate(deliverErrorValue, { name, seq, error }).catch(e => debugLogger.log('error', e)); } function takeHandle(arg: { name: string, seq: number }) { diff --git a/src/server/screenshotter.ts b/src/server/screenshotter.ts index 19a3aaaa63114..e6212b5300c42 100644 --- a/src/server/screenshotter.ts +++ b/src/server/screenshotter.ts @@ -37,14 +37,14 @@ export class Screenshotter { let viewportSize = originalViewportSize; if (!viewportSize) { const context = await this._page.mainFrame()._utilityContext(); - viewportSize = await context.evaluateInternal(() => ({ width: window.innerWidth, height: window.innerHeight })); + viewportSize = await context.evaluate(() => ({ width: window.innerWidth, height: window.innerHeight })); } return { viewportSize, originalViewportSize }; } private async _fullPageSize(): Promise { const context = await this._page.mainFrame()._utilityContext(); - const fullPageSize = await context.evaluateInternal(() => { + const fullPageSize = await context.evaluate(() => { if (!document.body || !document.documentElement) return null; return { @@ -125,7 +125,7 @@ export class Screenshotter { } const context = await this._page.mainFrame()._utilityContext(); - const scrollOffset = await context.evaluateInternal(() => ({ x: window.scrollX, y: window.scrollY })); + const scrollOffset = await context.evaluate(() => ({ x: window.scrollX, y: window.scrollY })); const documentRect = { ...boundingBox }; documentRect.x += scrollOffset.x; documentRect.y += scrollOffset.y; diff --git a/src/server/snapshot/snapshotter.ts b/src/server/snapshot/snapshotter.ts index 782bbf3bdd142..c87d75e379699 100644 --- a/src/server/snapshot/snapshotter.ts +++ b/src/server/snapshot/snapshotter.ts @@ -185,7 +185,7 @@ export class Snapshotter { async function setIntervalInFrame(frame: Frame, interval: number) { const context = frame._existingMainContext(); - await context?.evaluateInternal(({ kSnapshotStreamer, interval }) => { + await context?.evaluate(({ kSnapshotStreamer, interval }) => { (window as any)[kSnapshotStreamer].setSnapshotInterval(interval); }, { kSnapshotStreamer, interval }).catch(debugExceptionHandler); } @@ -197,7 +197,7 @@ async function annotateFrameHierarchy(frame: Frame) { if (!parent) return; const context = await parent._mainContext(); - await context?.evaluateInternal(({ kSnapshotStreamer, frameElement, frameId }) => { + await context?.evaluate(({ kSnapshotStreamer, frameElement, frameId }) => { (window as any)[kSnapshotStreamer].markIframe(frameElement, frameId); }, { kSnapshotStreamer, frameElement, frameId: frame.uniqueId }); frameElement.dispose(); diff --git a/src/server/supplements/har/harTracer.ts b/src/server/supplements/har/harTracer.ts index 5a5391ee4dbd2..f644255bff233 100644 --- a/src/server/supplements/har/harTracer.ts +++ b/src/server/supplements/har/harTracer.ts @@ -91,7 +91,7 @@ class HarContextTracer { page.on(Page.Events.Response, (response: network.Response) => this._onResponse(page, response)); page.on(Page.Events.DOMContentLoaded, () => { - const promise = page.mainFrame()._evaluateExpression(String(() => { + const promise = page.mainFrame().evaluateExpression(String(() => { return { title: document.title, domContentLoaded: performance.timing.domContentLoadedEventStart, @@ -103,7 +103,7 @@ class HarContextTracer { this._addBarrier(page, promise); }); page.on(Page.Events.Load, () => { - const promise = page.mainFrame()._evaluateExpression(String(() => { + const promise = page.mainFrame().evaluateExpression(String(() => { return { title: document.title, loaded: performance.timing.loadEventStart, @@ -118,7 +118,7 @@ class HarContextTracer { private _addBarrier(page: Page, promise: Promise) { const race = Promise.race([ - new Promise(f => page.on('close', () => { + new Promise(f => page.on('close', () => { this._barrierPromises.delete(race); f(); })), diff --git a/src/server/supplements/recorder/recorderApp.ts b/src/server/supplements/recorder/recorderApp.ts index fd58fe831a34b..f44d463766dd6 100644 --- a/src/server/supplements/recorder/recorderApp.ts +++ b/src/server/supplements/recorder/recorderApp.ts @@ -121,25 +121,25 @@ export class RecorderApp extends EventEmitter { } async setMode(mode: 'none' | 'recording' | 'inspecting'): Promise { - await this._page.mainFrame()._evaluateExpression(((mode: Mode) => { + await this._page.mainFrame().evaluateExpression(((mode: Mode) => { window.playwrightSetMode(mode); }).toString(), true, mode, 'main').catch(() => {}); } async setFile(file: string): Promise { - await this._page.mainFrame()._evaluateExpression(((file: string) => { + await this._page.mainFrame().evaluateExpression(((file: string) => { window.playwrightSetFile(file); }).toString(), true, file, 'main').catch(() => {}); } async setPaused(paused: boolean): Promise { - await this._page.mainFrame()._evaluateExpression(((paused: boolean) => { + await this._page.mainFrame().evaluateExpression(((paused: boolean) => { window.playwrightSetPaused(paused); }).toString(), true, paused, 'main').catch(() => {}); } async setSources(sources: Source[]): Promise { - await this._page.mainFrame()._evaluateExpression(((sources: Source[]) => { + await this._page.mainFrame().evaluateExpression(((sources: Source[]) => { window.playwrightSetSources(sources); }).toString(), true, sources, 'main').catch(() => {}); @@ -154,13 +154,13 @@ export class RecorderApp extends EventEmitter { } async setSelector(selector: string, focus?: boolean): Promise { - await this._page.mainFrame()._evaluateExpression(((arg: any) => { + await this._page.mainFrame().evaluateExpression(((arg: any) => { window.playwrightSetSelector(arg.selector, arg.focus); }).toString(), true, { selector, focus }, 'main').catch(() => {}); } async updateCallLogs(callLogs: CallLog[]): Promise { - await this._page.mainFrame()._evaluateExpression(((callLogs: CallLog[]) => { + await this._page.mainFrame().evaluateExpression(((callLogs: CallLog[]) => { window.playwrightUpdateLogs(callLogs); }).toString(), true, callLogs, 'main').catch(() => {}); } diff --git a/src/server/supplements/recorderSupplement.ts b/src/server/supplements/recorderSupplement.ts index 5f742a3f6e4e4..ec3c3e4fe5799 100644 --- a/src/server/supplements/recorderSupplement.ts +++ b/src/server/supplements/recorderSupplement.ts @@ -284,7 +284,7 @@ export class RecorderSupplement { private _refreshOverlay() { for (const page of this._context.pages()) - page.mainFrame()._evaluateExpression('window._playwrightRefreshOverlay()', false, undefined, 'main').catch(() => {}); + page.mainFrame().evaluateExpression('window._playwrightRefreshOverlay()', false, undefined, 'main').catch(() => {}); } private async _onPage(page: Page) { diff --git a/src/server/webkit/wkPage.ts b/src/server/webkit/wkPage.ts index 2a3169e60bd94..c3610a7a5d814 100644 --- a/src/server/webkit/wkPage.ts +++ b/src/server/webkit/wkPage.ts @@ -178,7 +178,7 @@ export class WKPage implements PageDelegate { promises.push(WKPage._setEmulateMedia(session, this._page._state.mediaType, this._page._state.colorScheme)); const bootstrapScript = this._calculateBootstrapScript(); promises.push(session.send('Page.setBootstrapScript', { source: bootstrapScript })); - this._page.frames().map(frame => frame._evaluateExpression(bootstrapScript, false, undefined, 'main').catch(e => {})); + this._page.frames().map(frame => frame.evaluateExpression(bootstrapScript, false, undefined, 'main').catch(e => {})); if (contextOptions.bypassCSP) promises.push(session.send('Page.setBypassCSP', { enabled: true })); if (this._page._state.viewportSize) { @@ -699,7 +699,7 @@ export class WKPage implements PageDelegate { if (binding.world !== 'main') throw new Error('Only main context bindings are supported in WebKit.'); const script = this._bindingToScript(binding); - await Promise.all(this._page.frames().map(frame => frame._evaluateExpression(script, false, {}).catch(e => {}))); + await Promise.all(this._page.frames().map(frame => frame.evaluateExpression(script, false, {}).catch(e => {}))); } async evaluateOnNewDocument(script: string): Promise { diff --git a/test/page-expose-function.spec.ts b/test/page-expose-function.spec.ts index 2ec829d562308..1b570c550066e 100644 --- a/test/page-expose-function.spec.ts +++ b/test/page-expose-function.spec.ts @@ -246,22 +246,22 @@ it('should work with internal bindings', (test, { mode, browserName }) => { foo = arg; }, 'utility'); expect(await page.evaluate('!!window.foo')).toBe(false); - expect(await implPage.mainFrame()._evaluateExpression('!!window.foo', false, {}, 'utility')).toBe(true); + expect(await implPage.mainFrame().evaluateExpression('!!window.foo', false, {}, 'utility')).toBe(true); expect(foo).toBe(undefined); - await implPage.mainFrame()._evaluateExpression('window.foo(123)', false, {}, 'utility'); + await implPage.mainFrame().evaluateExpression('window.foo(123)', false, {}, 'utility'); expect(foo).toBe(123); // should work after reload await page.goto(server.EMPTY_PAGE); expect(await page.evaluate('!!window.foo')).toBe(false); - await implPage.mainFrame()._evaluateExpression('window.foo(456)', false, {}, 'utility'); + await implPage.mainFrame().evaluateExpression('window.foo(456)', false, {}, 'utility'); expect(foo).toBe(456); // should work inside frames const frame = await attachFrame(page, 'myframe', server.CROSS_PROCESS_PREFIX + '/empty.html'); expect(await frame.evaluate('!!window.foo')).toBe(false); const implFrame: import('../src/server/frames').Frame = toImpl(frame); - await implFrame._evaluateExpression('window.foo(789)', false, {}, 'utility'); + await implFrame.evaluateExpression('window.foo(789)', false, {}, 'utility'); expect(foo).toBe(789); });