chore(rpc): serialize rpc into actual wire string (#2740)
This commit is contained in:
parent
3e33523ee3
commit
4e94bdabfd
26
src/dom.ts
26
src/dom.ts
|
|
@ -14,10 +14,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as mime from 'mime';
|
|
||||||
import * as path from 'path';
|
|
||||||
import * as util from 'util';
|
|
||||||
import * as frames from './frames';
|
import * as frames from './frames';
|
||||||
import { assert, helper, assertMaxArguments } from './helper';
|
import { assert, helper, assertMaxArguments } from './helper';
|
||||||
import InjectedScript from './injected/injectedScript';
|
import InjectedScript from './injected/injectedScript';
|
||||||
|
|
@ -30,6 +26,7 @@ import * as types from './types';
|
||||||
import { Progress } from './progress';
|
import { Progress } from './progress';
|
||||||
import DebugScript from './debug/injected/debugScript';
|
import DebugScript from './debug/injected/debugScript';
|
||||||
import { FatalDOMError, RetargetableDOMError } from './common/domErrors';
|
import { FatalDOMError, RetargetableDOMError } from './common/domErrors';
|
||||||
|
import { normalizeFilePayloads } from './rpc/serializers';
|
||||||
|
|
||||||
export class FrameExecutionContext extends js.ExecutionContext {
|
export class FrameExecutionContext extends js.ExecutionContext {
|
||||||
readonly frame: frames.Frame;
|
readonly frame: frames.Frame;
|
||||||
|
|
@ -504,25 +501,8 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
}, {}));
|
}, {}));
|
||||||
if (typeof multiple === 'string')
|
if (typeof multiple === 'string')
|
||||||
return multiple;
|
return multiple;
|
||||||
let ff: string[] | types.FilePayload[];
|
const filePayloads = await normalizeFilePayloads(files);
|
||||||
if (!Array.isArray(files))
|
assert(multiple || filePayloads.length <= 1, 'Non-multiple file input can only accept single file!');
|
||||||
ff = [ files ] as string[] | types.FilePayload[];
|
|
||||||
else
|
|
||||||
ff = files;
|
|
||||||
assert(multiple || ff.length <= 1, 'Non-multiple file input can only accept single file!');
|
|
||||||
const filePayloads: types.FilePayload[] = [];
|
|
||||||
for (const item of ff) {
|
|
||||||
if (typeof item === 'string') {
|
|
||||||
const file: types.FilePayload = {
|
|
||||||
name: path.basename(item),
|
|
||||||
mimeType: mime.getType(item) || 'application/octet-stream',
|
|
||||||
buffer: await util.promisify(fs.readFile)(item)
|
|
||||||
};
|
|
||||||
filePayloads.push(file);
|
|
||||||
} else {
|
|
||||||
filePayloads.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
await this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {
|
||||||
progress.throwIfAborted(); // Avoid action that has side-effects.
|
progress.throwIfAborted(); // Avoid action that has side-effects.
|
||||||
await this._page._delegate.setInputFiles(this as any as ElementHandle<HTMLInputElement>, filePayloads);
|
await this._page._delegate.setInputFiles(this as any as ElementHandle<HTMLInputElement>, filePayloads);
|
||||||
|
|
|
||||||
|
|
@ -362,21 +362,6 @@ export function logPolitely(toBeLogged: string) {
|
||||||
console.log(toBeLogged); // eslint-disable-line no-console
|
console.log(toBeLogged); // eslint-disable-line no-console
|
||||||
}
|
}
|
||||||
|
|
||||||
export function serializeError(e: any): types.Error {
|
|
||||||
if (e instanceof Error)
|
|
||||||
return { message: e.message, stack: e.stack };
|
|
||||||
return { value: e };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseError(error: types.Error): any {
|
|
||||||
if (error.message !== undefined) {
|
|
||||||
const e = new Error(error.message);
|
|
||||||
e.stack = error.stack;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
return error.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const escapeGlobChars = new Set(['/', '$', '^', '+', '.', '(', ')', '=', '!', '|']);
|
const escapeGlobChars = new Set(['/', '$', '^', '+', '.', '(', ')', '=', '!', '|']);
|
||||||
|
|
||||||
export const helper = Helper;
|
export const helper = Helper;
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ export interface PageChannel extends Channel {
|
||||||
goForward(params: { options?: types.NavigateOptions }): Promise<ResponseChannel | null>;
|
goForward(params: { options?: types.NavigateOptions }): Promise<ResponseChannel | null>;
|
||||||
opener(): Promise<PageChannel | null>;
|
opener(): Promise<PageChannel | null>;
|
||||||
reload(params: { options?: types.NavigateOptions }): Promise<ResponseChannel | null>;
|
reload(params: { options?: types.NavigateOptions }): Promise<ResponseChannel | null>;
|
||||||
screenshot(params: { options?: types.ScreenshotOptions }): Promise<Buffer>;
|
screenshot(params: { options?: types.ScreenshotOptions }): Promise<string>;
|
||||||
setExtraHTTPHeaders(params: { headers: types.Headers }): Promise<void>;
|
setExtraHTTPHeaders(params: { headers: types.Headers }): Promise<void>;
|
||||||
setNetworkInterceptionEnabled(params: { enabled: boolean }): Promise<void>;
|
setNetworkInterceptionEnabled(params: { enabled: boolean }): Promise<void>;
|
||||||
setViewportSize(params: { viewportSize: types.Size }): Promise<void>;
|
setViewportSize(params: { viewportSize: types.Size }): Promise<void>;
|
||||||
|
|
@ -151,7 +151,7 @@ export interface FrameChannel extends Channel {
|
||||||
querySelectorAll(params: { selector: string }): Promise<ElementHandleChannel[]>;
|
querySelectorAll(params: { selector: string }): Promise<ElementHandleChannel[]>;
|
||||||
selectOption(params: { selector: string, values: string | ElementHandleChannel | types.SelectOption | string[] | ElementHandleChannel[] | types.SelectOption[] | null, options: types.NavigatingActionWaitOptions }): Promise<string[]>;
|
selectOption(params: { selector: string, values: string | ElementHandleChannel | types.SelectOption | string[] | ElementHandleChannel[] | types.SelectOption[] | null, options: types.NavigatingActionWaitOptions }): Promise<string[]>;
|
||||||
setContent(params: { html: string, options: types.NavigateOptions }): Promise<void>;
|
setContent(params: { html: string, options: types.NavigateOptions }): Promise<void>;
|
||||||
setInputFiles(params: { selector: string, files: string | string[] | types.FilePayload | types.FilePayload[], options: types.NavigatingActionWaitOptions }): Promise<void>;
|
setInputFiles(params: { selector: string, files: { name: string, mimeType: string, buffer: string }[], options: types.NavigatingActionWaitOptions }): Promise<void>;
|
||||||
textContent(params: { selector: string, options: types.TimeoutOptions }): Promise<string | null>;
|
textContent(params: { selector: string, options: types.TimeoutOptions }): Promise<string | null>;
|
||||||
title(): Promise<string>;
|
title(): Promise<string>;
|
||||||
type(params: { selector: string, text: string, options: { delay?: number | undefined } & types.TimeoutOptions & { noWaitAfter?: boolean } }): Promise<void>;
|
type(params: { selector: string, text: string, options: { delay?: number | undefined } & types.TimeoutOptions & { noWaitAfter?: boolean } }): Promise<void>;
|
||||||
|
|
@ -199,7 +199,7 @@ export interface ElementHandleChannel extends JSHandleChannel {
|
||||||
press(params: { key: string; options?: { delay?: number } & types.TimeoutOptions & { noWaitAfter?: boolean } }): Promise<void>;
|
press(params: { key: string; options?: { delay?: number } & types.TimeoutOptions & { noWaitAfter?: boolean } }): Promise<void>;
|
||||||
querySelector(params: { selector: string }): Promise<ElementHandleChannel | null>;
|
querySelector(params: { selector: string }): Promise<ElementHandleChannel | null>;
|
||||||
querySelectorAll(params: { selector: string }): Promise<ElementHandleChannel[]>;
|
querySelectorAll(params: { selector: string }): Promise<ElementHandleChannel[]>;
|
||||||
screenshot(params: { options?: types.ElementScreenshotOptions }): Promise<Buffer>;
|
screenshot(params: { options?: types.ElementScreenshotOptions }): Promise<string>;
|
||||||
scrollIntoViewIfNeeded(params: { options?: types.TimeoutOptions }): Promise<void>;
|
scrollIntoViewIfNeeded(params: { options?: types.TimeoutOptions }): Promise<void>;
|
||||||
selectOption(params: { values: string | ElementHandleChannel | types.SelectOption | string[] | ElementHandleChannel[] | types.SelectOption[] | null; options?: types.NavigatingActionWaitOptions }): string[] | Promise<string[]>;
|
selectOption(params: { values: string | ElementHandleChannel | types.SelectOption | string[] | ElementHandleChannel[] | types.SelectOption[] | null; options?: types.NavigatingActionWaitOptions }): string[] | Promise<string[]>;
|
||||||
selectText(params: { options?: types.TimeoutOptions }): Promise<void>;
|
selectText(params: { options?: types.TimeoutOptions }): Promise<void>;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||||
super(connection, channel, initializer);
|
super(connection, channel, initializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
async newContext(options?: types.BrowserContextOptions): Promise<BrowserContext> {
|
async newContext(options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||||
|
delete (options as any).logger;
|
||||||
const context = BrowserContext.from(await this._channel.newContext({ options }));
|
const context = BrowserContext.from(await this._channel.newContext({ options }));
|
||||||
this._contexts.add(context);
|
this._contexts.add(context);
|
||||||
context._browser = this;
|
context._browser = this;
|
||||||
|
|
@ -49,7 +50,8 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||||
return [...this._contexts];
|
return [...this._contexts];
|
||||||
}
|
}
|
||||||
|
|
||||||
async newPage(options?: types.BrowserContextOptions): Promise<Page> {
|
async newPage(options: types.BrowserContextOptions = {}): Promise<Page> {
|
||||||
|
delete (options as any).logger;
|
||||||
const context = await this.newContext(options);
|
const context = await this.newContext(options);
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
page._ownedContext = context;
|
page._ownedContext = context;
|
||||||
|
|
|
||||||
|
|
@ -34,15 +34,18 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
||||||
return this._initializer.name;
|
return this._initializer.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
async launch(options?: types.LaunchOptions): Promise<Browser> {
|
async launch(options: types.LaunchOptions = {}): Promise<Browser> {
|
||||||
|
delete (options as any).logger;
|
||||||
return Browser.from(await this._channel.launch({ options }));
|
return Browser.from(await this._channel.launch({ options }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchPersistentContext(userDataDir: string, options?: types.LaunchOptions & types.BrowserContextOptions): Promise<BrowserContext> {
|
async launchPersistentContext(userDataDir: string, options: types.LaunchOptions & types.BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||||
|
delete (options as any).logger;
|
||||||
return BrowserContext.from(await this._channel.launchPersistentContext({ userDataDir, options }));
|
return BrowserContext.from(await this._channel.launchPersistentContext({ userDataDir, options }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(options: types.ConnectOptions): Promise<Browser> {
|
async connect(options: types.ConnectOptions): Promise<Browser> {
|
||||||
|
delete (options as any).logger;
|
||||||
return Browser.from(await this._channel.connect({ options }));
|
return Browser.from(await this._channel.connect({ options }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { ElementHandleChannel, JSHandleInitializer } from '../channels';
|
import { ElementHandleChannel, JSHandleInitializer } from '../channels';
|
||||||
import { Frame } from './frame';
|
import { Frame } from './frame';
|
||||||
import { FuncOn, JSHandle, convertArg } from './jsHandle';
|
import { FuncOn, JSHandle, serializeArgument, parseResult } from './jsHandle';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from '../connection';
|
||||||
|
|
||||||
export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
||||||
|
|
@ -125,7 +125,7 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async screenshot(options?: types.ElementScreenshotOptions): Promise<Buffer> {
|
async screenshot(options?: types.ElementScreenshotOptions): Promise<Buffer> {
|
||||||
return await this._elementChannel.screenshot({ options });
|
return Buffer.from(await this._elementChannel.screenshot({ options }), 'base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
async $(selector: string): Promise<ElementHandle<Element> | null> {
|
async $(selector: string): Promise<ElementHandle<Element> | null> {
|
||||||
|
|
@ -139,13 +139,13 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
||||||
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
|
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
|
||||||
async $eval<R>(selector: string, pageFunction: FuncOn<Element, void, R>, arg?: any): Promise<R>;
|
async $eval<R>(selector: string, pageFunction: FuncOn<Element, void, R>, arg?: any): Promise<R>;
|
||||||
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R> {
|
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R> {
|
||||||
return await this._elementChannel.$evalExpression({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
|
return parseResult(await this._elementChannel.$evalExpression({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>;
|
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>;
|
||||||
async $$eval<R>(selector: string, pageFunction: FuncOn<Element[], void, R>, arg?: any): Promise<R>;
|
async $$eval<R>(selector: string, pageFunction: FuncOn<Element[], void, R>, arg?: any): Promise<R>;
|
||||||
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R> {
|
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R> {
|
||||||
return await this._elementChannel.$$evalExpression({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
|
return parseResult(await this._elementChannel.$$evalExpression({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,12 @@ import { FrameChannel, FrameInitializer } from '../channels';
|
||||||
import { BrowserContext } from './browserContext';
|
import { BrowserContext } from './browserContext';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { ElementHandle, convertSelectOptionValues } from './elementHandle';
|
import { ElementHandle, convertSelectOptionValues } from './elementHandle';
|
||||||
import { JSHandle, Func1, FuncOn, SmartHandle, convertArg } from './jsHandle';
|
import { JSHandle, Func1, FuncOn, SmartHandle, serializeArgument, parseResult } from './jsHandle';
|
||||||
import * as network from './network';
|
import * as network from './network';
|
||||||
import { Response } from './network';
|
import { Response } from './network';
|
||||||
import { Page } from './page';
|
import { Page } from './page';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from '../connection';
|
||||||
|
import { normalizeFilePayloads } from '../serializers';
|
||||||
|
|
||||||
export type GotoOptions = types.NavigateOptions & {
|
export type GotoOptions = types.NavigateOptions & {
|
||||||
referer?: string,
|
referer?: string,
|
||||||
|
|
@ -78,14 +79,14 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
||||||
async evaluateHandle<R>(pageFunction: Func1<void, R>, arg?: any): Promise<SmartHandle<R>>;
|
async evaluateHandle<R>(pageFunction: Func1<void, R>, arg?: any): Promise<SmartHandle<R>>;
|
||||||
async evaluateHandle<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<SmartHandle<R>> {
|
async evaluateHandle<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<SmartHandle<R>> {
|
||||||
assertMaxArguments(arguments.length, 2);
|
assertMaxArguments(arguments.length, 2);
|
||||||
return JSHandle.from(await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) })) as SmartHandle<R>;
|
return JSHandle.from(await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) })) as SmartHandle<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async evaluate<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<R>;
|
async evaluate<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<R>;
|
||||||
async evaluate<R>(pageFunction: Func1<void, R>, arg?: any): Promise<R>;
|
async evaluate<R>(pageFunction: Func1<void, R>, arg?: any): Promise<R>;
|
||||||
async evaluate<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<R> {
|
async evaluate<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<R> {
|
||||||
assertMaxArguments(arguments.length, 2);
|
assertMaxArguments(arguments.length, 2);
|
||||||
return await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
|
return parseResult(await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async $(selector: string): Promise<ElementHandle<Element> | null> {
|
async $(selector: string): Promise<ElementHandle<Element> | null> {
|
||||||
|
|
@ -104,14 +105,14 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
||||||
async $eval<R>(selector: string, pageFunction: FuncOn<Element, void, R>, arg?: any): Promise<R>;
|
async $eval<R>(selector: string, pageFunction: FuncOn<Element, void, R>, arg?: any): Promise<R>;
|
||||||
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R> {
|
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R> {
|
||||||
assertMaxArguments(arguments.length, 3);
|
assertMaxArguments(arguments.length, 3);
|
||||||
return await this._channel.$eval({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
|
return await this._channel.$eval({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>;
|
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>;
|
||||||
async $$eval<R>(selector: string, pageFunction: FuncOn<Element[], void, R>, arg?: any): Promise<R>;
|
async $$eval<R>(selector: string, pageFunction: FuncOn<Element[], void, R>, arg?: any): Promise<R>;
|
||||||
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R> {
|
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R> {
|
||||||
assertMaxArguments(arguments.length, 3);
|
assertMaxArguments(arguments.length, 3);
|
||||||
return await this._channel.$$eval({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
|
return await this._channel.$$eval({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$(selector: string): Promise<ElementHandle<Element>[]> {
|
async $$(selector: string): Promise<ElementHandle<Element>[]> {
|
||||||
|
|
@ -196,7 +197,8 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async setInputFiles(selector: string, files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}): Promise<void> {
|
async setInputFiles(selector: string, files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||||
await this._channel.setInputFiles({ selector, files, options });
|
const filePayloads = await normalizeFilePayloads(files);
|
||||||
|
await this._channel.setInputFiles({ selector, files: filePayloads.map(f => ({ name: f.name, mimeType: f.mimeType, buffer: f.buffer.toString('base64') })), options });
|
||||||
}
|
}
|
||||||
|
|
||||||
async type(selector: string, text: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
async type(selector: string, text: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
||||||
|
|
@ -222,7 +224,7 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
||||||
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options?: types.WaitForFunctionOptions): Promise<SmartHandle<R>>;
|
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options?: types.WaitForFunctionOptions): Promise<SmartHandle<R>>;
|
||||||
async waitForFunction<R>(pageFunction: Func1<void, R>, arg?: any, options?: types.WaitForFunctionOptions): Promise<SmartHandle<R>>;
|
async waitForFunction<R>(pageFunction: Func1<void, R>, arg?: any, options?: types.WaitForFunctionOptions): Promise<SmartHandle<R>>;
|
||||||
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options: types.WaitForFunctionOptions = {}): Promise<SmartHandle<R>> {
|
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options: types.WaitForFunctionOptions = {}): Promise<SmartHandle<R>> {
|
||||||
return JSHandle.from(await this._channel.waitForFunction({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg, options })) as SmartHandle<R>;
|
return JSHandle.from(await this._channel.waitForFunction({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg), options })) as SmartHandle<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async title(): Promise<string> {
|
async title(): Promise<string> {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { JSHandleChannel, JSHandleInitializer } from '../channels';
|
||||||
import { ElementHandle } from './elementHandle';
|
import { ElementHandle } from './elementHandle';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
import { Connection } from '../connection';
|
import { Connection } from '../connection';
|
||||||
|
import { serializeAsCallArgument, parseEvaluationResultValue } from '../../common/utilityScriptSerializers';
|
||||||
|
|
||||||
type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg);
|
type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg);
|
||||||
type Unboxed<Arg> =
|
type Unboxed<Arg> =
|
||||||
|
|
@ -51,13 +52,13 @@ export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel, JSHandleIni
|
||||||
async evaluate<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<R>;
|
async evaluate<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<R>;
|
||||||
async evaluate<R>(pageFunction: FuncOn<T, void, R>, arg?: any): Promise<R>;
|
async evaluate<R>(pageFunction: FuncOn<T, void, R>, arg?: any): Promise<R>;
|
||||||
async evaluate<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<R> {
|
async evaluate<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<R> {
|
||||||
return await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
|
return parseResult(await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async evaluateHandle<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>>;
|
async evaluateHandle<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>>;
|
||||||
async evaluateHandle<R>(pageFunction: FuncOn<T, void, R>, arg?: any): Promise<SmartHandle<R>>;
|
async evaluateHandle<R>(pageFunction: FuncOn<T, void, R>, arg?: any): Promise<SmartHandle<R>>;
|
||||||
async evaluateHandle<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>> {
|
async evaluateHandle<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>> {
|
||||||
const handleChannel = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
|
const handleChannel = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||||
return JSHandle.from(handleChannel) as SmartHandle<R>;
|
return JSHandle.from(handleChannel) as SmartHandle<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,18 +98,20 @@ export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel, JSHandleIni
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertArg(arg: any): any {
|
export function serializeArgument(arg: any): any {
|
||||||
if (arg === null)
|
const guids: { guid: string }[] = [];
|
||||||
return null;
|
const pushHandle = (guid: string): number => {
|
||||||
if (Array.isArray(arg))
|
guids.push({ guid });
|
||||||
return arg.map(item => convertArg(item));
|
return guids.length - 1;
|
||||||
if (arg instanceof ChannelOwner)
|
};
|
||||||
return arg._channel;
|
const value = serializeAsCallArgument(arg, value => {
|
||||||
if (typeof arg === 'object') {
|
if (value instanceof ChannelOwner)
|
||||||
const result: any = {};
|
return { h: pushHandle(value._channel._guid) };
|
||||||
for (const key of Object.keys(arg))
|
return { fallThrough: value };
|
||||||
result[key] = convertArg(arg[key]);
|
});
|
||||||
return result;
|
return { value, guids };
|
||||||
}
|
}
|
||||||
return arg;
|
|
||||||
|
export function parseResult(arg: any): any {
|
||||||
|
return parseEvaluationResultValue(arg, []);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { Events } from '../../events';
|
import { Events } from '../../events';
|
||||||
import { assert, assertMaxArguments, helper, Listener, serializeError, parseError } from '../../helper';
|
import { assert, assertMaxArguments, helper, Listener } from '../../helper';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { PageChannel, BindingCallChannel, Channel, PageInitializer, BindingCallInitializer } from '../channels';
|
import { PageChannel, BindingCallChannel, Channel, PageInitializer, BindingCallInitializer } from '../channels';
|
||||||
import { BrowserContext } from './browserContext';
|
import { BrowserContext } from './browserContext';
|
||||||
|
|
@ -34,6 +34,7 @@ import { Dialog } from './dialog';
|
||||||
import { Download } from './download';
|
import { Download } from './download';
|
||||||
import { TimeoutError } from '../../errors';
|
import { TimeoutError } from '../../errors';
|
||||||
import { TimeoutSettings } from '../../timeoutSettings';
|
import { TimeoutSettings } from '../../timeoutSettings';
|
||||||
|
import { parseError, serializeError } from '../serializers';
|
||||||
|
|
||||||
export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||||
readonly pdf: ((options?: types.PDFOptions) => Promise<Buffer>) | undefined;
|
readonly pdf: ((options?: types.PDFOptions) => Promise<Buffer>) | undefined;
|
||||||
|
|
@ -365,7 +366,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async screenshot(options?: types.ScreenshotOptions): Promise<Buffer> {
|
async screenshot(options?: types.ScreenshotOptions): Promise<Buffer> {
|
||||||
return await this._channel.screenshot({ options });
|
return Buffer.from(await this._channel.screenshot({ options }), 'base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
async title(): Promise<string> {
|
async title(): Promise<string> {
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,14 @@ import { Channel } from './channels';
|
||||||
import { ConsoleMessage } from './client/consoleMessage';
|
import { ConsoleMessage } from './client/consoleMessage';
|
||||||
import { Dialog } from './client/dialog';
|
import { Dialog } from './client/dialog';
|
||||||
import { Download } from './client/download';
|
import { Download } from './client/download';
|
||||||
|
import { parseError } from './serializers';
|
||||||
|
|
||||||
export class Connection {
|
export class Connection {
|
||||||
private _channels = new Map<string, Channel>();
|
private _channels = new Map<string, Channel>();
|
||||||
private _waitingForObject = new Map<string, any>();
|
private _waitingForObject = new Map<string, any>();
|
||||||
sendMessageToServerTransport = (message: any): Promise<any> => Promise.resolve();
|
sendMessageToServerTransport = (message: string): void => {};
|
||||||
|
private _lastId = 0;
|
||||||
|
private _callbacks = new Map<number, { resolve: (a: any) => void, reject: (a: Error) => void }>();
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
|
|
@ -103,23 +106,33 @@ export class Connection {
|
||||||
return new Promise(f => this._waitingForObject.set(guid, f));
|
return new Promise(f => this._waitingForObject.set(guid, f));
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendMessageToServer(message: { guid: string, method: string, params: any }) {
|
async sendMessageToServer(message: { guid: string, method: string, params: any }): Promise<any> {
|
||||||
const converted = {...message, params: this._replaceChannelsWithGuids(message.params)};
|
const id = ++this._lastId;
|
||||||
|
const converted = { id, ...message, params: this._replaceChannelsWithGuids(message.params) };
|
||||||
debug('pw:channel:command')(converted);
|
debug('pw:channel:command')(converted);
|
||||||
const response = await this.sendMessageToServerTransport(converted);
|
this.sendMessageToServerTransport(JSON.stringify(converted));
|
||||||
debug('pw:channel:response')(response);
|
return new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject }));
|
||||||
return this._replaceGuidsWithChannels(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchMessageFromServer(message: { guid: string, method: string, params: any }) {
|
dispatchMessageFromServer(message: string) {
|
||||||
debug('pw:channel:event')(message);
|
const parsedMessage = JSON.parse(message);
|
||||||
const { guid, method, params } = message;
|
const { id, guid, method, params, result, error } = parsedMessage;
|
||||||
|
if (id) {
|
||||||
|
debug('pw:channel:response')(parsedMessage);
|
||||||
|
const callback = this._callbacks.get(id)!;
|
||||||
|
this._callbacks.delete(id);
|
||||||
|
if (error)
|
||||||
|
callback.reject(parseError(error));
|
||||||
|
else
|
||||||
|
callback.resolve(this._replaceGuidsWithChannels(result));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('pw:channel:event')(parsedMessage);
|
||||||
if (method === '__create__') {
|
if (method === '__create__') {
|
||||||
this._createRemoteObject(params.type, guid, params.initializer);
|
this._createRemoteObject(params.type, guid, params.initializer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const channel = this._channels.get(guid)!;
|
const channel = this._channels.get(guid)!;
|
||||||
channel.emit(method, this._replaceGuidsWithChannels(params));
|
channel.emit(method, this._replaceGuidsWithChannels(params));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { helper } from '../helper';
|
import { helper } from '../helper';
|
||||||
import { Channel } from './channels';
|
import { Channel } from './channels';
|
||||||
|
import { serializeError } from './serializers';
|
||||||
|
|
||||||
export class Dispatcher<Type, Initializer> extends EventEmitter implements Channel {
|
export class Dispatcher<Type, Initializer> extends EventEmitter implements Channel {
|
||||||
readonly _guid: string;
|
readonly _guid: string;
|
||||||
|
|
@ -43,16 +44,22 @@ export class Dispatcher<Type, Initializer> extends EventEmitter implements Chann
|
||||||
export class DispatcherScope {
|
export class DispatcherScope {
|
||||||
readonly dispatchers = new Map<string, Dispatcher<any, any>>();
|
readonly dispatchers = new Map<string, Dispatcher<any, any>>();
|
||||||
readonly dispatcherSymbol = Symbol('dispatcher');
|
readonly dispatcherSymbol = Symbol('dispatcher');
|
||||||
sendMessageToClientTransport = (message: any) => {};
|
sendMessageToClientTransport = (message: string) => {};
|
||||||
|
|
||||||
async sendMessageToClient(guid: string, method: string, params: any): Promise<any> {
|
async sendMessageToClient(guid: string, method: string, params: any): Promise<any> {
|
||||||
this.sendMessageToClientTransport({ guid, method, params: this._replaceDispatchersWithGuids(params) });
|
this.sendMessageToClientTransport(JSON.stringify({ guid, method, params: this._replaceDispatchersWithGuids(params) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async dispatchMessageFromClient(message: any): Promise<any> {
|
async dispatchMessageFromClient(message: string) {
|
||||||
const dispatcher = this.dispatchers.get(message.guid)!;
|
const parsedMessage = JSON.parse(message);
|
||||||
const value = await (dispatcher as any)[message.method](this._replaceGuidsWithDispatchers(message.params));
|
const { id, guid, method, params } = parsedMessage;
|
||||||
return this._replaceDispatchersWithGuids(value);
|
const dispatcher = this.dispatchers.get(guid)!;
|
||||||
|
try {
|
||||||
|
const result = await (dispatcher as any)[method](this._replaceGuidsWithDispatchers(params));
|
||||||
|
this.sendMessageToClientTransport(JSON.stringify({ id, result: this._replaceDispatchersWithGuids(result) }));
|
||||||
|
} catch (e) {
|
||||||
|
this.sendMessageToClientTransport(JSON.stringify({ id, error: serializeError(e) }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _replaceDispatchersWithGuids(payload: any): any {
|
private _replaceDispatchersWithGuids(payload: any): any {
|
||||||
|
|
|
||||||
64
src/rpc/serializers.ts
Normal file
64
src/rpc/serializers.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as mime from 'mime';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as util from 'util';
|
||||||
|
import { TimeoutError } from '../errors';
|
||||||
|
import * as types from '../types';
|
||||||
|
|
||||||
|
|
||||||
|
export function serializeError(e: any): types.Error {
|
||||||
|
if (e instanceof Error)
|
||||||
|
return { message: e.message, stack: e.stack, name: e.name };
|
||||||
|
return { value: e };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseError(error: types.Error): any {
|
||||||
|
if (error.message === undefined)
|
||||||
|
return error.value;
|
||||||
|
if (error.name === 'TimeoutError') {
|
||||||
|
const e = new TimeoutError(error.message);
|
||||||
|
e.stack = error.stack;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
const e = new Error(error.message);
|
||||||
|
e.stack = error.stack;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function normalizeFilePayloads(files: string | types.FilePayload | string[] | types.FilePayload[]): Promise<types.FilePayload[]> {
|
||||||
|
let ff: string[] | types.FilePayload[];
|
||||||
|
if (!Array.isArray(files))
|
||||||
|
ff = [ files ] as string[] | types.FilePayload[];
|
||||||
|
else
|
||||||
|
ff = files;
|
||||||
|
const filePayloads: types.FilePayload[] = [];
|
||||||
|
for (const item of ff) {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
const file: types.FilePayload = {
|
||||||
|
name: path.basename(item),
|
||||||
|
mimeType: mime.getType(item) || 'application/octet-stream',
|
||||||
|
buffer: await util.promisify(fs.readFile)(item)
|
||||||
|
};
|
||||||
|
filePayloads.push(file);
|
||||||
|
} else {
|
||||||
|
filePayloads.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filePayloads;
|
||||||
|
}
|
||||||
|
|
@ -19,8 +19,8 @@ import * as js from '../../javascript';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { ElementHandleChannel, FrameChannel } from '../channels';
|
import { ElementHandleChannel, FrameChannel } from '../channels';
|
||||||
import { DispatcherScope } from '../dispatcher';
|
import { DispatcherScope } from '../dispatcher';
|
||||||
import { convertArg, FrameDispatcher } from './frameDispatcher';
|
import { JSHandleDispatcher, serializeResult, parseArgument } from './jsHandleDispatcher';
|
||||||
import { JSHandleDispatcher } from './jsHandleDispatcher';
|
import { FrameDispatcher } from './frameDispatcher';
|
||||||
|
|
||||||
export class ElementHandleDispatcher extends JSHandleDispatcher implements ElementHandleChannel {
|
export class ElementHandleDispatcher extends JSHandleDispatcher implements ElementHandleChannel {
|
||||||
readonly _elementHandle: ElementHandle;
|
readonly _elementHandle: ElementHandle;
|
||||||
|
|
@ -140,8 +140,8 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements Eleme
|
||||||
return await this._elementHandle.boundingBox();
|
return await this._elementHandle.boundingBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
async screenshot(params: { options?: types.ElementScreenshotOptions }): Promise<Buffer> {
|
async screenshot(params: { options?: types.ElementScreenshotOptions }): Promise<string> {
|
||||||
return await this._elementHandle.screenshot(params.options);
|
return (await this._elementHandle.screenshot(params.options)).toString('base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
async querySelector(params: { selector: string }): Promise<ElementHandleChannel | null> {
|
async querySelector(params: { selector: string }): Promise<ElementHandleChannel | null> {
|
||||||
|
|
@ -154,11 +154,11 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements Eleme
|
||||||
}
|
}
|
||||||
|
|
||||||
async $evalExpression(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
async $evalExpression(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
||||||
return this._elementHandle._$evalExpression(params.selector, params.expression, params.isFunction, convertArg(this._scope, params.arg));
|
return serializeResult(await this._elementHandle._$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$evalExpression(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
async $$evalExpression(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
||||||
return this._elementHandle._$$evalExpression(params.selector, params.expression, params.isFunction, convertArg(this._scope, params.arg));
|
return serializeResult(await this._elementHandle._$$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@
|
||||||
|
|
||||||
import { Frame } from '../../frames';
|
import { Frame } from '../../frames';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { ElementHandleChannel, FrameChannel, JSHandleChannel, ResponseChannel, FrameInitializer } from '../channels';
|
import { ElementHandleChannel, FrameChannel, FrameInitializer, JSHandleChannel, ResponseChannel } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
||||||
import { ElementHandleDispatcher, convertSelectOptionValues } from './elementHandlerDispatcher';
|
import { convertSelectOptionValues, ElementHandleDispatcher } from './elementHandlerDispatcher';
|
||||||
import { JSHandleDispatcher } from './jsHandleDispatcher';
|
import { parseArgument, serializeResult } from './jsHandleDispatcher';
|
||||||
import { ResponseDispatcher } from './networkDispatchers';
|
import { ResponseDispatcher } from './networkDispatchers';
|
||||||
|
|
||||||
export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> implements FrameChannel {
|
export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> implements FrameChannel {
|
||||||
|
|
@ -63,15 +63,15 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
async evaluateExpression(params: { expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
async evaluateExpression(params: { expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
||||||
return this._frame._evaluateExpression(params.expression, params.isFunction, convertArg(this._scope, params.arg));
|
return serializeResult(await this._frame._evaluateExpression(params.expression, params.isFunction, parseArgument(params.arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async evaluateExpressionHandle(params: { expression: string, isFunction: boolean, arg: any}): Promise<JSHandleChannel> {
|
async evaluateExpressionHandle(params: { expression: string, isFunction: boolean, arg: any}): Promise<JSHandleChannel> {
|
||||||
return ElementHandleDispatcher.fromElement(this._scope, await this._frame._evaluateExpressionHandle(params.expression, params.isFunction, convertArg(this._scope, params.arg)));
|
return ElementHandleDispatcher.fromElement(this._scope, await this._frame._evaluateExpressionHandle(params.expression, params.isFunction, parseArgument(params.arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForSelector(params: { selector: string, options: types.WaitForElementOptions }): Promise<ElementHandleChannel | null> {
|
async waitForSelector(params: { selector: string, options: types.WaitForElementOptions }): Promise<ElementHandleChannel | null> {
|
||||||
return ElementHandleDispatcher.fromNullableElement(this._scope, await this._frame.waitForSelector(params.selector));
|
return ElementHandleDispatcher.fromNullableElement(this._scope, await this._frame.waitForSelector(params.selector, params.options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async dispatchEvent(params: { selector: string, type: string, eventInit: Object | undefined, options: types.TimeoutOptions }): Promise<void> {
|
async dispatchEvent(params: { selector: string, type: string, eventInit: Object | undefined, options: types.TimeoutOptions }): Promise<void> {
|
||||||
|
|
@ -79,11 +79,11 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
async $eval(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
async $eval(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
||||||
return this._frame._$evalExpression(params.selector, params.expression, params.isFunction, convertArg(this._scope, params.arg));
|
return serializeResult(await this._frame._$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$eval(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
async $$eval(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
||||||
return this._frame._$$evalExpression(params.selector, params.expression, params.isFunction, convertArg(this._scope, params.arg));
|
return serializeResult(await this._frame._$$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async querySelector(params: { selector: string }): Promise<ElementHandleChannel | null> {
|
async querySelector(params: { selector: string }): Promise<ElementHandleChannel | null> {
|
||||||
|
|
@ -151,8 +151,8 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
|
||||||
return this._frame.selectOption(params.selector, convertSelectOptionValues(params.values), params.options);
|
return this._frame.selectOption(params.selector, convertSelectOptionValues(params.values), params.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setInputFiles(params: { selector: string, files: string | string[] | types.FilePayload | types.FilePayload[], options: types.NavigatingActionWaitOptions }): Promise<void> {
|
async setInputFiles(params: { selector: string, files: { name: string, mimeType: string, buffer: string }[], options: types.NavigatingActionWaitOptions }): Promise<void> {
|
||||||
await this._frame.setInputFiles(params.selector, params.files, params.options);
|
await this._frame.setInputFiles(params.selector, params.files.map(f => ({ name: f.name, mimeType: f.mimeType, buffer: Buffer.from(f.buffer, 'base64') })), params.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
async type(params: { selector: string, text: string, options: { delay?: number | undefined } & types.TimeoutOptions & { noWaitAfter?: boolean } }): Promise<void> {
|
async type(params: { selector: string, text: string, options: { delay?: number | undefined } & types.TimeoutOptions & { noWaitAfter?: boolean } }): Promise<void> {
|
||||||
|
|
@ -172,26 +172,10 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForFunction(params: { expression: string, isFunction: boolean, arg: any; options: types.WaitForFunctionOptions }): Promise<JSHandleChannel> {
|
async waitForFunction(params: { expression: string, isFunction: boolean, arg: any; options: types.WaitForFunctionOptions }): Promise<JSHandleChannel> {
|
||||||
return ElementHandleDispatcher.from(this._scope, await this._frame._waitForFunctionExpression(params.expression, params.isFunction, convertArg(this._scope, params.arg), params.options));
|
return ElementHandleDispatcher.from(this._scope, await this._frame._waitForFunctionExpression(params.expression, params.isFunction, parseArgument(params.arg), params.options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async title(): Promise<string> {
|
async title(): Promise<string> {
|
||||||
return await this._frame.title();
|
return await this._frame.title();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertArg(scope: DispatcherScope, arg: any): any {
|
|
||||||
if (arg === null)
|
|
||||||
return null;
|
|
||||||
if (Array.isArray(arg))
|
|
||||||
return arg.map(item => convertArg(scope, item));
|
|
||||||
if (arg instanceof JSHandleDispatcher)
|
|
||||||
return arg._object;
|
|
||||||
if (typeof arg === 'object') {
|
|
||||||
const result: any = {};
|
|
||||||
for (const key of Object.keys(arg))
|
|
||||||
result[key] = convertArg(scope, arg[key]);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@
|
||||||
import * as js from '../../javascript';
|
import * as js from '../../javascript';
|
||||||
import { JSHandleChannel, JSHandleInitializer } from '../channels';
|
import { JSHandleChannel, JSHandleInitializer } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
||||||
import { convertArg } from './frameDispatcher';
|
|
||||||
import { ElementHandleDispatcher } from './elementHandlerDispatcher';
|
import { ElementHandleDispatcher } from './elementHandlerDispatcher';
|
||||||
|
import { parseEvaluationResultValue, serializeAsCallArgument } from '../../common/utilityScriptSerializers';
|
||||||
|
|
||||||
export class JSHandleDispatcher extends Dispatcher<js.JSHandle, JSHandleInitializer> implements JSHandleChannel {
|
export class JSHandleDispatcher extends Dispatcher<js.JSHandle, JSHandleInitializer> implements JSHandleChannel {
|
||||||
|
|
||||||
|
|
@ -29,11 +29,11 @@ export class JSHandleDispatcher extends Dispatcher<js.JSHandle, JSHandleInitiali
|
||||||
}
|
}
|
||||||
|
|
||||||
async evaluateExpression(params: { expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
async evaluateExpression(params: { expression: string, isFunction: boolean, arg: any }): Promise<any> {
|
||||||
return this._object._evaluateExpression(params.expression, params.isFunction, true /* returnByValue */, convertArg(this._scope, params.arg));
|
return this._object._evaluateExpression(params.expression, params.isFunction, true /* returnByValue */, parseArgument(params.arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
async evaluateExpressionHandle(params: { expression: string, isFunction: boolean, arg: any}): Promise<JSHandleChannel> {
|
async evaluateExpressionHandle(params: { expression: string, isFunction: boolean, arg: any}): Promise<JSHandleChannel> {
|
||||||
const jsHandle = await this._object._evaluateExpression(params.expression, params.isFunction, false /* returnByValue */, convertArg(this._scope, params.arg));
|
const jsHandle = await this._object._evaluateExpression(params.expression, params.isFunction, false /* returnByValue */, parseArgument(params.arg));
|
||||||
return ElementHandleDispatcher.from(this._scope, jsHandle);
|
return ElementHandleDispatcher.from(this._scope, jsHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,3 +53,27 @@ export class JSHandleDispatcher extends Dispatcher<js.JSHandle, JSHandleInitiali
|
||||||
await this._object.dispose();
|
await this._object.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseArgument(arg: { value: any, guids: JSHandleDispatcher[] }): any {
|
||||||
|
return convertDispatchersToObjects(parseEvaluationResultValue(arg.value, arg.guids));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function serializeResult(arg: any): any {
|
||||||
|
return serializeAsCallArgument(arg, value => ({ fallThrough: value }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertDispatchersToObjects(arg: any): any {
|
||||||
|
if (arg === null)
|
||||||
|
return null;
|
||||||
|
if (Array.isArray(arg))
|
||||||
|
return arg.map(item => convertDispatchersToObjects(item));
|
||||||
|
if (arg instanceof JSHandleDispatcher)
|
||||||
|
return arg._object;
|
||||||
|
if (typeof arg === 'object') {
|
||||||
|
const result: any = {};
|
||||||
|
for (const key of Object.keys(arg))
|
||||||
|
result[key] = convertDispatchersToObjects(arg[key]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@
|
||||||
import { BrowserContext } from '../../browserContext';
|
import { BrowserContext } from '../../browserContext';
|
||||||
import { Events } from '../../events';
|
import { Events } from '../../events';
|
||||||
import { Frame } from '../../frames';
|
import { Frame } from '../../frames';
|
||||||
import { parseError, serializeError } from '../../helper';
|
|
||||||
import { Request } from '../../network';
|
import { Request } from '../../network';
|
||||||
import { Page } from '../../page';
|
import { Page } from '../../page';
|
||||||
import * as types from '../../types';
|
import * as types from '../../types';
|
||||||
import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel } from '../channels';
|
import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel } from '../channels';
|
||||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
import { Dispatcher, DispatcherScope } from '../dispatcher';
|
||||||
|
import { parseError, serializeError } from '../serializers';
|
||||||
import { ConsoleMessageDispatcher } from './consoleMessageDispatcher';
|
import { ConsoleMessageDispatcher } from './consoleMessageDispatcher';
|
||||||
import { DialogDispatcher } from './dialogDispatcher';
|
import { DialogDispatcher } from './dialogDispatcher';
|
||||||
import { DownloadDispatcher } from './downloadDispatcher';
|
import { DownloadDispatcher } from './downloadDispatcher';
|
||||||
|
|
@ -129,8 +129,8 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async screenshot(params: { options?: types.ScreenshotOptions }): Promise<Buffer> {
|
async screenshot(params: { options?: types.ScreenshotOptions }): Promise<string> {
|
||||||
return await this._page.screenshot(params.options);
|
return (await this._page.screenshot(params.options)).toString('base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
async close(params: { options?: { runBeforeUnload?: boolean } }): Promise<void> {
|
async close(params: { options?: { runBeforeUnload?: boolean } }): Promise<void> {
|
||||||
|
|
|
||||||
|
|
@ -308,6 +308,7 @@ export type ConsoleMessageLocation = {
|
||||||
|
|
||||||
export type Error = {
|
export type Error = {
|
||||||
message?: string,
|
message?: string,
|
||||||
|
name?: string,
|
||||||
stack?: string,
|
stack?: string,
|
||||||
value?: any
|
value?: any
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue