diff --git a/src/page.ts b/src/page.ts index a810fe4d26..9b3645599d 100644 --- a/src/page.ts +++ b/src/page.ts @@ -686,36 +686,34 @@ export class PageBinding { static async dispatch(page: Page, payload: string, context: dom.FrameExecutionContext) { const {name, seq, args} = JSON.parse(payload); - let expression = null; try { let binding = page._pageBindings.get(name); if (!binding) binding = page._browserContext._pageBindings.get(name); const result = await binding!.playwrightFunction({ frame: context.frame, page, context: page._browserContext }, ...args); - expression = helper.evaluationString(deliverResult, name, seq, result); + context.evaluateInternal(deliverResult, { name, seq, result }).catch(logError(page._logger)); } catch (error) { if (error instanceof Error) - expression = helper.evaluationString(deliverError, name, seq, error.message, error.stack); + context.evaluateInternal(deliverError, { name, seq, message: error.message, stack: error.stack }).catch(logError(page._logger)); else - expression = helper.evaluationString(deliverErrorValue, name, seq, error); - } - context.evaluateInternal(expression).catch(logError(page._logger)); - - function deliverResult(name: string, seq: number, result: any) { - (window as any)[name]['callbacks'].get(seq).resolve(result); - (window as any)[name]['callbacks'].delete(seq); + context.evaluateInternal(deliverErrorValue, { name, seq, error }).catch(logError(page._logger)); } - function deliverError(name: string, seq: number, message: string, stack: string) { - const error = new Error(message); - error.stack = stack; - (window as any)[name]['callbacks'].get(seq).reject(error); - (window as any)[name]['callbacks'].delete(seq); + function deliverResult(arg: { name: string, seq: number, result: any }) { + (window as any)[arg.name]['callbacks'].get(arg.seq).resolve(arg.result); + (window as any)[arg.name]['callbacks'].delete(arg.seq); } - function deliverErrorValue(name: string, seq: number, value: any) { - (window as any)[name]['callbacks'].get(seq).reject(value); - (window as any)[name]['callbacks'].delete(seq); + function deliverError(arg: { name: string, seq: number, message: string, stack: string | undefined }) { + const error = new Error(arg.message); + error.stack = arg.stack; + (window as any)[arg.name]['callbacks'].get(arg.seq).reject(error); + (window as any)[arg.name]['callbacks'].delete(arg.seq); + } + + function deliverErrorValue(arg: { name: string, seq: number, error: any }) { + (window as any)[arg.name]['callbacks'].get(arg.seq).reject(arg.error); + (window as any)[arg.name]['callbacks'].delete(arg.seq); } } } diff --git a/src/rpc/client/page.ts b/src/rpc/client/page.ts index e9fb8026c1..d1f8946a06 100644 --- a/src/rpc/client/page.ts +++ b/src/rpc/client/page.ts @@ -32,7 +32,7 @@ import { ElementHandle } from './elementHandle'; import { Worker } from './worker'; import { Frame, FunctionWithSource, GotoOptions } from './frame'; import { Keyboard, Mouse } from './input'; -import { Func1, FuncOn, SmartHandle } from './jsHandle'; +import { Func1, FuncOn, SmartHandle, serializeArgument } from './jsHandle'; import { Request, Response, Route, RouteHandler } from './network'; import { FileChooser } from './fileChooser'; import { Buffer } from 'buffer'; @@ -535,7 +535,8 @@ export class BindingCall extends ChannelOwner { const page = await context.newPage(); await page.exposeFunction('mul', (a, b) => a * b); await context.exposeFunction('sub', (a, b) => a - b); - const result = await page.evaluate(async function() { - return { mul: await mul(9, 4), add: await add(9, 4), sub: await sub(9, 4) }; + await context.exposeBinding('addHandle', async ({ frame }, a, b) => { + const handle = await frame.evaluateHandle(([a, b]) => a + b, [a, b]); + return handle; }); - expect(result).toEqual({ mul: 36, add: 13, sub: 5 }); + const result = await page.evaluate(async function() { + return { mul: await mul(9, 4), add: await add(9, 4), sub: await sub(9, 4), addHandle: await addHandle(5, 6) }; + }); + expect(result).toEqual({ mul: 36, add: 13, sub: 5, addHandle: 11 }); await context.close(); }); it('should throw for duplicate registrations', async({browser, server}) => { diff --git a/test/page.spec.js b/test/page.spec.js index 41ba6c2392..d4333ffb82 100644 --- a/test/page.spec.js +++ b/test/page.spec.js @@ -467,6 +467,21 @@ describe('Page.exposeFunction', function() { }); expect(result).toBe(36); }); + it('should work with handles and complex objects', async({page, server}) => { + const fooHandle = await page.evaluateHandle(() => { + window.fooValue = { bar: 2 }; + return window.fooValue; + }); + await page.exposeFunction('handle', () => { + return [{ foo: fooHandle }]; + }); + const equals = await page.evaluate(async function() { + const value = await handle(); + const [{ foo }] = value; + return foo === window.fooValue; + }); + expect(equals).toBe(true); + }); it('should throw exception in page context', async({page, server}) => { await page.exposeFunction('woof', function() { throw new Error('WOOF WOOF');