feat(rpc): do not use server types and events in rpc/client (#3219)
This change removes almost all dependencies from rpc/client to the rest of the project. The last ones would be utilities like helper, converters, etc.
This commit is contained in:
parent
7dd9f2c290
commit
3bd97776b8
File diff suppressed because it is too large
Load Diff
|
@ -15,10 +15,28 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { PageChannel } from '../channels';
|
||||
import { PageChannel, AXNode } from '../channels';
|
||||
import { ElementHandle } from './elementHandle';
|
||||
import * as types from '../../types';
|
||||
import { axNodeFromProtocol } from '../serializers';
|
||||
|
||||
type SerializedAXNode = Omit<AXNode, 'valueString' | 'valueNumber' | 'children' | 'checked' | 'pressed'> & {
|
||||
value?: string|number,
|
||||
checked?: boolean | 'mixed',
|
||||
pressed?: boolean | 'mixed',
|
||||
children?: SerializedAXNode[]
|
||||
};
|
||||
|
||||
function axNodeFromProtocol(axNode: AXNode): SerializedAXNode {
|
||||
const result: SerializedAXNode = {
|
||||
...axNode,
|
||||
value: axNode.valueNumber !== undefined ? axNode.valueNumber : axNode.valueString,
|
||||
checked: axNode.checked === 'checked' ? true : axNode.checked === 'unchecked' ? false : axNode.checked,
|
||||
pressed: axNode.pressed === 'pressed' ? true : axNode.pressed === 'released' ? false : axNode.pressed,
|
||||
children: axNode.children ? axNode.children.map(axNodeFromProtocol) : undefined,
|
||||
};
|
||||
delete (result as any).valueNumber;
|
||||
delete (result as any).valueString;
|
||||
return result;
|
||||
}
|
||||
|
||||
export class Accessibility {
|
||||
private _channel: PageChannel;
|
||||
|
@ -27,7 +45,7 @@ export class Accessibility {
|
|||
this._channel = channel;
|
||||
}
|
||||
|
||||
async snapshot(options: { interestingOnly?: boolean; root?: ElementHandle } = {}): Promise<types.SerializedAXNode | null> {
|
||||
async snapshot(options: { interestingOnly?: boolean; root?: ElementHandle } = {}): Promise<SerializedAXNode | null> {
|
||||
const root = options.root ? options.root._elementChannel : undefined;
|
||||
const result = await this._channel.accessibilitySnapshot({ interestingOnly: options.interestingOnly, root });
|
||||
return result.rootAXNode ? axNodeFromProtocol(result.rootAXNode) : null;
|
||||
|
|
|
@ -14,15 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { BrowserChannel, BrowserInitializer, BrowserNewContextParams } from '../channels';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { Page } from './page';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Events } from '../../events';
|
||||
import { LoggerSink } from '../../loggerSink';
|
||||
import { Events } from './events';
|
||||
import { BrowserType } from './browserType';
|
||||
import { headersObjectToArray } from '../../converters';
|
||||
import { BrowserContextOptions } from './types';
|
||||
|
||||
export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
||||
readonly _contexts = new Set<BrowserContext>();
|
||||
|
@ -50,7 +49,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
|||
this._closedPromise = new Promise(f => this.once(Events.Browser.Disconnected, f));
|
||||
}
|
||||
|
||||
async newContext(options: types.BrowserContextOptions & { logger?: LoggerSink } = {}): Promise<BrowserContext> {
|
||||
async newContext(options: BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('browser.newContext', async () => {
|
||||
|
@ -75,7 +74,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
|||
return this._initializer.version;
|
||||
}
|
||||
|
||||
async newPage(options: types.BrowserContextOptions & { logger?: LoggerSink } = {}): Promise<Page> {
|
||||
async newPage(options: BrowserContextOptions = {}): Promise<Page> {
|
||||
const context = await this.newContext(options);
|
||||
const page = await context.newPage();
|
||||
page._ownedContext = context;
|
||||
|
|
|
@ -17,20 +17,20 @@
|
|||
|
||||
import * as frames from './frame';
|
||||
import { Page, BindingCall } from './page';
|
||||
import * as types from '../../types';
|
||||
import * as network from './network';
|
||||
import { BrowserContextChannel, BrowserContextInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { helper } from '../../helper';
|
||||
import { Browser } from './browser';
|
||||
import { Events } from '../../events';
|
||||
import { Events } from './events';
|
||||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import { Waiter } from './waiter';
|
||||
import { headersObjectToArray } from '../../converters';
|
||||
import { URLMatch, Headers, WaitForEventOptions } from './types';
|
||||
|
||||
export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserContextInitializer> {
|
||||
_pages = new Set<Page>();
|
||||
private _routes: { url: types.URLMatch, handler: network.RouteHandler }[] = [];
|
||||
private _routes: { url: URLMatch, handler: network.RouteHandler }[] = [];
|
||||
readonly _browser: Browser | undefined;
|
||||
readonly _browserName: string;
|
||||
readonly _bindings = new Map<string, frames.FunctionWithSource>();
|
||||
|
@ -138,13 +138,13 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
|||
});
|
||||
}
|
||||
|
||||
async setGeolocation(geolocation: types.Geolocation | null): Promise<void> {
|
||||
async setGeolocation(geolocation: { longitude: number, latitude: number, accuracy?: number } | null): Promise<void> {
|
||||
return this._wrapApiCall('browserContext.setGeolocation', async () => {
|
||||
await this._channel.setGeolocation({ geolocation: geolocation || undefined });
|
||||
});
|
||||
}
|
||||
|
||||
async setExtraHTTPHeaders(headers: types.Headers): Promise<void> {
|
||||
async setExtraHTTPHeaders(headers: Headers): Promise<void> {
|
||||
return this._wrapApiCall('browserContext.setExtraHTTPHeaders', async () => {
|
||||
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
|
||||
});
|
||||
|
@ -156,7 +156,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
|||
});
|
||||
}
|
||||
|
||||
async setHTTPCredentials(httpCredentials: types.Credentials | null): Promise<void> {
|
||||
async setHTTPCredentials(httpCredentials: { username: string, password: string } | null): Promise<void> {
|
||||
return this._wrapApiCall('browserContext.setHTTPCredentials', async () => {
|
||||
await this._channel.setHTTPCredentials({ httpCredentials: httpCredentials || undefined });
|
||||
});
|
||||
|
@ -186,7 +186,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
|||
await this.exposeBinding(name, (source, ...args) => playwrightFunction(...args));
|
||||
}
|
||||
|
||||
async route(url: types.URLMatch, handler: network.RouteHandler): Promise<void> {
|
||||
async route(url: URLMatch, handler: network.RouteHandler): Promise<void> {
|
||||
return this._wrapApiCall('browserContext.route', async () => {
|
||||
this._routes.push({ url, handler });
|
||||
if (this._routes.length === 1)
|
||||
|
@ -194,7 +194,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
|||
});
|
||||
}
|
||||
|
||||
async unroute(url: types.URLMatch, handler?: network.RouteHandler): Promise<void> {
|
||||
async unroute(url: URLMatch, handler?: network.RouteHandler): Promise<void> {
|
||||
return this._wrapApiCall('browserContext.unroute', async () => {
|
||||
this._routes = this._routes.filter(route => route.url !== url || (handler && route.handler !== handler));
|
||||
if (this._routes.length === 0)
|
||||
|
@ -202,7 +202,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
|||
});
|
||||
}
|
||||
|
||||
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = new Waiter();
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
import { ChildProcess } from 'child_process';
|
||||
import { BrowserServerChannel, BrowserServerInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Events } from '../../events';
|
||||
import { Events } from './events';
|
||||
|
||||
export class BrowserServer extends ChannelOwner<BrowserServerChannel, BrowserServerInitializer> {
|
||||
static from(server: BrowserServerChannel): BrowserServer {
|
||||
|
|
|
@ -14,18 +14,15 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { BrowserTypeChannel, BrowserTypeInitializer, BrowserTypeLaunchParams, BrowserTypeLaunchServerParams, BrowserTypeLaunchPersistentContextParams } from '../channels';
|
||||
import { Browser } from './browser';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { BrowserServer } from './browserServer';
|
||||
import { LoggerSink } from '../../loggerSink';
|
||||
import { headersObjectToArray, envObjectToArray } from '../../converters';
|
||||
import { serializeArgument } from './jsHandle';
|
||||
import { assert } from '../../helper';
|
||||
|
||||
type FirefoxPrefsOptions = { firefoxUserPrefs?: { [key: string]: string | number | boolean } };
|
||||
import { LaunchOptions, LaunchServerOptions, BrowserContextOptions, ConnectOptions } from './types';
|
||||
|
||||
export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {
|
||||
|
||||
|
@ -45,7 +42,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
|||
return this._initializer.name;
|
||||
}
|
||||
|
||||
async launch(options: types.LaunchOptions & FirefoxPrefsOptions & { logger?: LoggerSink } = {}): Promise<Browser> {
|
||||
async launch(options: LaunchOptions = {}): Promise<Browser> {
|
||||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('browserType.launch', async () => {
|
||||
|
@ -64,7 +61,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
|||
}, logger);
|
||||
}
|
||||
|
||||
async launchServer(options: types.LaunchServerOptions & FirefoxPrefsOptions & { logger?: LoggerSink } = {}): Promise<BrowserServer> {
|
||||
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
|
||||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('browserType.launchServer', async () => {
|
||||
|
@ -79,7 +76,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
|||
}, logger);
|
||||
}
|
||||
|
||||
async launchPersistentContext(userDataDir: string, options: types.LaunchOptions & types.BrowserContextOptions & { logger?: LoggerSink } = {}): Promise<BrowserContext> {
|
||||
async launchPersistentContext(userDataDir: string, options: LaunchOptions & BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('browserType.launchPersistentContext', async () => {
|
||||
|
@ -100,7 +97,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
|||
}, logger);
|
||||
}
|
||||
|
||||
async connect(options: types.ConnectOptions & { logger?: LoggerSink }): Promise<Browser> {
|
||||
async connect(options: ConnectOptions): Promise<Browser> {
|
||||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('browserType.connect', async () => {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
import { EventEmitter } from 'events';
|
||||
import type { Channel } from '../channels';
|
||||
import type { Connection } from './connection';
|
||||
import type { LoggerSink } from '../../loggerSink';
|
||||
import type { LoggerSink } from './types';
|
||||
import { DebugLoggerSink } from '../../logger';
|
||||
|
||||
export abstract class ChannelOwner<T extends Channel = Channel, Initializer = {}> extends EventEmitter {
|
||||
|
|
|
@ -19,7 +19,7 @@ import { Page } from './page';
|
|||
import { BrowserContextInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { CDPSession } from './cdpSession';
|
||||
import { Events as ChromiumEvents } from '../../chromium/events';
|
||||
import { Events } from './events';
|
||||
import { Worker } from './worker';
|
||||
import { BrowserContext } from './browserContext';
|
||||
|
||||
|
@ -32,13 +32,13 @@ export class ChromiumBrowserContext extends BrowserContext {
|
|||
this._channel.on('crBackgroundPage', ({ page }) => {
|
||||
const backgroundPage = Page.from(page);
|
||||
this._backgroundPages.add(backgroundPage);
|
||||
this.emit(ChromiumEvents.ChromiumBrowserContext.BackgroundPage, backgroundPage);
|
||||
this.emit(Events.ChromiumBrowserContext.BackgroundPage, backgroundPage);
|
||||
});
|
||||
this._channel.on('crServiceWorker', ({worker}) => {
|
||||
const serviceWorker = Worker.from(worker);
|
||||
serviceWorker._context = this;
|
||||
this._serviceWorkers.add(serviceWorker);
|
||||
this.emit(ChromiumEvents.ChromiumBrowserContext.ServiceWorker, serviceWorker);
|
||||
this.emit(Events.ChromiumBrowserContext.ServiceWorker, serviceWorker);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { PageChannel } from '../channels';
|
||||
import { PageChannel, PageCrStartJSCoverageOptions, PageCrStopJSCoverageResult, PageCrStartCSSCoverageOptions, PageCrStopCSSCoverageResult } from '../channels';
|
||||
|
||||
let __dummyJSResult: PageCrStopJSCoverageResult;
|
||||
type PageCrStopJSCoverageResultEntries = typeof __dummyJSResult.entries;
|
||||
let __dummyCSSResult: PageCrStopCSSCoverageResult;
|
||||
type PageCrStopCSSCoverageResultEntries = typeof __dummyCSSResult.entries;
|
||||
|
||||
export class ChromiumCoverage {
|
||||
private _channel: PageChannel;
|
||||
|
@ -24,19 +28,19 @@ export class ChromiumCoverage {
|
|||
this._channel = channel;
|
||||
}
|
||||
|
||||
async startJSCoverage(options: types.JSCoverageOptions = {}) {
|
||||
async startJSCoverage(options: PageCrStartJSCoverageOptions = {}) {
|
||||
await this._channel.crStartJSCoverage(options);
|
||||
}
|
||||
|
||||
async stopJSCoverage(): Promise<types.JSCoverageEntry[]> {
|
||||
async stopJSCoverage(): Promise<PageCrStopJSCoverageResultEntries> {
|
||||
return (await this._channel.crStopJSCoverage()).entries;
|
||||
}
|
||||
|
||||
async startCSSCoverage(options: types.CSSCoverageOptions = {}) {
|
||||
async startCSSCoverage(options: PageCrStartCSSCoverageOptions = {}) {
|
||||
await this._channel.crStartCSSCoverage(options);
|
||||
}
|
||||
|
||||
async stopCSSCoverage(): Promise<types.CSSCoverageEntry[]> {
|
||||
async stopCSSCoverage(): Promise<PageCrStopCSSCoverageResultEntries> {
|
||||
return (await this._channel.crStopCSSCoverage()).entries;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
*/
|
||||
|
||||
import * as util from 'util';
|
||||
import { ConsoleMessageLocation } from '../../types';
|
||||
import { JSHandle } from './jsHandle';
|
||||
import { ConsoleMessageChannel, ConsoleMessageInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
|
||||
let __dummyInitializer: ConsoleMessageInitializer;
|
||||
type ConsoleMessageLocation = typeof __dummyInitializer.location;
|
||||
|
||||
export class ConsoleMessage extends ChannelOwner<ConsoleMessageChannel, ConsoleMessageInitializer> {
|
||||
static from(message: ConsoleMessageChannel): ConsoleMessage {
|
||||
return (message as any)._object;
|
||||
|
|
|
@ -14,18 +14,16 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { ElectronChannel, ElectronInitializer, ElectronApplicationChannel, ElectronApplicationInitializer, ElectronLaunchParams } from '../channels';
|
||||
import { ElectronChannel, ElectronInitializer, ElectronApplicationChannel, ElectronApplicationInitializer, ElectronLaunchParams, ElectronLaunchOptions } from '../channels';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Page } from './page';
|
||||
import { serializeArgument, FuncOn, parseResult, SmartHandle, JSHandle } from './jsHandle';
|
||||
import { ElectronEvents, ElectronLaunchOptionsBase } from '../../server/electron';
|
||||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import { Waiter } from './waiter';
|
||||
import { Events } from '../../events';
|
||||
import { LoggerSink } from '../../loggerSink';
|
||||
import { Events } from './events';
|
||||
import { envObjectToArray } from '../../converters';
|
||||
import { WaitForEventOptions, Env, LoggerSink } from './types';
|
||||
|
||||
export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer> {
|
||||
static from(electron: ElectronChannel): Electron {
|
||||
|
@ -36,7 +34,7 @@ export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer>
|
|||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
async launch(executablePath: string, options: ElectronLaunchOptionsBase & { logger?: LoggerSink } = {}): Promise<ElectronApplication> {
|
||||
async launch(executablePath: string, options: ElectronLaunchOptions & { env?: Env, logger?: LoggerSink } = {}): Promise<ElectronApplication> {
|
||||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('electron.launch', async () => {
|
||||
|
@ -66,10 +64,10 @@ export class ElectronApplication extends ChannelOwner<ElectronApplicationChannel
|
|||
const window = Page.from(page);
|
||||
(window as any).browserWindow = JSHandle.from(browserWindow);
|
||||
this._windows.add(window);
|
||||
this.emit(ElectronEvents.ElectronApplication.Window, window);
|
||||
this.emit(Events.ElectronApplication.Window, window);
|
||||
window.once(Events.Page.Close, () => this._windows.delete(window));
|
||||
});
|
||||
this._channel.on('close', () => this.emit(ElectronEvents.ElectronApplication.Close));
|
||||
this._channel.on('close', () => this.emit(Events.ElectronApplication.Close));
|
||||
}
|
||||
|
||||
windows(): Page[] {
|
||||
|
@ -95,13 +93,13 @@ export class ElectronApplication extends ChannelOwner<ElectronApplicationChannel
|
|||
await this._channel.close();
|
||||
}
|
||||
|
||||
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = new Waiter();
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
if (event !== ElectronEvents.ElectronApplication.Close)
|
||||
waiter.rejectOnEvent(this, ElectronEvents.ElectronApplication.Close, new Error('Electron application closed'));
|
||||
if (event !== Events.ElectronApplication.Close)
|
||||
waiter.rejectOnEvent(this, Events.ElectronApplication.Close, new Error('Electron application closed'));
|
||||
const result = await waiter.waitForEvent(this, event, predicate as any);
|
||||
waiter.dispose();
|
||||
return result;
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { ElementHandleChannel, JSHandleInitializer } from '../channels';
|
||||
import { ElementHandleChannel, JSHandleInitializer, ElementHandleScrollIntoViewIfNeededOptions, ElementHandleHoverOptions, ElementHandleClickOptions, ElementHandleDblclickOptions, ElementHandleSelectOptionOptions, ElementHandleFillOptions, ElementHandleSetInputFilesOptions, ElementHandlePressOptions, ElementHandleCheckOptions, ElementHandleUncheckOptions, ElementHandleScreenshotOptions, ElementHandleTypeOptions } from '../channels';
|
||||
import { Frame } from './frame';
|
||||
import { FuncOn, JSHandle, serializeArgument, parseResult } from './jsHandle';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { helper, assert } from '../../helper';
|
||||
import { normalizeFilePayloads } from '../../converters';
|
||||
import { SelectOption, FilePayload, Rect, SelectOptionOptions } from './types';
|
||||
|
||||
export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
||||
readonly _elementChannel: ElementHandleChannel;
|
||||
|
@ -86,50 +86,50 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
|||
});
|
||||
}
|
||||
|
||||
async scrollIntoViewIfNeeded(options: types.TimeoutOptions = {}) {
|
||||
async scrollIntoViewIfNeeded(options: ElementHandleScrollIntoViewIfNeededOptions = {}) {
|
||||
return this._wrapApiCall('elementHandle.scrollIntoViewIfNeeded', async () => {
|
||||
await this._elementChannel.scrollIntoViewIfNeeded(options);
|
||||
});
|
||||
}
|
||||
|
||||
async hover(options: types.PointerActionOptions & types.PointerActionWaitOptions = {}): Promise<void> {
|
||||
async hover(options: ElementHandleHoverOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall('elementHandle.hover', async () => {
|
||||
await this._elementChannel.hover(options);
|
||||
});
|
||||
}
|
||||
|
||||
async click(options: types.MouseClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||
async click(options: ElementHandleClickOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall('elementHandle.click', async () => {
|
||||
return await this._elementChannel.click(options);
|
||||
});
|
||||
}
|
||||
|
||||
async dblclick(options: types.MouseMultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||
async dblclick(options: ElementHandleDblclickOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall('elementHandle.dblclick', async () => {
|
||||
return await this._elementChannel.dblclick(options);
|
||||
});
|
||||
}
|
||||
|
||||
async selectOption(values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[] | null, options: types.NavigatingActionWaitOptions = {}): Promise<string[]> {
|
||||
async selectOption(values: string | ElementHandle | SelectOption | string[] | ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> {
|
||||
return this._wrapApiCall('elementHandle.selectOption', async () => {
|
||||
const result = await this._elementChannel.selectOption({ ...convertSelectOptionValues(values), ...options });
|
||||
return result.values;
|
||||
});
|
||||
}
|
||||
|
||||
async fill(value: string, options: types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||
async fill(value: string, options: ElementHandleFillOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall('elementHandle.fill', async () => {
|
||||
return await this._elementChannel.fill({ value, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async selectText(options: types.TimeoutOptions = {}): Promise<void> {
|
||||
async selectText(options: ElementHandleSelectOptionOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall('elementHandle.selectText', async () => {
|
||||
await this._elementChannel.selectText(options);
|
||||
});
|
||||
}
|
||||
|
||||
async setInputFiles(files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}) {
|
||||
async setInputFiles(files: string | FilePayload | string[] | FilePayload[], options: ElementHandleSetInputFilesOptions = {}) {
|
||||
return this._wrapApiCall('elementHandle.setInputFiles', async () => {
|
||||
await this._elementChannel.setInputFiles({ files: await convertInputFiles(files), ...options });
|
||||
});
|
||||
|
@ -141,38 +141,38 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
|||
});
|
||||
}
|
||||
|
||||
async type(text: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||
async type(text: string, options: ElementHandleTypeOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall('elementHandle.type', async () => {
|
||||
await this._elementChannel.type({ text, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async press(key: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||
async press(key: string, options: ElementHandlePressOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall('elementHandle.press', async () => {
|
||||
await this._elementChannel.press({ key, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async check(options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||
async check(options: ElementHandleCheckOptions = {}) {
|
||||
return this._wrapApiCall('elementHandle.check', async () => {
|
||||
return await this._elementChannel.check(options);
|
||||
});
|
||||
}
|
||||
|
||||
async uncheck(options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||
async uncheck(options: ElementHandleUncheckOptions = {}) {
|
||||
return this._wrapApiCall('elementHandle.uncheck', async () => {
|
||||
return await this._elementChannel.uncheck(options);
|
||||
});
|
||||
}
|
||||
|
||||
async boundingBox(): Promise<types.Rect | null> {
|
||||
async boundingBox(): Promise<Rect | null> {
|
||||
return this._wrapApiCall('elementHandle.boundingBox', async () => {
|
||||
const value = (await this._elementChannel.boundingBox()).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
}
|
||||
|
||||
async screenshot(options: types.ElementScreenshotOptions = {}): Promise<Buffer> {
|
||||
async screenshot(options: ElementHandleScreenshotOptions = {}): Promise<Buffer> {
|
||||
return this._wrapApiCall('elementHandle.screenshot', async () => {
|
||||
return Buffer.from((await this._elementChannel.screenshot(options)).binary, 'base64');
|
||||
});
|
||||
|
@ -210,7 +210,7 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
|||
}
|
||||
}
|
||||
|
||||
export function convertSelectOptionValues(values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[] | null): { elements?: ElementHandleChannel[], options?: types.SelectOption[] } {
|
||||
export function convertSelectOptionValues(values: string | ElementHandle | SelectOption | string[] | ElementHandle[] | SelectOption[] | null): { elements?: ElementHandleChannel[], options?: SelectOption[] } {
|
||||
if (!values)
|
||||
return {};
|
||||
if (!Array.isArray(values))
|
||||
|
@ -224,10 +224,10 @@ export function convertSelectOptionValues(values: string | ElementHandle | types
|
|||
return { elements: (values as ElementHandle[]).map((v: ElementHandle) => v._elementChannel) };
|
||||
if (helper.isString(values[0]))
|
||||
return { options: (values as string[]).map(value => ({ value })) };
|
||||
return { options: values as types.SelectOption[] };
|
||||
return { options: values as SelectOption[] };
|
||||
}
|
||||
|
||||
export async function convertInputFiles(files: string | types.FilePayload | string[] | types.FilePayload[]): Promise<{ name: string, mimeType: string, buffer: string }[]> {
|
||||
export async function convertInputFiles(files: string | FilePayload | string[] | FilePayload[]): Promise<{ name: string, mimeType: string, buffer: string }[]> {
|
||||
const filePayloads = await normalizeFilePayloads(files);
|
||||
return filePayloads.map(f => ({ name: f.name, mimeType: f.mimeType, buffer: f.buffer.toString('base64') }));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright 2019 Google Inc. All rights reserved.
|
||||
* Modifications 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.
|
||||
*/
|
||||
|
||||
export const Events = {
|
||||
Browser: {
|
||||
Disconnected: 'disconnected'
|
||||
},
|
||||
|
||||
BrowserContext: {
|
||||
Close: 'close',
|
||||
Page: 'page',
|
||||
},
|
||||
|
||||
BrowserServer: {
|
||||
Close: 'close',
|
||||
},
|
||||
|
||||
Page: {
|
||||
Close: 'close',
|
||||
Crash: 'crash',
|
||||
Console: 'console',
|
||||
Dialog: 'dialog',
|
||||
Download: 'download',
|
||||
FileChooser: 'filechooser',
|
||||
DOMContentLoaded: 'domcontentloaded',
|
||||
// Can't use just 'error' due to node.js special treatment of error events.
|
||||
// @see https://nodejs.org/api/events.html#events_error_events
|
||||
PageError: 'pageerror',
|
||||
Request: 'request',
|
||||
Response: 'response',
|
||||
RequestFailed: 'requestfailed',
|
||||
RequestFinished: 'requestfinished',
|
||||
FrameAttached: 'frameattached',
|
||||
FrameDetached: 'framedetached',
|
||||
FrameNavigated: 'framenavigated',
|
||||
Load: 'load',
|
||||
Popup: 'popup',
|
||||
Worker: 'worker',
|
||||
},
|
||||
|
||||
Worker: {
|
||||
Close: 'close',
|
||||
},
|
||||
|
||||
ChromiumBrowserContext: {
|
||||
BackgroundPage: 'backgroundpage',
|
||||
ServiceWorker: 'serviceworker',
|
||||
},
|
||||
|
||||
ElectronApplication: {
|
||||
Close: 'close',
|
||||
Window: 'window',
|
||||
},
|
||||
};
|
|
@ -14,9 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { ElementHandle } from './elementHandle';
|
||||
import { Page } from './page';
|
||||
import { FilePayload } from './types';
|
||||
import { ElementHandleSetInputFilesOptions } from '../channels';
|
||||
|
||||
export class FileChooser {
|
||||
private _page: Page;
|
||||
|
@ -41,7 +42,7 @@ export class FileChooser {
|
|||
return this._page;
|
||||
}
|
||||
|
||||
async setFiles(files: string | types.FilePayload | string[] | types.FilePayload[], options?: types.NavigatingActionWaitOptions) {
|
||||
async setFiles(files: string | FilePayload | string[] | FilePayload[], options?: ElementHandleSetInputFilesOptions) {
|
||||
return this._elementHandle.setInputFiles(files, options);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
*/
|
||||
|
||||
import { assertMaxArguments, helper, assert } from '../../helper';
|
||||
import * as types from '../../types';
|
||||
import { FrameChannel, FrameInitializer, FrameNavigatedEvent } from '../channels';
|
||||
import { FrameChannel, FrameInitializer, FrameNavigatedEvent, FrameGotoOptions, FrameWaitForSelectorOptions, FrameDispatchEventOptions, FrameSetContentOptions, FrameClickOptions, FrameDblclickOptions, FrameFillOptions, FrameFocusOptions, FrameTextContentOptions, FrameInnerTextOptions, FrameInnerHTMLOptions, FrameGetAttributeOptions, FrameHoverOptions, FrameSetInputFilesOptions, FrameTypeOptions, FramePressOptions, FrameCheckOptions, FrameUncheckOptions } from '../channels';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { ElementHandle, convertSelectOptionValues, convertInputFiles } from './elementHandle';
|
||||
|
@ -28,19 +27,21 @@ import * as util from 'util';
|
|||
import { Page } from './page';
|
||||
import { EventEmitter } from 'events';
|
||||
import { Waiter } from './waiter';
|
||||
import { Events } from '../../events';
|
||||
import { Events } from './events';
|
||||
import { LifecycleEvent, URLMatch, SelectOption, SelectOptionOptions, FilePayload, WaitForFunctionOptions, kLifecycleEvents } from './types';
|
||||
|
||||
const fsReadFileAsync = util.promisify(fs.readFile.bind(fs));
|
||||
|
||||
export type GotoOptions = types.NavigateOptions & {
|
||||
referer?: string,
|
||||
};
|
||||
|
||||
export type FunctionWithSource = (source: { context: BrowserContext, page: Page, frame: Frame }, ...args: any) => any;
|
||||
export type WaitForNavigationOptions = {
|
||||
timeout?: number,
|
||||
waitUntil?: LifecycleEvent,
|
||||
url?: URLMatch,
|
||||
};
|
||||
|
||||
export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
||||
_eventEmitter: EventEmitter;
|
||||
_loadStates: Set<types.LifecycleEvent>;
|
||||
_loadStates: Set<LifecycleEvent>;
|
||||
_parentFrame: Frame | null = null;
|
||||
_url = '';
|
||||
_name = '';
|
||||
|
@ -87,14 +88,14 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
return this._page!._isPageCall ? 'page.' + method : 'frame.' + method;
|
||||
}
|
||||
|
||||
async goto(url: string, options: GotoOptions = {}): Promise<network.Response | null> {
|
||||
async goto(url: string, options: FrameGotoOptions = {}): Promise<network.Response | null> {
|
||||
return this._wrapApiCall(this._apiName('goto'), async () => {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
return network.Response.fromNullable((await this._channel.goto({ url, ...options, waitUntil })).response);
|
||||
});
|
||||
}
|
||||
|
||||
private _setupNavigationWaiter(options: types.TimeoutOptions): Waiter {
|
||||
private _setupNavigationWaiter(options: { timeout?: number }): Waiter {
|
||||
const waiter = new Waiter();
|
||||
waiter.rejectOnEvent(this._page!, Events.Page.Close, new Error('Navigation failed because page was closed!'));
|
||||
waiter.rejectOnEvent(this._page!, Events.Page.Crash, new Error('Navigation failed because page crashed!'));
|
||||
|
@ -105,7 +106,7 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
return waiter;
|
||||
}
|
||||
|
||||
async waitForNavigation(options: types.WaitForNavigationOptions = {}): Promise<network.Response | null> {
|
||||
async waitForNavigation(options: WaitForNavigationOptions = {}): Promise<network.Response | null> {
|
||||
return this._wrapApiCall(this._apiName('waitForNavigation'), async () => {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
const waiter = this._setupNavigationWaiter(options);
|
||||
|
@ -127,7 +128,7 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
}
|
||||
|
||||
if (!this._loadStates.has(waitUntil)) {
|
||||
await waiter.waitForEvent<types.LifecycleEvent>(this._eventEmitter, 'loadstate', s => {
|
||||
await waiter.waitForEvent<LifecycleEvent>(this._eventEmitter, 'loadstate', s => {
|
||||
waiter.log(` "${s}" event fired`);
|
||||
return s === waitUntil;
|
||||
});
|
||||
|
@ -140,13 +141,13 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async waitForLoadState(state: types.LifecycleEvent = 'load', options: types.TimeoutOptions = {}): Promise<void> {
|
||||
async waitForLoadState(state: LifecycleEvent = 'load', options: { timeout?: number } = {}): Promise<void> {
|
||||
state = verifyLoadState('state', state);
|
||||
if (this._loadStates.has(state))
|
||||
return;
|
||||
return this._wrapApiCall(this._apiName('waitForLoadState'), async () => {
|
||||
const waiter = this._setupNavigationWaiter(options);
|
||||
await waiter.waitForEvent<types.LifecycleEvent>(this._eventEmitter, 'loadstate', s => {
|
||||
await waiter.waitForEvent<LifecycleEvent>(this._eventEmitter, 'loadstate', s => {
|
||||
waiter.log(` "${s}" event fired`);
|
||||
return s === state;
|
||||
});
|
||||
|
@ -187,7 +188,7 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async waitForSelector(selector: string, options: types.WaitForElementOptions = {}): Promise<ElementHandle<Element> | null> {
|
||||
async waitForSelector(selector: string, options: FrameWaitForSelectorOptions = {}): Promise<ElementHandle<Element> | null> {
|
||||
return this._wrapApiCall(this._apiName('waitForSelector'), async () => {
|
||||
if ((options as any).visibility)
|
||||
throw new Error('options.visibility is not supported, did you mean options.state?');
|
||||
|
@ -198,7 +199,7 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async dispatchEvent(selector: string, type: string, eventInit?: any, options: types.TimeoutOptions = {}): Promise<void> {
|
||||
async dispatchEvent(selector: string, type: string, eventInit?: any, options: FrameDispatchEventOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(this._apiName('dispatchEvent'), async () => {
|
||||
await this._channel.dispatchEvent({ selector, type, eventInit: serializeArgument(eventInit), ...options });
|
||||
});
|
||||
|
@ -237,7 +238,7 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async setContent(html: string, options: types.NavigateOptions = {}): Promise<void> {
|
||||
async setContent(html: string, options: FrameSetContentOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(this._apiName('setContent'), async () => {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
await this._channel.setContent({ html, ...options, waitUntil });
|
||||
|
@ -286,93 +287,93 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async click(selector: string, options: types.MouseClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||
async click(selector: string, options: FrameClickOptions = {}) {
|
||||
return this._wrapApiCall(this._apiName('click'), async () => {
|
||||
return await this._channel.click({ selector, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async dblclick(selector: string, options: types.MouseMultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||
async dblclick(selector: string, options: FrameDblclickOptions = {}) {
|
||||
return this._wrapApiCall(this._apiName('dblclick'), async () => {
|
||||
return await this._channel.dblclick({ selector, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async fill(selector: string, value: string, options: types.NavigatingActionWaitOptions = {}) {
|
||||
async fill(selector: string, value: string, options: FrameFillOptions = {}) {
|
||||
return this._wrapApiCall(this._apiName('fill'), async () => {
|
||||
return await this._channel.fill({ selector, value, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async focus(selector: string, options: types.TimeoutOptions = {}) {
|
||||
async focus(selector: string, options: FrameFocusOptions = {}) {
|
||||
return this._wrapApiCall(this._apiName('focus'), async () => {
|
||||
await this._channel.focus({ selector, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async textContent(selector: string, options: types.TimeoutOptions = {}): Promise<null|string> {
|
||||
async textContent(selector: string, options: FrameTextContentOptions = {}): Promise<null|string> {
|
||||
return this._wrapApiCall(this._apiName('textContent'), async () => {
|
||||
const value = (await this._channel.textContent({ selector, ...options })).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
}
|
||||
|
||||
async innerText(selector: string, options: types.TimeoutOptions = {}): Promise<string> {
|
||||
async innerText(selector: string, options: FrameInnerTextOptions = {}): Promise<string> {
|
||||
return this._wrapApiCall(this._apiName('innerText'), async () => {
|
||||
return (await this._channel.innerText({ selector, ...options })).value;
|
||||
});
|
||||
}
|
||||
|
||||
async innerHTML(selector: string, options: types.TimeoutOptions = {}): Promise<string> {
|
||||
async innerHTML(selector: string, options: FrameInnerHTMLOptions = {}): Promise<string> {
|
||||
return this._wrapApiCall(this._apiName('innerHTML'), async () => {
|
||||
return (await this._channel.innerHTML({ selector, ...options })).value;
|
||||
});
|
||||
}
|
||||
|
||||
async getAttribute(selector: string, name: string, options: types.TimeoutOptions = {}): Promise<string | null> {
|
||||
async getAttribute(selector: string, name: string, options: FrameGetAttributeOptions = {}): Promise<string | null> {
|
||||
return this._wrapApiCall(this._apiName('getAttribute'), async () => {
|
||||
const value = (await this._channel.getAttribute({ selector, name, ...options })).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
}
|
||||
|
||||
async hover(selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions = {}) {
|
||||
async hover(selector: string, options: FrameHoverOptions = {}) {
|
||||
return this._wrapApiCall(this._apiName('hover'), async () => {
|
||||
await this._channel.hover({ selector, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async selectOption(selector: string, values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[] | null, options: types.NavigatingActionWaitOptions = {}): Promise<string[]> {
|
||||
async selectOption(selector: string, values: string | ElementHandle | SelectOption | string[] | ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> {
|
||||
return this._wrapApiCall(this._apiName('selectOption'), async () => {
|
||||
return (await this._channel.selectOption({ selector, ...convertSelectOptionValues(values), ...options })).values;
|
||||
});
|
||||
}
|
||||
|
||||
async setInputFiles(selector: string, files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||
async setInputFiles(selector: string, files: string | FilePayload | string[] | FilePayload[], options: FrameSetInputFilesOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(this._apiName('setInputFiles'), async () => {
|
||||
await this._channel.setInputFiles({ selector, files: await convertInputFiles(files), ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async type(selector: string, text: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
||||
async type(selector: string, text: string, options: FrameTypeOptions = {}) {
|
||||
return this._wrapApiCall(this._apiName('type'), async () => {
|
||||
await this._channel.type({ selector, text, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async press(selector: string, key: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
||||
async press(selector: string, key: string, options: FramePressOptions = {}) {
|
||||
return this._wrapApiCall(this._apiName('press'), async () => {
|
||||
await this._channel.press({ selector, key, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async check(selector: string, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||
async check(selector: string, options: FrameCheckOptions = {}) {
|
||||
return this._wrapApiCall(this._apiName('check'), async () => {
|
||||
await this._channel.check({ selector, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async uncheck(selector: string, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||
async uncheck(selector: string, options: FrameUncheckOptions = {}) {
|
||||
return this._wrapApiCall(this._apiName('uncheck'), async () => {
|
||||
await this._channel.uncheck({ selector, ...options });
|
||||
});
|
||||
|
@ -382,9 +383,9 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
await new Promise(fulfill => setTimeout(fulfill, timeout));
|
||||
}
|
||||
|
||||
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, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options: types.WaitForFunctionOptions = {}): Promise<SmartHandle<R>> {
|
||||
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options?: WaitForFunctionOptions): Promise<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 () => {
|
||||
if (typeof options.polling === 'string')
|
||||
assert(options.polling === 'raf', 'Unknown polling option: ' + options.polling);
|
||||
|
@ -406,10 +407,10 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
}
|
||||
}
|
||||
|
||||
export function verifyLoadState(name: string, waitUntil: types.LifecycleEvent): types.LifecycleEvent {
|
||||
export function verifyLoadState(name: string, waitUntil: LifecycleEvent): LifecycleEvent {
|
||||
if (waitUntil as unknown === 'networkidle0')
|
||||
waitUntil = 'networkidle';
|
||||
if (!types.kLifecycleEvents.has(waitUntil))
|
||||
if (!kLifecycleEvents.has(waitUntil))
|
||||
throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle)`);
|
||||
return waitUntil;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { PageChannel } from '../channels';
|
||||
import { PageChannel, PageKeyboardTypeOptions, PageKeyboardPressOptions, PageMouseDownOptions, PageMouseUpOptions, PageMouseClickOptions } from '../channels';
|
||||
|
||||
export class Keyboard {
|
||||
private _channel: PageChannel;
|
||||
|
@ -37,11 +36,11 @@ export class Keyboard {
|
|||
await this._channel.keyboardInsertText({ text });
|
||||
}
|
||||
|
||||
async type(text: string, options: { delay?: number } = {}) {
|
||||
async type(text: string, options: PageKeyboardTypeOptions = {}) {
|
||||
await this._channel.keyboardType({ text, ...options });
|
||||
}
|
||||
|
||||
async press(key: string, options: { delay?: number } = {}) {
|
||||
async press(key: string, options: PageKeyboardPressOptions = {}) {
|
||||
await this._channel.keyboardPress({ key, ...options });
|
||||
}
|
||||
}
|
||||
|
@ -57,19 +56,19 @@ export class Mouse {
|
|||
await this._channel.mouseMove({ x, y, ...options });
|
||||
}
|
||||
|
||||
async down(options: { button?: types.MouseButton, clickCount?: number } = {}) {
|
||||
async down(options: PageMouseDownOptions = {}) {
|
||||
await this._channel.mouseDown({ ...options });
|
||||
}
|
||||
|
||||
async up(options: { button?: types.MouseButton, clickCount?: number } = {}) {
|
||||
async up(options: PageMouseUpOptions = {}) {
|
||||
await this._channel.mouseUp(options);
|
||||
}
|
||||
|
||||
async click(x: number, y: number, options: { delay?: number, button?: types.MouseButton, clickCount?: number } = {}) {
|
||||
async click(x: number, y: number, options: PageMouseClickOptions = {}) {
|
||||
await this._channel.mouseClick({ x, y, ...options });
|
||||
}
|
||||
|
||||
async dblclick(x: number, y: number, options: { delay?: number, button?: types.MouseButton } = {}) {
|
||||
async dblclick(x: number, y: number, options: Omit<PageMouseClickOptions, 'clickCount'> = {}) {
|
||||
await this.click(x, y, { ...options, clickCount: 2 });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
*/
|
||||
|
||||
import { URLSearchParams } from 'url';
|
||||
import * as types from '../../types';
|
||||
import { RequestChannel, ResponseChannel, RouteChannel, RequestInitializer, ResponseInitializer, RouteInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Frame } from './frame';
|
||||
import { normalizeFulfillParameters, headersArrayToObject, normalizeContinueOverrides } from '../../converters';
|
||||
import { Headers } from './types';
|
||||
|
||||
export type NetworkCookie = {
|
||||
name: string,
|
||||
|
@ -44,11 +44,24 @@ export type SetNetworkCookieParam = {
|
|||
sameSite?: 'Strict' | 'Lax' | 'None'
|
||||
};
|
||||
|
||||
type FulfillResponse = {
|
||||
status?: number,
|
||||
headers?: Headers,
|
||||
contentType?: string,
|
||||
body?: string | Buffer,
|
||||
};
|
||||
|
||||
type ContinueOverrides = {
|
||||
method?: string,
|
||||
headers?: Headers,
|
||||
postData?: string | Buffer,
|
||||
};
|
||||
|
||||
export class Request extends ChannelOwner<RequestChannel, RequestInitializer> {
|
||||
private _redirectedFrom: Request | null = null;
|
||||
private _redirectedTo: Request | null = null;
|
||||
_failureText: string | null = null;
|
||||
private _headers: types.Headers;
|
||||
private _headers: Headers;
|
||||
private _postData: Buffer | null;
|
||||
|
||||
static from(request: RequestChannel): Request {
|
||||
|
@ -108,7 +121,7 @@ export class Request extends ChannelOwner<RequestChannel, RequestInitializer> {
|
|||
return JSON.parse(postData);
|
||||
}
|
||||
|
||||
headers(): types.Headers {
|
||||
headers(): Headers {
|
||||
return { ...this._headers };
|
||||
}
|
||||
|
||||
|
@ -162,12 +175,12 @@ export class Route extends ChannelOwner<RouteChannel, RouteInitializer> {
|
|||
await this._channel.abort({ errorCode });
|
||||
}
|
||||
|
||||
async fulfill(response: types.FulfillResponse & { path?: string }) {
|
||||
async fulfill(response: FulfillResponse & { path?: string }) {
|
||||
const normalized = await normalizeFulfillParameters(response);
|
||||
await this._channel.fulfill(normalized);
|
||||
}
|
||||
|
||||
async continue(overrides: types.ContinueOverrides = {}) {
|
||||
async continue(overrides: ContinueOverrides = {}) {
|
||||
const normalized = normalizeContinueOverrides(overrides);
|
||||
await this._channel.continue({
|
||||
method: normalized.method,
|
||||
|
@ -180,7 +193,7 @@ export class Route extends ChannelOwner<RouteChannel, RouteInitializer> {
|
|||
export type RouteHandler = (route: Route, request: Request) => void;
|
||||
|
||||
export class Response extends ChannelOwner<ResponseChannel, ResponseInitializer> {
|
||||
private _headers: types.Headers;
|
||||
private _headers: Headers;
|
||||
|
||||
static from(response: ResponseChannel): Response {
|
||||
return (response as any)._object;
|
||||
|
@ -211,7 +224,7 @@ export class Response extends ChannelOwner<ResponseChannel, ResponseInitializer>
|
|||
return this._initializer.statusText;
|
||||
}
|
||||
|
||||
headers(): types.Headers {
|
||||
headers(): Headers {
|
||||
return { ...this._headers };
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Events } from '../../events';
|
||||
import { Events } from './events';
|
||||
import { assert, assertMaxArguments, helper, Listener } from '../../helper';
|
||||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import * as types from '../../types';
|
||||
import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer, PagePdfParams } from '../channels';
|
||||
import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer, PagePdfParams, FrameWaitForSelectorOptions, FrameDispatchEventOptions, FrameSetContentOptions, FrameGotoOptions, PageReloadOptions, PageGoBackOptions, PageGoForwardOptions, PageScreenshotOptions, FrameClickOptions, FrameDblclickOptions, FrameFillOptions, FrameFocusOptions, FrameTextContentOptions, FrameInnerTextOptions, FrameInnerHTMLOptions, FrameGetAttributeOptions, FrameHoverOptions, FrameSetInputFilesOptions, FrameTypeOptions, FramePressOptions, FrameCheckOptions, FrameUncheckOptions } from '../channels';
|
||||
import { parseError, serializeError } from '../serializers';
|
||||
import { headersObjectToArray } from '../../converters';
|
||||
import { Accessibility } from './accessibility';
|
||||
|
@ -30,7 +29,7 @@ import { Dialog } from './dialog';
|
|||
import { Download } from './download';
|
||||
import { ElementHandle } from './elementHandle';
|
||||
import { Worker } from './worker';
|
||||
import { Frame, FunctionWithSource, GotoOptions, verifyLoadState } from './frame';
|
||||
import { Frame, FunctionWithSource, verifyLoadState, WaitForNavigationOptions } from './frame';
|
||||
import { Keyboard, Mouse } from './input';
|
||||
import { Func1, FuncOn, SmartHandle, serializeArgument, parseResult } from './jsHandle';
|
||||
import { Request, Response, Route, RouteHandler } from './network';
|
||||
|
@ -41,6 +40,19 @@ import { Waiter } from './waiter';
|
|||
|
||||
import * as fs from 'fs';
|
||||
import * as util from 'util';
|
||||
import { Size, URLMatch, Headers, LifecycleEvent, WaitForEventOptions, SelectOption, SelectOptionOptions, FilePayload, WaitForFunctionOptions } from './types';
|
||||
|
||||
type PDFOptions = Omit<PagePdfParams, 'width' | 'height' | 'margin'> & {
|
||||
width?: string | number,
|
||||
height?: string | number,
|
||||
margin?: {
|
||||
top?: string | number,
|
||||
bottom?: string | number,
|
||||
left?: string | number,
|
||||
right?: string | number
|
||||
},
|
||||
path?: string,
|
||||
};
|
||||
|
||||
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
|
||||
|
||||
|
@ -52,14 +64,14 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
private _frames = new Set<Frame>();
|
||||
_workers = new Set<Worker>();
|
||||
private _closed = false;
|
||||
private _viewportSize: types.Size | null;
|
||||
private _routes: { url: types.URLMatch, handler: RouteHandler }[] = [];
|
||||
private _viewportSize: Size | null;
|
||||
private _routes: { url: URLMatch, handler: RouteHandler }[] = [];
|
||||
|
||||
readonly accessibility: Accessibility;
|
||||
readonly keyboard: Keyboard;
|
||||
readonly mouse: Mouse;
|
||||
coverage: ChromiumCoverage | null = null;
|
||||
pdf?: (options?: types.PDFOptions) => Promise<Buffer>;
|
||||
pdf?: (options?: PDFOptions) => Promise<Buffer>;
|
||||
|
||||
readonly _bindings = new Map<string, FunctionWithSource>();
|
||||
readonly _timeoutSettings: TimeoutSettings;
|
||||
|
@ -183,7 +195,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return this._mainFrame;
|
||||
}
|
||||
|
||||
frame(options: string | { name?: string, url?: types.URLMatch }): Frame | null {
|
||||
frame(options: string | { name?: string, url?: URLMatch }): Frame | null {
|
||||
const name = helper.isString(options) ? options : options.name;
|
||||
const url = helper.isObject(options) ? options.url : undefined;
|
||||
assert(name || url, 'Either name or url matcher should be specified');
|
||||
|
@ -221,11 +233,11 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return this._attributeToPage(() => this._mainFrame.$(selector));
|
||||
}
|
||||
|
||||
async waitForSelector(selector: string, options?: types.WaitForElementOptions): Promise<ElementHandle<Element> | null> {
|
||||
async waitForSelector(selector: string, options?: FrameWaitForSelectorOptions): Promise<ElementHandle<Element> | null> {
|
||||
return this._attributeToPage(() => this._mainFrame.waitForSelector(selector, options));
|
||||
}
|
||||
|
||||
async dispatchEvent(selector: string, type: string, eventInit?: any, options?: types.TimeoutOptions): Promise<void> {
|
||||
async dispatchEvent(selector: string, type: string, eventInit?: any, options?: FrameDispatchEventOptions): Promise<void> {
|
||||
return this._attributeToPage(() => this._mainFrame.dispatchEvent(selector, type, eventInit, options));
|
||||
}
|
||||
|
||||
|
@ -277,7 +289,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async setExtraHTTPHeaders(headers: types.Headers) {
|
||||
async setExtraHTTPHeaders(headers: Headers) {
|
||||
return this._wrapApiCall('page.setExtraHTTPHeaders', async () => {
|
||||
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
|
||||
});
|
||||
|
@ -291,30 +303,30 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return this._attributeToPage(() => this._mainFrame.content());
|
||||
}
|
||||
|
||||
async setContent(html: string, options?: types.NavigateOptions): Promise<void> {
|
||||
async setContent(html: string, options?: FrameSetContentOptions): Promise<void> {
|
||||
return this._attributeToPage(() => this._mainFrame.setContent(html, options));
|
||||
}
|
||||
|
||||
async goto(url: string, options?: GotoOptions): Promise<Response | null> {
|
||||
async goto(url: string, options?: FrameGotoOptions): Promise<Response | null> {
|
||||
return this._attributeToPage(() => this._mainFrame.goto(url, options));
|
||||
}
|
||||
|
||||
async reload(options: types.NavigateOptions = {}): Promise<Response | null> {
|
||||
async reload(options: PageReloadOptions = {}): Promise<Response | null> {
|
||||
return this._wrapApiCall('page.reload', async () => {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
return Response.fromNullable((await this._channel.reload({ ...options, waitUntil })).response);
|
||||
});
|
||||
}
|
||||
|
||||
async waitForLoadState(state?: types.LifecycleEvent, options?: types.TimeoutOptions): Promise<void> {
|
||||
async waitForLoadState(state?: LifecycleEvent, options?: { timeout?: number }): Promise<void> {
|
||||
return this._attributeToPage(() => this._mainFrame.waitForLoadState(state, options));
|
||||
}
|
||||
|
||||
async waitForNavigation(options?: types.WaitForNavigationOptions): Promise<Response | null> {
|
||||
async waitForNavigation(options?: WaitForNavigationOptions): Promise<Response | null> {
|
||||
return this._attributeToPage(() => this._mainFrame.waitForNavigation(options));
|
||||
}
|
||||
|
||||
async waitForRequest(urlOrPredicate: string | RegExp | ((r: Request) => boolean), options: types.TimeoutOptions = {}): Promise<Request> {
|
||||
async waitForRequest(urlOrPredicate: string | RegExp | ((r: Request) => boolean), options: { timeout?: number } = {}): Promise<Request> {
|
||||
const predicate = (request: Request) => {
|
||||
if (helper.isString(urlOrPredicate) || helper.isRegExp(urlOrPredicate))
|
||||
return helper.urlMatches(request.url(), urlOrPredicate);
|
||||
|
@ -323,7 +335,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return this.waitForEvent(Events.Page.Request, { predicate, timeout: options.timeout });
|
||||
}
|
||||
|
||||
async waitForResponse(urlOrPredicate: string | RegExp | ((r: Response) => boolean), options: types.TimeoutOptions = {}): Promise<Response> {
|
||||
async waitForResponse(urlOrPredicate: string | RegExp | ((r: Response) => boolean), options: { timeout?: number } = {}): Promise<Response> {
|
||||
const predicate = (response: Response) => {
|
||||
if (helper.isString(urlOrPredicate) || helper.isRegExp(urlOrPredicate))
|
||||
return helper.urlMatches(response.url(), urlOrPredicate);
|
||||
|
@ -332,7 +344,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return this.waitForEvent(Events.Page.Response, { predicate, timeout: options.timeout });
|
||||
}
|
||||
|
||||
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = new Waiter();
|
||||
|
@ -346,21 +358,21 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return result;
|
||||
}
|
||||
|
||||
async goBack(options: types.NavigateOptions = {}): Promise<Response | null> {
|
||||
async goBack(options: PageGoBackOptions = {}): Promise<Response | null> {
|
||||
return this._wrapApiCall('page.goBack', async () => {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
return Response.fromNullable((await this._channel.goBack({ ...options, waitUntil })).response);
|
||||
});
|
||||
}
|
||||
|
||||
async goForward(options: types.NavigateOptions = {}): Promise<Response | null> {
|
||||
async goForward(options: PageGoForwardOptions = {}): Promise<Response | null> {
|
||||
return this._wrapApiCall('page.goForward', async () => {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
return Response.fromNullable((await this._channel.goForward({ ...options, waitUntil })).response);
|
||||
});
|
||||
}
|
||||
|
||||
async emulateMedia(options: { media?: types.MediaType | null, colorScheme?: types.ColorScheme | null }) {
|
||||
async emulateMedia(options: { media?: 'screen' | 'print' | null, colorScheme?: 'dark' | 'light' | 'no-preference' | null }) {
|
||||
return this._wrapApiCall('page.emulateMedia', async () => {
|
||||
await this._channel.emulateMedia({
|
||||
media: options.media === null ? 'null' : options.media,
|
||||
|
@ -369,14 +381,14 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async setViewportSize(viewportSize: types.Size) {
|
||||
async setViewportSize(viewportSize: Size) {
|
||||
return this._wrapApiCall('page.setViewportSize', async () => {
|
||||
this._viewportSize = viewportSize;
|
||||
await this._channel.setViewportSize({ viewportSize });
|
||||
});
|
||||
}
|
||||
|
||||
viewportSize(): types.Size | null {
|
||||
viewportSize(): Size | null {
|
||||
return this._viewportSize;
|
||||
}
|
||||
|
||||
|
@ -394,7 +406,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async route(url: types.URLMatch, handler: RouteHandler): Promise<void> {
|
||||
async route(url: URLMatch, handler: RouteHandler): Promise<void> {
|
||||
return this._wrapApiCall('page.route', async () => {
|
||||
this._routes.push({ url, handler });
|
||||
if (this._routes.length === 1)
|
||||
|
@ -402,7 +414,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async unroute(url: types.URLMatch, handler?: RouteHandler): Promise<void> {
|
||||
async unroute(url: URLMatch, handler?: RouteHandler): Promise<void> {
|
||||
return this._wrapApiCall('page.unroute', async () => {
|
||||
this._routes = this._routes.filter(route => route.url !== url || (handler && route.handler !== handler));
|
||||
if (this._routes.length === 0)
|
||||
|
@ -410,7 +422,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
async screenshot(options: types.ScreenshotOptions = {}): Promise<Buffer> {
|
||||
async screenshot(options: PageScreenshotOptions = {}): Promise<Buffer> {
|
||||
return this._wrapApiCall('page.screenshot', async () => {
|
||||
return Buffer.from((await this._channel.screenshot(options)).binary, 'base64');
|
||||
});
|
||||
|
@ -438,63 +450,63 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return this._closed;
|
||||
}
|
||||
|
||||
async click(selector: string, options?: types.MouseClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
||||
async click(selector: string, options?: FrameClickOptions) {
|
||||
return this._attributeToPage(() => this._mainFrame.click(selector, options));
|
||||
}
|
||||
|
||||
async dblclick(selector: string, options?: types.MouseMultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
||||
async dblclick(selector: string, options?: FrameDblclickOptions) {
|
||||
return this._attributeToPage(() => this._mainFrame.dblclick(selector, options));
|
||||
}
|
||||
|
||||
async fill(selector: string, value: string, options?: types.NavigatingActionWaitOptions) {
|
||||
async fill(selector: string, value: string, options?: FrameFillOptions) {
|
||||
return this._attributeToPage(() => this._mainFrame.fill(selector, value, options));
|
||||
}
|
||||
|
||||
async focus(selector: string, options?: types.TimeoutOptions) {
|
||||
async focus(selector: string, options?: FrameFocusOptions) {
|
||||
return this._attributeToPage(() => this._mainFrame.focus(selector, options));
|
||||
}
|
||||
|
||||
async textContent(selector: string, options?: types.TimeoutOptions): Promise<null|string> {
|
||||
async textContent(selector: string, options?: FrameTextContentOptions): Promise<null|string> {
|
||||
return this._attributeToPage(() => this._mainFrame.textContent(selector, options));
|
||||
}
|
||||
|
||||
async innerText(selector: string, options?: types.TimeoutOptions): Promise<string> {
|
||||
async innerText(selector: string, options?: FrameInnerTextOptions): Promise<string> {
|
||||
return this._attributeToPage(() => this._mainFrame.innerText(selector, options));
|
||||
}
|
||||
|
||||
async innerHTML(selector: string, options?: types.TimeoutOptions): Promise<string> {
|
||||
async innerHTML(selector: string, options?: FrameInnerHTMLOptions): Promise<string> {
|
||||
return this._attributeToPage(() => this._mainFrame.innerHTML(selector, options));
|
||||
}
|
||||
|
||||
async getAttribute(selector: string, name: string, options?: types.TimeoutOptions): Promise<string | null> {
|
||||
async getAttribute(selector: string, name: string, options?: FrameGetAttributeOptions): Promise<string | null> {
|
||||
return this._attributeToPage(() => this._mainFrame.getAttribute(selector, name, options));
|
||||
}
|
||||
|
||||
async hover(selector: string, options?: types.PointerActionOptions & types.PointerActionWaitOptions) {
|
||||
async hover(selector: string, options?: FrameHoverOptions) {
|
||||
return this._attributeToPage(() => this._mainFrame.hover(selector, options));
|
||||
}
|
||||
|
||||
async selectOption(selector: string, values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[] | null, options?: types.NavigatingActionWaitOptions): Promise<string[]> {
|
||||
async selectOption(selector: string, values: string | ElementHandle | SelectOption | string[] | ElementHandle[] | SelectOption[] | null, options?: SelectOptionOptions): Promise<string[]> {
|
||||
return this._attributeToPage(() => this._mainFrame.selectOption(selector, values, options));
|
||||
}
|
||||
|
||||
async setInputFiles(selector: string, files: string | types.FilePayload | string[] | types.FilePayload[], options?: types.NavigatingActionWaitOptions): Promise<void> {
|
||||
async setInputFiles(selector: string, files: string | FilePayload | string[] | FilePayload[], options?: FrameSetInputFilesOptions): Promise<void> {
|
||||
return this._attributeToPage(() => this._mainFrame.setInputFiles(selector, files, options));
|
||||
}
|
||||
|
||||
async type(selector: string, text: string, options?: { delay?: number } & types.NavigatingActionWaitOptions) {
|
||||
async type(selector: string, text: string, options?: FrameTypeOptions) {
|
||||
return this._attributeToPage(() => this._mainFrame.type(selector, text, options));
|
||||
}
|
||||
|
||||
async press(selector: string, key: string, options?: { delay?: number } & types.NavigatingActionWaitOptions) {
|
||||
async press(selector: string, key: string, options?: FramePressOptions) {
|
||||
return this._attributeToPage(() => this._mainFrame.press(selector, key, options));
|
||||
}
|
||||
|
||||
async check(selector: string, options?: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
||||
async check(selector: string, options?: FrameCheckOptions) {
|
||||
return this._attributeToPage(() => this._mainFrame.check(selector, options));
|
||||
}
|
||||
|
||||
async uncheck(selector: string, options?: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
||||
async uncheck(selector: string, options?: FrameUncheckOptions) {
|
||||
return this._attributeToPage(() => this._mainFrame.uncheck(selector, options));
|
||||
}
|
||||
|
||||
|
@ -502,9 +514,9 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
await this._mainFrame.waitForTimeout(timeout);
|
||||
}
|
||||
|
||||
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, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options?: types.WaitForFunctionOptions): Promise<SmartHandle<R>> {
|
||||
async waitForFunction<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg, options?: WaitForFunctionOptions): Promise<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));
|
||||
}
|
||||
|
||||
|
@ -528,7 +540,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return this;
|
||||
}
|
||||
|
||||
async _pdf(options: types.PDFOptions = {}): Promise<Buffer> {
|
||||
async _pdf(options: PDFOptions = {}): Promise<Buffer> {
|
||||
const path = options.path;
|
||||
const transportOptions: PagePdfParams = { ...options } as PagePdfParams;
|
||||
if (path)
|
||||
|
|
|
@ -15,18 +15,27 @@
|
|||
*/
|
||||
|
||||
import { PlaywrightChannel, PlaywrightInitializer } from '../channels';
|
||||
import * as types from '../../types';
|
||||
import { BrowserType } from './browserType';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Selectors } from './selectors';
|
||||
import { Electron } from './electron';
|
||||
import { TimeoutError } from '../../errors';
|
||||
import { Size } from './types';
|
||||
|
||||
type DeviceDescriptor = {
|
||||
userAgent: string,
|
||||
viewport: Size,
|
||||
deviceScaleFactor: number,
|
||||
isMobile: boolean,
|
||||
hasTouch: boolean
|
||||
};
|
||||
type Devices = { [name: string]: DeviceDescriptor };
|
||||
|
||||
export class Playwright extends ChannelOwner<PlaywrightChannel, PlaywrightInitializer> {
|
||||
readonly chromium: BrowserType;
|
||||
readonly firefox: BrowserType;
|
||||
readonly webkit: BrowserType;
|
||||
readonly devices: types.Devices;
|
||||
readonly devices: Devices;
|
||||
readonly selectors: Selectors;
|
||||
readonly errors: { TimeoutError: typeof TimeoutError };
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
* Modifications 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 { BrowserNewContextOptions, BrowserTypeLaunchOptions, BrowserTypeLaunchServerOptions, BrowserTypeConnectParams } from '../channels';
|
||||
|
||||
type LoggerSeverity = 'verbose' | 'info' | 'warning' | 'error';
|
||||
export interface LoggerSink {
|
||||
isEnabled(name: string, severity: LoggerSeverity): boolean;
|
||||
log(name: string, severity: LoggerSeverity, message: string | Error, args: any[], hints: { color?: string }): void;
|
||||
}
|
||||
|
||||
export type Size = { width: number, height: number };
|
||||
export type Point = { x: number, y: number };
|
||||
export type Rect = Size & Point;
|
||||
export type Headers = { [key: string]: string };
|
||||
export type Env = { [key: string]: string | number | boolean | undefined };
|
||||
export type URLMatch = string | RegExp | ((url: URL) => boolean);
|
||||
|
||||
export type WaitForEventOptions = Function | { predicate?: Function, timeout?: number };
|
||||
export type WaitForFunctionOptions = { timeout?: number, polling?: 'raf' | number };
|
||||
|
||||
export type SelectOption = { value?: string, label?: string, index?: number };
|
||||
export type SelectOptionOptions = { timeout?: number, noWaitAfter?: boolean };
|
||||
export type FilePayload = { name: string, mimeType: string, buffer: Buffer };
|
||||
|
||||
export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle';
|
||||
export const kLifecycleEvents: Set<LifecycleEvent> = new Set(['load', 'domcontentloaded', 'networkidle']);
|
||||
|
||||
export type BrowserContextOptions = Omit<BrowserNewContextOptions, 'viewport' | 'noDefaultViewport' | 'extraHTTPHeaders'> & {
|
||||
viewport?: Size | null,
|
||||
extraHTTPHeaders?: Headers,
|
||||
logger?: LoggerSink,
|
||||
};
|
||||
|
||||
type LaunchOverrides = {
|
||||
ignoreDefaultArgs?: boolean | string[],
|
||||
env?: Env,
|
||||
firefoxUserPrefs?: { [key: string]: string | number | boolean },
|
||||
logger?: LoggerSink,
|
||||
};
|
||||
export type LaunchOptions = Omit<BrowserTypeLaunchOptions, 'ignoreAllDefaultArgs' | 'ignoreDefaultArgs' | 'env' | 'firefoxUserPrefs'> & LaunchOverrides;
|
||||
export type LaunchServerOptions = Omit<BrowserTypeLaunchServerOptions, 'ignoreAllDefaultArgs' | 'ignoreDefaultArgs' | 'env' | 'firefoxUserPrefs'> & LaunchOverrides;
|
||||
export type ConnectOptions = BrowserTypeConnectParams & { logger?: LoggerSink };
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Events } from '../../events';
|
||||
import { Events } from './events';
|
||||
import { assertMaxArguments } from '../../helper';
|
||||
import { WorkerChannel, WorkerInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
*/
|
||||
|
||||
import { TimeoutError } from '../errors';
|
||||
import * as types from '../types';
|
||||
import { helper } from '../helper';
|
||||
import { SerializedError, AXNode, SerializedValue } from './channels';
|
||||
import { SerializedError, SerializedValue } from './channels';
|
||||
|
||||
export function serializeError(e: any): SerializedError {
|
||||
if (helper.isError(e))
|
||||
|
@ -41,32 +40,6 @@ export function parseError(error: SerializedError): Error {
|
|||
return e;
|
||||
}
|
||||
|
||||
export function axNodeToProtocol(axNode: types.SerializedAXNode): AXNode {
|
||||
const result: AXNode = {
|
||||
...axNode,
|
||||
valueNumber: typeof axNode.value === 'number' ? axNode.value : undefined,
|
||||
valueString: typeof axNode.value === 'string' ? axNode.value : undefined,
|
||||
checked: axNode.checked === true ? 'checked' : axNode.checked === false ? 'unchecked' : axNode.checked,
|
||||
pressed: axNode.pressed === true ? 'pressed' : axNode.pressed === false ? 'released' : axNode.pressed,
|
||||
children: axNode.children ? axNode.children.map(axNodeToProtocol) : undefined,
|
||||
};
|
||||
delete (result as any).value;
|
||||
return result;
|
||||
}
|
||||
|
||||
export function axNodeFromProtocol(axNode: AXNode): types.SerializedAXNode {
|
||||
const result: types.SerializedAXNode = {
|
||||
...axNode,
|
||||
value: axNode.valueNumber !== undefined ? axNode.valueNumber : axNode.valueString,
|
||||
checked: axNode.checked === 'checked' ? true : axNode.checked === 'unchecked' ? false : axNode.checked,
|
||||
pressed: axNode.pressed === 'pressed' ? true : axNode.pressed === 'released' ? false : axNode.pressed,
|
||||
children: axNode.children ? axNode.children.map(axNodeFromProtocol) : undefined,
|
||||
};
|
||||
delete (result as any).valueNumber;
|
||||
delete (result as any).valueString;
|
||||
return result;
|
||||
}
|
||||
|
||||
export function parseSerializedValue(value: SerializedValue, handles: any[] | undefined): any {
|
||||
if (value.n !== undefined)
|
||||
return value.n;
|
||||
|
|
|
@ -20,9 +20,9 @@ import { Frame } from '../../frames';
|
|||
import { Request } from '../../network';
|
||||
import { Page, Worker } from '../../page';
|
||||
import * as types from '../../types';
|
||||
import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel, WorkerInitializer, WorkerChannel, JSHandleChannel, Binary, SerializedArgument, PagePdfParams, SerializedError, PageAccessibilitySnapshotResult, SerializedValue, PageEmulateMediaParams } from '../channels';
|
||||
import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel, WorkerInitializer, WorkerChannel, JSHandleChannel, Binary, SerializedArgument, PagePdfParams, SerializedError, PageAccessibilitySnapshotResult, SerializedValue, PageEmulateMediaParams, AXNode } from '../channels';
|
||||
import { Dispatcher, DispatcherScope, lookupDispatcher, lookupNullableDispatcher } from './dispatcher';
|
||||
import { parseError, serializeError, axNodeToProtocol } from '../serializers';
|
||||
import { parseError, serializeError } from '../serializers';
|
||||
import { headersArrayToObject } from '../../converters';
|
||||
import { ConsoleMessageDispatcher } from './consoleMessageDispatcher';
|
||||
import { DialogDispatcher } from './dialogDispatcher';
|
||||
|
@ -278,3 +278,16 @@ export class BindingCallDispatcher extends Dispatcher<{}, BindingCallInitializer
|
|||
this._reject!(parseError(params.error));
|
||||
}
|
||||
}
|
||||
|
||||
function axNodeToProtocol(axNode: types.SerializedAXNode): AXNode {
|
||||
const result: AXNode = {
|
||||
...axNode,
|
||||
valueNumber: typeof axNode.value === 'number' ? axNode.value : undefined,
|
||||
valueString: typeof axNode.value === 'string' ? axNode.value : undefined,
|
||||
checked: axNode.checked === true ? 'checked' : axNode.checked === false ? 'unchecked' : axNode.checked,
|
||||
pressed: axNode.pressed === true ? 'pressed' : axNode.pressed === false ? 'released' : axNode.pressed,
|
||||
children: axNode.children ? axNode.children.map(axNodeToProtocol) : undefined,
|
||||
};
|
||||
delete (result as any).value;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -70,11 +70,13 @@ function inlineType(type, indent, wrapEnums = false) {
|
|||
raise(type);
|
||||
}
|
||||
|
||||
function properties(props, indent) {
|
||||
function properties(props, indent, onlyOptional) {
|
||||
const ts = [];
|
||||
const scheme = [];
|
||||
for (const [name, value] of Object.entries(props)) {
|
||||
const inner = inlineType(value, indent);
|
||||
if (onlyOptional && !inner.optional)
|
||||
continue;
|
||||
ts.push(`${indent}${name}${inner.optional ? '?' : ''}: ${inner.ts},`);
|
||||
const wrapped = inner.optional ? `tOptional(${inner.scheme})` : inner.scheme;
|
||||
scheme.push(`${indent}${name}: ${wrapped},`);
|
||||
|
@ -82,10 +84,10 @@ function properties(props, indent) {
|
|||
return { ts: ts.join('\n'), scheme: scheme.join('\n') };
|
||||
}
|
||||
|
||||
function objectType(props, indent) {
|
||||
function objectType(props, indent, onlyOptional = false) {
|
||||
if (!Object.entries(props).length)
|
||||
return { ts: `{}`, scheme: `tObject({})` };
|
||||
const inner = properties(props, indent + ' ');
|
||||
const inner = properties(props, indent + ' ', onlyOptional);
|
||||
return { ts: `{\n${inner.ts}\n${indent}}`, scheme: `tObject({\n${inner.scheme}\n${indent}})` };
|
||||
}
|
||||
|
||||
|
@ -195,7 +197,9 @@ for (const [name, item] of Object.entries(protocol)) {
|
|||
method = {};
|
||||
const parameters = objectType(method.parameters || {}, '');
|
||||
const paramsName = `${channelName}${titleCase(methodName)}Params`;
|
||||
const optionsName = `${channelName}${titleCase(methodName)}Options`;
|
||||
ts_types.set(paramsName, parameters.ts);
|
||||
ts_types.set(optionsName, objectType(method.parameters || {}, '', true).ts);
|
||||
addScheme(paramsName, method.parameters ? parameters.scheme : `tOptional(tObject({}))`);
|
||||
for (const key of inherits.keys()) {
|
||||
if (inherits.get(key) === channelName)
|
||||
|
|
Loading…
Reference in New Issue