feat(types): make our client classes implement public types (#4817)

This patch:
- introduces non-exported but used in api/impl struct types (e.g. Point);
- makes all client classes implement respective public api interface.

Pros:
- Typescript is now responsible for type checking.
  We can remove our doclint checker (not removed yet).
- Electron and Android types can be defined in the same way
  (this is not implemented yet).
- We can move most of the type structs like Point to the public api
  and make some of them available.

Cons:
- Any cons?
This commit is contained in:
Dmitry Gozman 2020-12-26 17:05:57 -08:00 committed by GitHub
parent dc25173ae3
commit 34c1b338be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 196 additions and 210 deletions

View file

@ -17,6 +17,7 @@
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import { ElementHandle } from './elementHandle'; import { ElementHandle } from './elementHandle';
import * as api from '../../types/types';
type SerializedAXNode = Omit<channels.AXNode, 'valueString' | 'valueNumber' | 'children' | 'checked' | 'pressed'> & { type SerializedAXNode = Omit<channels.AXNode, 'valueString' | 'valueNumber' | 'children' | 'checked' | 'pressed'> & {
value?: string|number, value?: string|number,
@ -38,7 +39,7 @@ function axNodeFromProtocol(axNode: channels.AXNode): SerializedAXNode {
return result; return result;
} }
export class Accessibility { export class Accessibility implements api.Accessibility {
private _channel: channels.PageChannel; private _channel: channels.PageChannel;
constructor(channel: channels.PageChannel) { constructor(channel: channels.PageChannel) {

View file

@ -21,8 +21,9 @@ import { ChannelOwner } from './channelOwner';
import { Events } from './events'; import { Events } from './events';
import { BrowserContextOptions } from './types'; import { BrowserContextOptions } from './types';
import { isSafeCloseError } from '../utils/errors'; import { isSafeCloseError } from '../utils/errors';
import * as api from '../../types/types';
export class Browser extends ChannelOwner<channels.BrowserChannel, channels.BrowserInitializer> { export class Browser extends ChannelOwner<channels.BrowserChannel, channels.BrowserInitializer> implements api.Browser {
readonly _contexts = new Set<BrowserContext>(); readonly _contexts = new Set<BrowserContext>();
private _isConnected = true; private _isConnected = true;
private _closedPromise: Promise<void>; private _closedPromise: Promise<void>;

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Page, BindingCall, FunctionWithSource } from './page'; import { Page, BindingCall } from './page';
import * as network from './network'; import * as network from './network';
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import * as util from 'util'; import * as util from 'util';
@ -30,16 +30,18 @@ import { URLMatch, Headers, WaitForEventOptions, BrowserContextOptions, StorageS
import { isUnderTest, headersObjectToArray, mkdirIfNeeded } from '../utils/utils'; import { isUnderTest, headersObjectToArray, mkdirIfNeeded } from '../utils/utils';
import { isSafeCloseError } from '../utils/errors'; import { isSafeCloseError } from '../utils/errors';
import { serializeArgument } from './jsHandle'; import { serializeArgument } from './jsHandle';
import * as api from '../../types/types';
import * as structs from '../../types/structs';
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs)); const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
const fsReadFileAsync = util.promisify(fs.readFile.bind(fs)); const fsReadFileAsync = util.promisify(fs.readFile.bind(fs));
export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel, channels.BrowserContextInitializer> { export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel, channels.BrowserContextInitializer> implements api.BrowserContext {
_pages = new Set<Page>(); _pages = new Set<Page>();
private _routes: { url: URLMatch, handler: network.RouteHandler }[] = []; private _routes: { url: URLMatch, handler: network.RouteHandler }[] = [];
readonly _browser: Browser | null = null; readonly _browser: Browser | null = null;
readonly _browserName: string; readonly _browserName: string;
readonly _bindings = new Map<string, FunctionWithSource>(); readonly _bindings = new Map<string, (source: structs.BindingSource, ...args: any[]) => any>();
_timeoutSettings = new TimeoutSettings(); _timeoutSettings = new TimeoutSettings();
_ownerPage: Page | undefined; _ownerPage: Page | undefined;
private _closedPromise: Promise<void>; private _closedPromise: Promise<void>;
@ -182,7 +184,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
}); });
} }
async exposeBinding(name: string, playwrightBinding: FunctionWithSource, options: { handle?: boolean } = {}): Promise<void> { async exposeBinding(name: string, playwrightBinding: (source: structs.BindingSource, ...args: any[]) => any, options: { handle?: boolean } = {}): Promise<void> {
return this._wrapApiCall('browserContext.exposeBinding', async () => { return this._wrapApiCall('browserContext.exposeBinding', async () => {
await this._channel.exposeBinding({ name, needsHandle: options.handle }); await this._channel.exposeBinding({ name, needsHandle: options.handle });
this._bindings.set(name, playwrightBinding); this._bindings.set(name, playwrightBinding);
@ -192,7 +194,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
async exposeFunction(name: string, playwrightFunction: Function): Promise<void> { async exposeFunction(name: string, playwrightFunction: Function): Promise<void> {
return this._wrapApiCall('browserContext.exposeFunction', async () => { return this._wrapApiCall('browserContext.exposeFunction', async () => {
await this._channel.exposeBinding({ name }); await this._channel.exposeBinding({ name });
const binding: FunctionWithSource = (source, ...args) => playwrightFunction(...args); const binding = (source: structs.BindingSource, ...args: any[]) => playwrightFunction(...args);
this._bindings.set(name, binding); this._bindings.set(name, binding);
}); });
} }

View file

@ -32,19 +32,21 @@ import { assert, makeWaitForNextTask, mkdirIfNeeded } from '../utils/utils';
import { SelectorsOwner, sharedSelectors } from './selectors'; import { SelectorsOwner, sharedSelectors } from './selectors';
import { kBrowserClosedError } from '../utils/errors'; import { kBrowserClosedError } from '../utils/errors';
import { Stream } from './stream'; import { Stream } from './stream';
import * as api from '../../types/types';
export interface BrowserServerLauncher { export interface BrowserServerLauncher {
launchServer(options?: LaunchServerOptions): Promise<BrowserServer>; launchServer(options?: LaunchServerOptions): Promise<api.BrowserServer>;
} }
export interface BrowserServer { // This is here just for api generation and checking.
export interface BrowserServer extends api.BrowserServer {
process(): ChildProcess; process(): ChildProcess;
wsEndpoint(): string; wsEndpoint(): string;
close(): Promise<void>; close(): Promise<void>;
kill(): Promise<void>; kill(): Promise<void>;
} }
export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel, channels.BrowserTypeInitializer> { export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel, channels.BrowserTypeInitializer> implements api.BrowserType<api.Browser> {
private _timeoutSettings = new TimeoutSettings(); private _timeoutSettings = new TimeoutSettings();
_serverLauncher?: BrowserServerLauncher; _serverLauncher?: BrowserServerLauncher;
@ -83,7 +85,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel, chann
}, logger); }, logger);
} }
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> { async launchServer(options: LaunchServerOptions = {}): Promise<api.BrowserServer> {
if (!this._serverLauncher) if (!this._serverLauncher)
throw new Error('Launching server is not supported'); throw new Error('Launching server is not supported');
return this._serverLauncher.launchServer(options); return this._serverLauncher.launchServer(options);

View file

@ -17,8 +17,9 @@
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import { ChannelOwner } from './channelOwner'; import { ChannelOwner } from './channelOwner';
import { Protocol } from '../server/chromium/protocol'; import { Protocol } from '../server/chromium/protocol';
import * as api from '../../types/types';
export class CDPSession extends ChannelOwner<channels.CDPSessionChannel, channels.CDPSessionInitializer> { export class CDPSession extends ChannelOwner<channels.CDPSessionChannel, channels.CDPSessionInitializer> implements api.CDPSession {
static from(cdpSession: channels.CDPSessionChannel): CDPSession { static from(cdpSession: channels.CDPSessionChannel): CDPSession {
return (cdpSession as any)._object; return (cdpSession as any)._object;
} }

View file

@ -17,8 +17,19 @@
import { Page } from './page'; import { Page } from './page';
import { CDPSession } from './cdpSession'; import { CDPSession } from './cdpSession';
import { Browser } from './browser'; import { Browser } from './browser';
import * as api from '../../types/types';
import { ChromiumBrowserContext } from './chromiumBrowserContext';
import { BrowserContextOptions } from './types';
export class ChromiumBrowser extends Browser implements api.ChromiumBrowser {
contexts(): ChromiumBrowserContext[] {
return super.contexts() as ChromiumBrowserContext[];
}
newContext(options?: BrowserContextOptions): Promise<ChromiumBrowserContext> {
return super.newContext(options) as Promise<ChromiumBrowserContext>;
}
export class ChromiumBrowser extends Browser {
async newBrowserCDPSession(): Promise<CDPSession> { async newBrowserCDPSession(): Promise<CDPSession> {
return this._wrapApiCall('chromiumBrowser.newBrowserCDPSession', async () => { return this._wrapApiCall('chromiumBrowser.newBrowserCDPSession', async () => {
return CDPSession.from((await this._channel.crNewBrowserCDPSession()).session); return CDPSession.from((await this._channel.crNewBrowserCDPSession()).session);

View file

@ -22,8 +22,9 @@ import { CDPSession } from './cdpSession';
import { Events } from './events'; import { Events } from './events';
import { Worker } from './worker'; import { Worker } from './worker';
import { BrowserContext } from './browserContext'; import { BrowserContext } from './browserContext';
import * as api from '../../types/types';
export class ChromiumBrowserContext extends BrowserContext { export class ChromiumBrowserContext extends BrowserContext implements api.ChromiumBrowserContext {
_backgroundPages = new Set<Page>(); _backgroundPages = new Set<Page>();
_serviceWorkers = new Set<Worker>(); _serviceWorkers = new Set<Worker>();

View file

@ -15,8 +15,9 @@
*/ */
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import * as api from '../../types/types';
export class ChromiumCoverage { export class ChromiumCoverage implements api.ChromiumCoverage {
private _channel: channels.PageChannel; private _channel: channels.PageChannel;
constructor(channel: channels.PageChannel) { constructor(channel: channels.PageChannel) {

View file

@ -18,10 +18,11 @@ import * as util from 'util';
import { JSHandle } from './jsHandle'; import { JSHandle } from './jsHandle';
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import { ChannelOwner } from './channelOwner'; import { ChannelOwner } from './channelOwner';
import * as api from '../../types/types';
type ConsoleMessageLocation = channels.ConsoleMessageInitializer['location']; type ConsoleMessageLocation = channels.ConsoleMessageInitializer['location'];
export class ConsoleMessage extends ChannelOwner<channels.ConsoleMessageChannel, channels.ConsoleMessageInitializer> { export class ConsoleMessage extends ChannelOwner<channels.ConsoleMessageChannel, channels.ConsoleMessageInitializer> implements api.ConsoleMessage {
static from(message: channels.ConsoleMessageChannel): ConsoleMessage { static from(message: channels.ConsoleMessageChannel): ConsoleMessage {
return (message as any)._object; return (message as any)._object;
} }

View file

@ -16,8 +16,9 @@
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import { ChannelOwner } from './channelOwner'; import { ChannelOwner } from './channelOwner';
import * as api from '../../types/types';
export class Dialog extends ChannelOwner<channels.DialogChannel, channels.DialogInitializer> { export class Dialog extends ChannelOwner<channels.DialogChannel, channels.DialogInitializer> implements api.Dialog {
static from(dialog: channels.DialogChannel): Dialog { static from(dialog: channels.DialogChannel): Dialog {
return (dialog as any)._object; return (dialog as any)._object;
} }

View file

@ -22,8 +22,9 @@ import { Browser } from './browser';
import { BrowserContext } from './browserContext'; import { BrowserContext } from './browserContext';
import * as fs from 'fs'; import * as fs from 'fs';
import { mkdirIfNeeded } from '../utils/utils'; import { mkdirIfNeeded } from '../utils/utils';
import * as api from '../../types/types';
export class Download extends ChannelOwner<channels.DownloadChannel, channels.DownloadInitializer> { export class Download extends ChannelOwner<channels.DownloadChannel, channels.DownloadInitializer> implements api.Download {
private _browser: Browser | null; private _browser: Browser | null;
static from(download: channels.DownloadChannel): Download { static from(download: channels.DownloadChannel): Download {

View file

@ -18,12 +18,13 @@ import * as channels from '../protocol/channels';
import { BrowserContext } from './browserContext'; import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner'; import { ChannelOwner } from './channelOwner';
import { Page } from './page'; import { Page } from './page';
import { serializeArgument, FuncOn, parseResult, SmartHandle, JSHandle } from './jsHandle'; import { serializeArgument, parseResult, JSHandle } from './jsHandle';
import { TimeoutSettings } from '../utils/timeoutSettings'; import { TimeoutSettings } from '../utils/timeoutSettings';
import { Waiter } from './waiter'; import { Waiter } from './waiter';
import { Events } from './events'; import { Events } from './events';
import { WaitForEventOptions, Env, Logger } from './types'; import { WaitForEventOptions, Env, Logger } from './types';
import { envObjectToArray } from './clientHelper'; import { envObjectToArray } from './clientHelper';
import * as structs from '../../types/structs';
type ElectronOptions = Omit<channels.ElectronLaunchOptions, 'env'> & { type ElectronOptions = Omit<channels.ElectronLaunchOptions, 'env'> & {
env?: Env, env?: Env,
@ -110,17 +111,13 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
return result; return result;
} }
async evaluate<R, Arg>(pageFunction: FuncOn<any, Arg, R>, arg: Arg): Promise<R>; async evaluate<R, Arg>(pageFunction: structs.PageFunctionOn<any, Arg, R>, arg: Arg): Promise<R> {
async evaluate<R>(pageFunction: FuncOn<any, void, R>, arg?: any): Promise<R>;
async evaluate<R, Arg>(pageFunction: FuncOn<any, Arg, R>, arg: Arg): Promise<R> {
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return parseResult(result.value); return parseResult(result.value);
} }
async evaluateHandle<R, Arg>(pageFunction: FuncOn<any, Arg, R>, arg: Arg): Promise<SmartHandle<R>>; async evaluateHandle<R, Arg>(pageFunction: structs.PageFunctionOn<any, Arg, R>, arg: Arg): Promise<structs.SmartHandle<R>> {
async evaluateHandle<R>(pageFunction: FuncOn<any, void, R>, arg?: any): Promise<SmartHandle<R>>;
async evaluateHandle<R, Arg>(pageFunction: FuncOn<any, Arg, R>, arg: Arg): Promise<SmartHandle<R>> {
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return JSHandle.from(result.handle) as SmartHandle<R>; return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
} }
} }

View file

@ -16,7 +16,7 @@
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import { Frame } from './frame'; import { Frame } from './frame';
import { FuncOn, JSHandle, serializeArgument, parseResult } from './jsHandle'; import { JSHandle, serializeArgument, parseResult } from './jsHandle';
import { ChannelOwner } from './channelOwner'; import { ChannelOwner } from './channelOwner';
import { SelectOption, FilePayload, Rect, SelectOptionOptions } from './types'; import { SelectOption, FilePayload, Rect, SelectOptionOptions } from './types';
import * as fs from 'fs'; import * as fs from 'fs';
@ -24,10 +24,12 @@ import * as mime from 'mime';
import * as path from 'path'; import * as path from 'path';
import * as util from 'util'; import * as util from 'util';
import { assert, isString, mkdirIfNeeded } from '../utils/utils'; import { assert, isString, mkdirIfNeeded } from '../utils/utils';
import * as api from '../../types/types';
import * as structs from '../../types/structs';
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs)); const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
export class ElementHandle<T extends Node = Node> extends JSHandle<T> { export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements api.ElementHandle {
readonly _elementChannel: channels.ElementHandleChannel; readonly _elementChannel: channels.ElementHandleChannel;
static from(handle: channels.ElementHandleChannel): ElementHandle { static from(handle: channels.ElementHandleChannel): ElementHandle {
@ -43,8 +45,8 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
this._elementChannel = this._channel as channels.ElementHandleChannel; this._elementChannel = this._channel as channels.ElementHandleChannel;
} }
asElement(): ElementHandle<T> | null { asElement(): T extends Node ? ElementHandle<T> : null {
return this; return this as any;
} }
async ownerFrame(): Promise<Frame | null> { async ownerFrame(): Promise<Frame | null> {
@ -121,7 +123,7 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
}); });
} }
async selectOption(values: string | ElementHandle | SelectOption | string[] | ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> { async selectOption(values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> {
return this._wrapApiCall('elementHandle.selectOption', async () => { return this._wrapApiCall('elementHandle.selectOption', async () => {
const result = await this._elementChannel.selectOption({ ...convertSelectOptionValues(values), ...options }); const result = await this._elementChannel.selectOption({ ...convertSelectOptionValues(values), ...options });
return result.values; return result.values;
@ -198,31 +200,27 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
}); });
} }
async $(selector: string): Promise<ElementHandle<Element> | null> { async $(selector: string): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
return this._wrapApiCall('elementHandle.$', async () => { return this._wrapApiCall('elementHandle.$', async () => {
return ElementHandle.fromNullable((await this._elementChannel.querySelector({ selector })).element) as ElementHandle<Element> | null; return ElementHandle.fromNullable((await this._elementChannel.querySelector({ selector })).element) as ElementHandle<SVGElement | HTMLElement> | null;
}); });
} }
async $$(selector: string): Promise<ElementHandle<Element>[]> { async $$(selector: string): Promise<ElementHandle<SVGElement | HTMLElement>[]> {
return this._wrapApiCall('elementHandle.$$', async () => { return this._wrapApiCall('elementHandle.$$', async () => {
const result = await this._elementChannel.querySelectorAll({ selector }); const result = await this._elementChannel.querySelectorAll({ selector });
return result.elements.map(h => ElementHandle.from(h) as ElementHandle<Element>); return result.elements.map(h => ElementHandle.from(h) as ElementHandle<SVGElement | HTMLElement>);
}); });
} }
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R>; async $eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element, Arg, R>, arg?: Arg): 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> {
return this._wrapApiCall('elementHandle.$eval', async () => { return this._wrapApiCall('elementHandle.$eval', async () => {
const result = await this._elementChannel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._elementChannel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return parseResult(result.value); return parseResult(result.value);
}); });
} }
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>; async $$eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element[], Arg, R>, arg?: Arg): 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> {
return this._wrapApiCall('elementHandle.$$eval', async () => { return this._wrapApiCall('elementHandle.$$eval', async () => {
const result = await this._elementChannel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._elementChannel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return parseResult(result.value); return parseResult(result.value);
@ -235,15 +233,17 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
}); });
} }
async waitForSelector(selector: string, options: channels.ElementHandleWaitForSelectorOptions = {}): Promise<ElementHandle<Element> | null> { waitForSelector(selector: string, options: channels.ElementHandleWaitForSelectorOptions & { state: 'attached' | 'visible' }): Promise<ElementHandle<SVGElement | HTMLElement>>;
waitForSelector(selector: string, options?: channels.ElementHandleWaitForSelectorOptions): Promise<ElementHandle<SVGElement | HTMLElement> | null>;
async waitForSelector(selector: string, options: channels.ElementHandleWaitForSelectorOptions = {}): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
return this._wrapApiCall('elementHandle.waitForSelector', async () => { return this._wrapApiCall('elementHandle.waitForSelector', async () => {
const result = await this._elementChannel.waitForSelector({ selector, ...options }); const result = await this._elementChannel.waitForSelector({ selector, ...options });
return ElementHandle.fromNullable(result.element) as ElementHandle<Element> | null; return ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
}); });
} }
} }
export function convertSelectOptionValues(values: string | ElementHandle | SelectOption | string[] | ElementHandle[] | SelectOption[] | null): { elements?: channels.ElementHandleChannel[], options?: SelectOption[] } { export function convertSelectOptionValues(values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null): { elements?: channels.ElementHandleChannel[], options?: SelectOption[] } {
if (values === null) if (values === null)
return {}; return {};
if (!Array.isArray(values)) if (!Array.isArray(values))

View file

@ -18,8 +18,9 @@ import { ElementHandle } from './elementHandle';
import { Page } from './page'; import { Page } from './page';
import { FilePayload } from './types'; import { FilePayload } from './types';
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import * as api from '../../types/types';
export class FileChooser { export class FileChooser implements api.FileChooser {
private _page: Page; private _page: Page;
private _elementHandle: ElementHandle<Node>; private _elementHandle: ElementHandle<Node>;
private _isMultiple: boolean; private _isMultiple: boolean;

View file

@ -15,6 +15,7 @@
*/ */
import { Browser } from './browser'; import { Browser } from './browser';
import * as api from '../../types/types';
export class FirefoxBrowser extends Browser { export class FirefoxBrowser extends Browser implements api.FirefoxBrowser {
} }

View file

@ -19,7 +19,7 @@ import { assert } from '../utils/utils';
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import { ChannelOwner } from './channelOwner'; import { ChannelOwner } from './channelOwner';
import { ElementHandle, convertSelectOptionValues, convertInputFiles } from './elementHandle'; import { ElementHandle, convertSelectOptionValues, convertInputFiles } from './elementHandle';
import { assertMaxArguments, JSHandle, Func1, FuncOn, SmartHandle, serializeArgument, parseResult } from './jsHandle'; import { assertMaxArguments, JSHandle, serializeArgument, parseResult } from './jsHandle';
import * as fs from 'fs'; import * as fs from 'fs';
import * as network from './network'; import * as network from './network';
import * as util from 'util'; import * as util from 'util';
@ -29,6 +29,8 @@ import { Waiter } from './waiter';
import { Events } from './events'; import { Events } from './events';
import { LifecycleEvent, URLMatch, SelectOption, SelectOptionOptions, FilePayload, WaitForFunctionOptions, kLifecycleEvents } from './types'; import { LifecycleEvent, URLMatch, SelectOption, SelectOptionOptions, FilePayload, WaitForFunctionOptions, kLifecycleEvents } from './types';
import { urlMatches } from './clientHelper'; import { urlMatches } from './clientHelper';
import * as api from '../../types/types';
import * as structs from '../../types/structs';
const fsReadFileAsync = util.promisify(fs.readFile.bind(fs)); const fsReadFileAsync = util.promisify(fs.readFile.bind(fs));
@ -38,7 +40,7 @@ export type WaitForNavigationOptions = {
url?: URLMatch, url?: URLMatch,
}; };
export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameInitializer> { export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameInitializer> implements api.Frame {
_eventEmitter: EventEmitter; _eventEmitter: EventEmitter;
_loadStates: Set<LifecycleEvent>; _loadStates: Set<LifecycleEvent>;
_parentFrame: Frame | null = null; _parentFrame: Frame | null = null;
@ -164,29 +166,25 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
}); });
} }
async evaluateHandle<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<SmartHandle<R>>; async evaluateHandle<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<structs.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>> {
assertMaxArguments(arguments.length, 2); assertMaxArguments(arguments.length, 2);
return this._wrapApiCall(this._apiName('evaluateHandle'), async () => { return this._wrapApiCall(this._apiName('evaluateHandle'), async () => {
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return JSHandle.from(result.handle) as SmartHandle<R>; return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
}); });
} }
async _evaluateHandleInUtility<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<SmartHandle<R>>; async _evaluateHandleInUtility<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg: Arg): Promise<structs.SmartHandle<R>>;
async _evaluateHandleInUtility<R>(pageFunction: Func1<void, R>, arg?: any): Promise<SmartHandle<R>>; async _evaluateHandleInUtility<R>(pageFunction: structs.PageFunction<void, R>, arg?: any): Promise<structs.SmartHandle<R>>;
async _evaluateHandleInUtility<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<SmartHandle<R>> { async _evaluateHandleInUtility<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<structs.SmartHandle<R>> {
assertMaxArguments(arguments.length, 2); assertMaxArguments(arguments.length, 2);
return this._wrapApiCall(this._apiName('_evaluateHandleInUtility'), async () => { return this._wrapApiCall(this._apiName('_evaluateHandleInUtility'), async () => {
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg), world: 'utility' }); const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg), world: 'utility' });
return JSHandle.from(result.handle) as SmartHandle<R>; return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
}); });
} }
async evaluate<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<R>; async evaluate<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): 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> {
assertMaxArguments(arguments.length, 2); assertMaxArguments(arguments.length, 2);
return this._wrapApiCall(this._apiName('evaluate'), async () => { return this._wrapApiCall(this._apiName('evaluate'), async () => {
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
@ -194,9 +192,9 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
}); });
} }
async _evaluateInUtility<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<R>; async _evaluateInUtility<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg: Arg): Promise<R>;
async _evaluateInUtility<R>(pageFunction: Func1<void, R>, arg?: any): Promise<R>; async _evaluateInUtility<R>(pageFunction: structs.PageFunction<void, R>, arg?: any): Promise<R>;
async _evaluateInUtility<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<R> { async _evaluateInUtility<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<R> {
assertMaxArguments(arguments.length, 2); assertMaxArguments(arguments.length, 2);
return this._wrapApiCall(this._apiName('evaluate'), async () => { return this._wrapApiCall(this._apiName('evaluate'), async () => {
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg), world: 'utility' }); const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg), world: 'utility' });
@ -204,21 +202,23 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
}); });
} }
async $(selector: string): Promise<ElementHandle<Element> | null> { async $(selector: string): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
return this._wrapApiCall(this._apiName('$'), async () => { return this._wrapApiCall(this._apiName('$'), async () => {
const result = await this._channel.querySelector({ selector }); const result = await this._channel.querySelector({ selector });
return ElementHandle.fromNullable(result.element) as ElementHandle<Element> | null; return ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
}); });
} }
async waitForSelector(selector: string, options: channels.FrameWaitForSelectorOptions = {}): Promise<ElementHandle<Element> | null> { waitForSelector(selector: string, options: channels.FrameWaitForSelectorOptions & { state: 'attached' | 'visible' }): Promise<ElementHandle<SVGElement | HTMLElement>>;
waitForSelector(selector: string, options?: channels.FrameWaitForSelectorOptions): Promise<ElementHandle<SVGElement | HTMLElement> | null>;
async waitForSelector(selector: string, options: channels.FrameWaitForSelectorOptions = {}): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
return this._wrapApiCall(this._apiName('waitForSelector'), async () => { return this._wrapApiCall(this._apiName('waitForSelector'), async () => {
if ((options as any).visibility) if ((options as any).visibility)
throw new Error('options.visibility is not supported, did you mean options.state?'); throw new Error('options.visibility is not supported, did you mean options.state?');
if ((options as any).waitFor && (options as any).waitFor !== 'visible') if ((options as any).waitFor && (options as any).waitFor !== 'visible')
throw new Error('options.waitFor is not supported, did you mean options.state?'); throw new Error('options.waitFor is not supported, did you mean options.state?');
const result = await this._channel.waitForSelector({ selector, ...options }); const result = await this._channel.waitForSelector({ selector, ...options });
return ElementHandle.fromNullable(result.element) as ElementHandle<Element> | null; return ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
}); });
} }
@ -228,9 +228,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
}); });
} }
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R>; async $eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element, Arg, R>, arg?: Arg): 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> {
assertMaxArguments(arguments.length, 3); assertMaxArguments(arguments.length, 3);
return this._wrapApiCall(this._apiName('$eval'), async () => { return this._wrapApiCall(this._apiName('$eval'), async () => {
const result = await this._channel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
@ -238,9 +236,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
}); });
} }
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>; async $$eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element[], Arg, R>, arg?: Arg): 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> {
assertMaxArguments(arguments.length, 3); assertMaxArguments(arguments.length, 3);
return this._wrapApiCall(this._apiName('$$eval'), async () => { return this._wrapApiCall(this._apiName('$$eval'), async () => {
const result = await this._channel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
@ -248,10 +244,10 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
}); });
} }
async $$(selector: string): Promise<ElementHandle<Element>[]> { async $$(selector: string): Promise<ElementHandle<SVGElement | HTMLElement>[]> {
return this._wrapApiCall(this._apiName('$$'), async () => { return this._wrapApiCall(this._apiName('$$'), async () => {
const result = await this._channel.querySelectorAll({ selector }); const result = await this._channel.querySelectorAll({ selector });
return result.elements.map(e => ElementHandle.from(e) as ElementHandle<Element>); return result.elements.map(e => ElementHandle.from(e) as ElementHandle<SVGElement | HTMLElement>);
}); });
} }
@ -372,7 +368,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
}); });
} }
async selectOption(selector: string, values: string | ElementHandle | SelectOption | string[] | ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> { async selectOption(selector: string, values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> {
return this._wrapApiCall(this._apiName('selectOption'), async () => { return this._wrapApiCall(this._apiName('selectOption'), async () => {
return (await this._channel.selectOption({ selector, ...convertSelectOptionValues(values), ...options })).values; return (await this._channel.selectOption({ selector, ...convertSelectOptionValues(values), ...options })).values;
}); });
@ -412,9 +408,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
await new Promise(fulfill => setTimeout(fulfill, timeout)); await new Promise(fulfill => setTimeout(fulfill, timeout));
} }
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options?: WaitForFunctionOptions): Promise<SmartHandle<R>>; async waitForFunction<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg, options: WaitForFunctionOptions = {}): Promise<structs.SmartHandle<R>> {
async waitForFunction<R>(pageFunction: Func1<void, R>, arg?: any, options?: WaitForFunctionOptions): Promise<SmartHandle<R>>;
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options: WaitForFunctionOptions = {}): Promise<SmartHandle<R>> {
return this._wrapApiCall(this._apiName('waitForFunction'), async () => { return this._wrapApiCall(this._apiName('waitForFunction'), async () => {
if (typeof options.polling === 'string') if (typeof options.polling === 'string')
assert(options.polling === 'raf', 'Unknown polling option: ' + options.polling); assert(options.polling === 'raf', 'Unknown polling option: ' + options.polling);
@ -425,7 +419,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel, channels.FrameIni
isFunction: typeof pageFunction === 'function', isFunction: typeof pageFunction === 'function',
arg: serializeArgument(arg), arg: serializeArgument(arg),
}); });
return JSHandle.from(result.handle) as SmartHandle<R>; return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
}); });
} }

View file

@ -16,8 +16,9 @@
*/ */
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import * as api from '../../types/types';
export class Keyboard { export class Keyboard implements api.Keyboard {
private _channel: channels.PageChannel; private _channel: channels.PageChannel;
constructor(channel: channels.PageChannel) { constructor(channel: channels.PageChannel) {
@ -45,7 +46,7 @@ export class Keyboard {
} }
} }
export class Mouse { export class Mouse implements api.Mouse {
private _channel: channels.PageChannel; private _channel: channels.PageChannel;
constructor(channel: channels.PageChannel) { constructor(channel: channels.PageChannel) {
@ -73,7 +74,7 @@ export class Mouse {
} }
} }
export class Touchscreen { export class Touchscreen implements api.Touchscreen {
private _channel: channels.PageChannel; private _channel: channels.PageChannel;
constructor(channel: channels.PageChannel) { constructor(channel: channels.PageChannel) {

View file

@ -15,27 +15,12 @@
*/ */
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import { ElementHandle } from './elementHandle';
import { ChannelOwner } from './channelOwner'; import { ChannelOwner } from './channelOwner';
import { parseSerializedValue, serializeValue } from '../protocol/serializers'; import { parseSerializedValue, serializeValue } from '../protocol/serializers';
import * as api from '../../types/types';
import * as structs from '../../types/structs';
type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg); export class JSHandle<T = any> extends ChannelOwner<channels.JSHandleChannel, channels.JSHandleInitializer> implements api.JSHandle {
type Unboxed<Arg> =
Arg extends ElementHandle<infer T> ? T :
Arg extends JSHandle<infer T> ? T :
Arg extends NoHandles<Arg> ? Arg :
Arg extends [infer A0] ? [Unboxed<A0>] :
Arg extends [infer A0, infer A1] ? [Unboxed<A0>, Unboxed<A1>] :
Arg extends [infer A0, infer A1, infer A2] ? [Unboxed<A0>, Unboxed<A1>, Unboxed<A2>] :
Arg extends Array<infer T> ? Array<Unboxed<T>> :
Arg extends object ? { [Key in keyof Arg]: Unboxed<Arg[Key]> } :
Arg;
export type Func0<R> = string | (() => R | Promise<R>);
export type Func1<Arg, R> = string | ((arg: Unboxed<Arg>) => R | Promise<R>);
export type FuncOn<On, Arg2, R> = string | ((on: On, arg2: Unboxed<Arg2>) => R | Promise<R>);
export type SmartHandle<T> = T extends Node ? ElementHandle<T> : JSHandle<T>;
export class JSHandle<T = any> extends ChannelOwner<channels.JSHandleChannel, channels.JSHandleInitializer> {
private _preview: string; private _preview: string;
static from(handle: channels.JSHandleChannel): JSHandle { static from(handle: channels.JSHandleChannel): JSHandle {
@ -48,18 +33,14 @@ export class JSHandle<T = any> extends ChannelOwner<channels.JSHandleChannel, ch
this._channel.on('previewUpdated', ({preview}) => this._preview = preview); this._channel.on('previewUpdated', ({preview}) => this._preview = preview);
} }
async evaluate<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<R>; async evaluate<R, Arg>(pageFunction: structs.PageFunctionOn<T, Arg, R>, arg?: Arg): 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> {
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return parseResult(result.value); return parseResult(result.value);
} }
async evaluateHandle<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>>; async evaluateHandle<R, Arg>(pageFunction: structs.PageFunctionOn<T, Arg, R>, arg?: Arg): Promise<structs.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>> {
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return JSHandle.from(result.handle) as SmartHandle<R>; return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
} }
async getProperty(propertyName: string): Promise<JSHandle> { async getProperty(propertyName: string): Promise<JSHandle> {
@ -78,8 +59,8 @@ export class JSHandle<T = any> extends ChannelOwner<channels.JSHandleChannel, ch
return parseResult((await this._channel.jsonValue()).value); return parseResult((await this._channel.jsonValue()).value);
} }
asElement(): ElementHandle | null { asElement(): T extends Node ? api.ElementHandle<T> : null {
return null; return null as any;
} }
async dispose() { async dispose() {

View file

@ -26,6 +26,7 @@ import { isString, headersObjectToArray, headersArrayToObject } from '../utils/u
import { Events } from './events'; import { Events } from './events';
import { Page } from './page'; import { Page } from './page';
import { Waiter } from './waiter'; import { Waiter } from './waiter';
import * as api from '../../types/types';
export type NetworkCookie = { export type NetworkCookie = {
name: string, name: string,
@ -50,7 +51,7 @@ export type SetNetworkCookieParam = {
sameSite?: 'Strict' | 'Lax' | 'None' sameSite?: 'Strict' | 'Lax' | 'None'
}; };
export class Request extends ChannelOwner<channels.RequestChannel, channels.RequestInitializer> { export class Request extends ChannelOwner<channels.RequestChannel, channels.RequestInitializer> implements api.Request {
private _redirectedFrom: Request | null = null; private _redirectedFrom: Request | null = null;
private _redirectedTo: Request | null = null; private _redirectedTo: Request | null = null;
_failureText: string | null = null; _failureText: string | null = null;
@ -167,7 +168,7 @@ export class Request extends ChannelOwner<channels.RequestChannel, channels.Requ
} }
} }
export class Route extends ChannelOwner<channels.RouteChannel, channels.RouteInitializer> { export class Route extends ChannelOwner<channels.RouteChannel, channels.RouteInitializer> implements api.Route {
static from(route: channels.RouteChannel): Route { static from(route: channels.RouteChannel): Route {
return (route as any)._object; return (route as any)._object;
} }
@ -246,7 +247,7 @@ export type ResourceTiming = {
responseEnd: number; responseEnd: number;
}; };
export class Response extends ChannelOwner<channels.ResponseChannel, channels.ResponseInitializer> { export class Response extends ChannelOwner<channels.ResponseChannel, channels.ResponseInitializer> implements api.Response {
private _headers: Headers; private _headers: Headers;
private _request: Request; private _request: Request;
@ -316,7 +317,7 @@ export class Response extends ChannelOwner<channels.ResponseChannel, channels.Re
} }
} }
export class WebSocket extends ChannelOwner<channels.WebSocketChannel, channels.WebSocketInitializer> { export class WebSocket extends ChannelOwner<channels.WebSocketChannel, channels.WebSocketInitializer> implements api.WebSocket {
private _page: Page; private _page: Page;
private _isClosed: boolean; private _isClosed: boolean;

View file

@ -30,13 +30,14 @@ import { ElementHandle, determineScreenshotType } from './elementHandle';
import { Worker } from './worker'; import { Worker } from './worker';
import { Frame, verifyLoadState, WaitForNavigationOptions } from './frame'; import { Frame, verifyLoadState, WaitForNavigationOptions } from './frame';
import { Keyboard, Mouse, Touchscreen } from './input'; import { Keyboard, Mouse, Touchscreen } from './input';
import { assertMaxArguments, Func1, FuncOn, SmartHandle, serializeArgument, parseResult, JSHandle } from './jsHandle'; import { assertMaxArguments, serializeArgument, parseResult, JSHandle } from './jsHandle';
import { Request, Response, Route, RouteHandler, WebSocket, validateHeaders } from './network'; import { Request, Response, Route, RouteHandler, WebSocket, validateHeaders } from './network';
import { FileChooser } from './fileChooser'; import { FileChooser } from './fileChooser';
import { Buffer } from 'buffer'; import { Buffer } from 'buffer';
import { ChromiumCoverage } from './chromiumCoverage'; import { ChromiumCoverage } from './chromiumCoverage';
import { Waiter } from './waiter'; import { Waiter } from './waiter';
import * as api from '../../types/types';
import * as structs from '../../types/structs';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as util from 'util'; import * as util from 'util';
@ -61,9 +62,8 @@ type PDFOptions = Omit<channels.PagePdfParams, 'width' | 'height' | 'margin'> &
path?: string, path?: string,
}; };
type Listener = (...args: any[]) => void; type Listener = (...args: any[]) => void;
export type FunctionWithSource = (source: { context: BrowserContext, page: Page, frame: Frame }, ...args: any) => any;
export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitializer> { export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitializer> implements api.Page {
private _browserContext: BrowserContext; private _browserContext: BrowserContext;
_ownedContext: BrowserContext | undefined; _ownedContext: BrowserContext | undefined;
@ -79,9 +79,9 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
readonly mouse: Mouse; readonly mouse: Mouse;
readonly touchscreen: Touchscreen; readonly touchscreen: Touchscreen;
coverage: ChromiumCoverage | null = null; coverage: ChromiumCoverage | null = null;
pdf?: (options?: PDFOptions) => Promise<Buffer>; pdf: (options?: PDFOptions) => Promise<Buffer>;
readonly _bindings = new Map<string, FunctionWithSource>(); readonly _bindings = new Map<string, (source: structs.BindingSource, ...args: any[]) => any>();
readonly _timeoutSettings: TimeoutSettings; readonly _timeoutSettings: TimeoutSettings;
_isPageCall = false; _isPageCall = false;
private _video: Video | null = null; private _video: Video | null = null;
@ -136,6 +136,8 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
if (this._browserContext._browserName === 'chromium') { if (this._browserContext._browserName === 'chromium') {
this.coverage = new ChromiumCoverage(this._channel); this.coverage = new ChromiumCoverage(this._channel);
this.pdf = options => this._pdf(options); this.pdf = options => this._pdf(options);
} else {
this.pdf = undefined as any;
} }
} }
@ -261,11 +263,13 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
} }
} }
async $(selector: string): Promise<ElementHandle<Element> | null> { async $(selector: string): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
return this._attributeToPage(() => this._mainFrame.$(selector)); return this._attributeToPage(() => this._mainFrame.$(selector));
} }
async waitForSelector(selector: string, options?: channels.FrameWaitForSelectorOptions): Promise<ElementHandle<Element> | null> { waitForSelector(selector: string, options: channels.FrameWaitForSelectorOptions & { state: 'attached' | 'visible' }): Promise<ElementHandle<SVGElement | HTMLElement>>;
waitForSelector(selector: string, options?: channels.FrameWaitForSelectorOptions): Promise<ElementHandle<SVGElement | HTMLElement> | null>;
async waitForSelector(selector: string, options?: channels.FrameWaitForSelectorOptions): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
return this._attributeToPage(() => this._mainFrame.waitForSelector(selector, options)); return this._attributeToPage(() => this._mainFrame.waitForSelector(selector, options));
} }
@ -273,28 +277,22 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
return this._attributeToPage(() => this._mainFrame.dispatchEvent(selector, type, eventInit, options)); return this._attributeToPage(() => this._mainFrame.dispatchEvent(selector, type, eventInit, options));
} }
async evaluateHandle<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<SmartHandle<R>>; async evaluateHandle<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<structs.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>> {
assertMaxArguments(arguments.length, 2); assertMaxArguments(arguments.length, 2);
return this._attributeToPage(() => this._mainFrame.evaluateHandle(pageFunction, arg)); return this._attributeToPage(() => this._mainFrame.evaluateHandle(pageFunction, arg));
} }
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R>; async $eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element, Arg, R>, arg?: Arg): 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> {
assertMaxArguments(arguments.length, 3); assertMaxArguments(arguments.length, 3);
return this._attributeToPage(() => this._mainFrame.$eval(selector, pageFunction, arg)); return this._attributeToPage(() => this._mainFrame.$eval(selector, pageFunction, arg));
} }
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>; async $$eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element[], Arg, R>, arg?: Arg): 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> {
assertMaxArguments(arguments.length, 3); assertMaxArguments(arguments.length, 3);
return this._attributeToPage(() => this._mainFrame.$$eval(selector, pageFunction, arg)); return this._attributeToPage(() => this._mainFrame.$$eval(selector, pageFunction, arg));
} }
async $$(selector: string): Promise<ElementHandle<Element>[]> { async $$(selector: string): Promise<ElementHandle<SVGElement | HTMLElement>[]> {
return this._attributeToPage(() => this._mainFrame.$$(selector)); return this._attributeToPage(() => this._mainFrame.$$(selector));
} }
@ -309,12 +307,12 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
async exposeFunction(name: string, playwrightFunction: Function) { async exposeFunction(name: string, playwrightFunction: Function) {
return this._wrapApiCall('page.exposeFunction', async () => { return this._wrapApiCall('page.exposeFunction', async () => {
await this._channel.exposeBinding({ name }); await this._channel.exposeBinding({ name });
const binding: FunctionWithSource = (source, ...args) => playwrightFunction(...args); const binding = (source: structs.BindingSource, ...args: any[]) => playwrightFunction(...args);
this._bindings.set(name, binding); this._bindings.set(name, binding);
}); });
} }
async exposeBinding(name: string, playwrightBinding: FunctionWithSource, options: { handle?: boolean } = {}) { async exposeBinding(name: string, playwrightBinding: (source: structs.BindingSource, ...args: any[]) => any, options: { handle?: boolean } = {}) {
return this._wrapApiCall('page.exposeBinding', async () => { return this._wrapApiCall('page.exposeBinding', async () => {
await this._channel.exposeBinding({ name, needsHandle: options.handle }); await this._channel.exposeBinding({ name, needsHandle: options.handle });
this._bindings.set(name, playwrightBinding); this._bindings.set(name, playwrightBinding);
@ -425,9 +423,7 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
return this._viewportSize; return this._viewportSize;
} }
async evaluate<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<R>; async evaluate<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): 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> {
assertMaxArguments(arguments.length, 2); assertMaxArguments(arguments.length, 2);
return this._attributeToPage(() => this._mainFrame.evaluate(pageFunction, arg)); return this._attributeToPage(() => this._mainFrame.evaluate(pageFunction, arg));
} }
@ -538,7 +534,7 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
return this._attributeToPage(() => this._mainFrame.hover(selector, options)); return this._attributeToPage(() => this._mainFrame.hover(selector, options));
} }
async selectOption(selector: string, values: string | ElementHandle | SelectOption | string[] | ElementHandle[] | SelectOption[] | null, options?: SelectOptionOptions): Promise<string[]> { async selectOption(selector: string, values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null, options?: SelectOptionOptions): Promise<string[]> {
return this._attributeToPage(() => this._mainFrame.selectOption(selector, values, options)); return this._attributeToPage(() => this._mainFrame.selectOption(selector, values, options));
} }
@ -566,9 +562,7 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
await this._mainFrame.waitForTimeout(timeout); await this._mainFrame.waitForTimeout(timeout);
} }
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options?: WaitForFunctionOptions): Promise<SmartHandle<R>>; async waitForFunction<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg, options?: WaitForFunctionOptions): Promise<structs.SmartHandle<R>> {
async waitForFunction<R>(pageFunction: Func1<void, R>, arg?: any, options?: WaitForFunctionOptions): Promise<SmartHandle<R>>;
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options?: WaitForFunctionOptions): Promise<SmartHandle<R>> {
return this._attributeToPage(() => this._mainFrame.waitForFunction(pageFunction, arg, options)); return this._attributeToPage(() => this._mainFrame.waitForFunction(pageFunction, arg, options));
} }
@ -636,7 +630,7 @@ export class BindingCall extends ChannelOwner<channels.BindingCallChannel, chann
super(parent, type, guid, initializer); super(parent, type, guid, initializer);
} }
async call(func: FunctionWithSource) { async call(func: (source: structs.BindingSource, ...args: any[]) => any) {
try { try {
const frame = Frame.from(this._initializer.frame); const frame = Frame.from(this._initializer.frame);
const source = { const source = {

View file

@ -18,8 +18,9 @@ import { evaluationScript } from './clientHelper';
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import { ChannelOwner } from './channelOwner'; import { ChannelOwner } from './channelOwner';
import { SelectorEngine } from './types'; import { SelectorEngine } from './types';
import * as api from '../../types/types';
export class Selectors { export class Selectors implements api.Selectors {
private _channels = new Set<SelectorsOwner>(); private _channels = new Set<SelectorsOwner>();
private _registrations: channels.SelectorsRegisterParams[] = []; private _registrations: channels.SelectorsRegisterParams[] = [];

View file

@ -16,8 +16,9 @@
import * as path from 'path'; import * as path from 'path';
import { Page } from './page'; import { Page } from './page';
import * as api from '../../types/types';
export class Video { export class Video implements api.Video {
private _page: Page; private _page: Page;
private _pathCallback: ((path: string) => void) | undefined; private _pathCallback: ((path: string) => void) | undefined;
private _pathPromise: Promise<string>; private _pathPromise: Promise<string>;

View file

@ -15,6 +15,7 @@
*/ */
import { Browser } from './browser'; import { Browser } from './browser';
import * as api from '../../types/types';
export class WebKitBrowser extends Browser { export class WebKitBrowser extends Browser implements api.WebKitBrowser {
} }

View file

@ -17,12 +17,14 @@
import { Events } from './events'; import { Events } from './events';
import * as channels from '../protocol/channels'; import * as channels from '../protocol/channels';
import { ChannelOwner } from './channelOwner'; import { ChannelOwner } from './channelOwner';
import { assertMaxArguments, Func1, JSHandle, parseResult, serializeArgument, SmartHandle } from './jsHandle'; import { assertMaxArguments, JSHandle, parseResult, serializeArgument } from './jsHandle';
import { Page } from './page'; import { Page } from './page';
import { BrowserContext } from './browserContext'; import { BrowserContext } from './browserContext';
import { ChromiumBrowserContext } from './chromiumBrowserContext'; import { ChromiumBrowserContext } from './chromiumBrowserContext';
import * as api from '../../types/types';
import * as structs from '../../types/structs';
export class Worker extends ChannelOwner<channels.WorkerChannel, channels.WorkerInitializer> { export class Worker extends ChannelOwner<channels.WorkerChannel, channels.WorkerInitializer> implements api.Worker {
_page: Page | undefined; // Set for web workers. _page: Page | undefined; // Set for web workers.
_context: BrowserContext | undefined; // Set for service workers. _context: BrowserContext | undefined; // Set for service workers.
@ -45,19 +47,15 @@ export class Worker extends ChannelOwner<channels.WorkerChannel, channels.Worker
return this._initializer.url; return this._initializer.url;
} }
async evaluate<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<R>; async evaluate<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): 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> {
assertMaxArguments(arguments.length, 2); assertMaxArguments(arguments.length, 2);
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return parseResult(result.value); return parseResult(result.value);
} }
async evaluateHandle<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<SmartHandle<R>>; async evaluateHandle<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<structs.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>> {
assertMaxArguments(arguments.length, 2); assertMaxArguments(arguments.length, 2);
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }); const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return JSHandle.from(result.handle) as SmartHandle<R>; return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
} }
} }

45
types/structs.d.ts vendored Normal file
View file

@ -0,0 +1,45 @@
/**
* 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 { JSHandle, ElementHandle, Frame, Page, BrowserContext } from './types';
/**
* Can be converted to JSON
*/
export type Serializable = {};
/**
* Can be converted to JSON, but may also contain JSHandles.
*/
export type EvaluationArgument = {};
export type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg);
export type Unboxed<Arg> =
Arg extends ElementHandle<infer T> ? T :
Arg extends JSHandle<infer T> ? T :
Arg extends NoHandles<Arg> ? Arg :
Arg extends [infer A0] ? [Unboxed<A0>] :
Arg extends [infer A0, infer A1] ? [Unboxed<A0>, Unboxed<A1>] :
Arg extends [infer A0, infer A1, infer A2] ? [Unboxed<A0>, Unboxed<A1>, Unboxed<A2>] :
Arg extends [infer A0, infer A1, infer A2, infer A3] ? [Unboxed<A0>, Unboxed<A1>, Unboxed<A2>, Unboxed<A3>] :
Arg extends Array<infer T> ? Array<Unboxed<T>> :
Arg extends object ? { [Key in keyof Arg]: Unboxed<Arg[Key]> } :
Arg;
export type PageFunction0<R> = string | (() => R | Promise<R>);
export type PageFunction<Arg, R> = string | ((arg: Unboxed<Arg>) => R | Promise<R>);
export type PageFunctionOn<On, Arg2, R> = string | ((on: On, arg2: Unboxed<Arg2>) => R | Promise<R>);
export type SmartHandle<T> = T extends Node ? ElementHandle<T> : JSHandle<T>;
export type ElementHandleForTag<K extends keyof HTMLElementTagNameMap> = ElementHandle<HTMLElementTagNameMap[K]>;
export type BindingSource = { context: BrowserContext, page: Page, frame: Frame };

29
types/types.d.ts vendored
View file

@ -18,32 +18,7 @@ import { Protocol } from './protocol';
import { ChildProcess } from 'child_process'; import { ChildProcess } from 'child_process';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { Readable } from 'stream'; import { Readable } from 'stream';
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from './structs';
/**
* Can be converted to JSON
*/
type Serializable = {};
/**
* Can be converted to JSON, but may also contain JSHandles.
*/
type EvaluationArgument = {};
type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg);
type Unboxed<Arg> =
Arg extends ElementHandle<infer T> ? T :
Arg extends JSHandle<infer T> ? T :
Arg extends NoHandles<Arg> ? Arg :
Arg extends [infer A0] ? [Unboxed<A0>] :
Arg extends [infer A0, infer A1] ? [Unboxed<A0>, Unboxed<A1>] :
Arg extends [infer A0, infer A1, infer A2] ? [Unboxed<A0>, Unboxed<A1>, Unboxed<A2>] :
Arg extends [infer A0, infer A1, infer A2, infer A3] ? [Unboxed<A0>, Unboxed<A1>, Unboxed<A2>, Unboxed<A3>] :
Arg extends Array<infer T> ? Array<Unboxed<T>> :
Arg extends object ? { [Key in keyof Arg]: Unboxed<Arg[Key]> } :
Arg;
type PageFunction<Arg, R> = string | ((arg: Unboxed<Arg>) => R | Promise<R>);
type PageFunctionOn<On, Arg2, R> = string | ((on: On, arg2: Unboxed<Arg2>) => R | Promise<R>);
type SmartHandle<T> = T extends Node ? ElementHandle<T> : JSHandle<T>;
type ElementHandleForTag<K extends keyof HTMLElementTagNameMap> = ElementHandle<HTMLElementTagNameMap[K]>;
type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & { type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
state: 'visible'|'attached'; state: 'visible'|'attached';
@ -52,8 +27,6 @@ type ElementHandleWaitForSelectorOptionsNotHidden = ElementHandleWaitForSelector
state: 'visible'|'attached'; state: 'visible'|'attached';
}; };
type BindingSource = { context: BrowserContext, page: Page, frame: Frame };
/** /**
* Page provides methods to interact with a single tab in a Browser, or an extension background page in Chromium. One Browser instance might have multiple Page instances. * Page provides methods to interact with a single tab in a Browser, or an extension background page in Chromium. One Browser instance might have multiple Page instances.
* This example creates a page, navigates it to a URL, and then saves a screenshot: * This example creates a page, navigates it to a URL, and then saves a screenshot:

View file

@ -200,7 +200,8 @@ function compareDocumentations(actual, expected) {
[/Handle\<R\>/g, 'JSHandle'], [/Handle\<R\>/g, 'JSHandle'],
[/JSHandle\<Object\>/g, 'JSHandle'], [/JSHandle\<Object\>/g, 'JSHandle'],
[/object/g, 'Object'], [/object/g, 'Object'],
[/Promise\<T\>/, 'Promise<Object>'] [/Promise\<T\>/, 'Promise<Object>'],
[/TextendsNode\?ElementHandle:null/, 'null|ElementHandle']
] ]
let actualName = actual.name; let actualName = actual.name;
for (const replacer of mdReplacers) for (const replacer of mdReplacers)

View file

@ -17,32 +17,7 @@ import { Protocol } from './protocol';
import { ChildProcess } from 'child_process'; import { ChildProcess } from 'child_process';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { Readable } from 'stream'; import { Readable } from 'stream';
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from './structs';
/**
* Can be converted to JSON
*/
type Serializable = {};
/**
* Can be converted to JSON, but may also contain JSHandles.
*/
type EvaluationArgument = {};
type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg);
type Unboxed<Arg> =
Arg extends ElementHandle<infer T> ? T :
Arg extends JSHandle<infer T> ? T :
Arg extends NoHandles<Arg> ? Arg :
Arg extends [infer A0] ? [Unboxed<A0>] :
Arg extends [infer A0, infer A1] ? [Unboxed<A0>, Unboxed<A1>] :
Arg extends [infer A0, infer A1, infer A2] ? [Unboxed<A0>, Unboxed<A1>, Unboxed<A2>] :
Arg extends [infer A0, infer A1, infer A2, infer A3] ? [Unboxed<A0>, Unboxed<A1>, Unboxed<A2>, Unboxed<A3>] :
Arg extends Array<infer T> ? Array<Unboxed<T>> :
Arg extends object ? { [Key in keyof Arg]: Unboxed<Arg[Key]> } :
Arg;
type PageFunction<Arg, R> = string | ((arg: Unboxed<Arg>) => R | Promise<R>);
type PageFunctionOn<On, Arg2, R> = string | ((on: On, arg2: Unboxed<Arg2>) => R | Promise<R>);
type SmartHandle<T> = T extends Node ? ElementHandle<T> : JSHandle<T>;
type ElementHandleForTag<K extends keyof HTMLElementTagNameMap> = ElementHandle<HTMLElementTagNameMap[K]>;
type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & { type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
state: 'visible'|'attached'; state: 'visible'|'attached';
@ -51,8 +26,6 @@ type ElementHandleWaitForSelectorOptionsNotHidden = ElementHandleWaitForSelector
state: 'visible'|'attached'; state: 'visible'|'attached';
}; };
type BindingSource = { context: BrowserContext, page: Page, frame: Frame };
export interface Page { export interface Page {
evaluate<R, Arg>(pageFunction: PageFunction<Arg, R>, arg: Arg): Promise<R>; evaluate<R, Arg>(pageFunction: PageFunction<Arg, R>, arg: Arg): Promise<R>;
evaluate<R>(pageFunction: PageFunction<void, R>, arg?: any): Promise<R>; evaluate<R>(pageFunction: PageFunction<void, R>, arg?: any): Promise<R>;