mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-14 21:53:35 +03:00
chore: drop wrapApiCall (2) (#10445)
This commit is contained in:
parent
4eaeb3b59c
commit
a73e6bbd0e
@ -48,10 +48,8 @@ export class Android extends ChannelOwner<channels.AndroidChannel> implements ap
|
||||
}
|
||||
|
||||
async devices(): Promise<AndroidDevice[]> {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidChannel) => {
|
||||
const { devices } = await channel.devices();
|
||||
return devices.map(d => AndroidDevice.from(d));
|
||||
});
|
||||
const { devices } = await this._channel.devices();
|
||||
return devices.map(d => AndroidDevice.from(d));
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,15 +112,11 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
|
||||
}
|
||||
|
||||
async wait(selector: api.AndroidSelector, options?: { state?: 'gone' } & types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.wait({ selector: toSelectorChannel(selector), ...options });
|
||||
});
|
||||
await this._channel.wait({ selector: toSelectorChannel(selector), ...options });
|
||||
}
|
||||
|
||||
async fill(selector: api.AndroidSelector, text: string, options?: types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.fill({ selector: toSelectorChannel(selector), text, ...options });
|
||||
});
|
||||
await this._channel.fill({ selector: toSelectorChannel(selector), text, ...options });
|
||||
}
|
||||
|
||||
async press(selector: api.AndroidSelector, key: api.AndroidKey, options?: types.TimeoutOptions) {
|
||||
@ -131,114 +125,82 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
|
||||
}
|
||||
|
||||
async tap(selector: api.AndroidSelector, options?: { duration?: number } & types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.tap({ selector: toSelectorChannel(selector), ...options });
|
||||
});
|
||||
await this._channel.tap({ selector: toSelectorChannel(selector), ...options });
|
||||
}
|
||||
|
||||
async drag(selector: api.AndroidSelector, dest: types.Point, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.drag({ selector: toSelectorChannel(selector), dest, ...options });
|
||||
});
|
||||
await this._channel.drag({ selector: toSelectorChannel(selector), dest, ...options });
|
||||
}
|
||||
|
||||
async fling(selector: api.AndroidSelector, direction: Direction, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.fling({ selector: toSelectorChannel(selector), direction, ...options });
|
||||
});
|
||||
await this._channel.fling({ selector: toSelectorChannel(selector), direction, ...options });
|
||||
}
|
||||
|
||||
async longTap(selector: api.AndroidSelector, options?: types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.longTap({ selector: toSelectorChannel(selector), ...options });
|
||||
});
|
||||
await this._channel.longTap({ selector: toSelectorChannel(selector), ...options });
|
||||
}
|
||||
|
||||
async pinchClose(selector: api.AndroidSelector, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.pinchClose({ selector: toSelectorChannel(selector), percent, ...options });
|
||||
});
|
||||
await this._channel.pinchClose({ selector: toSelectorChannel(selector), percent, ...options });
|
||||
}
|
||||
|
||||
async pinchOpen(selector: api.AndroidSelector, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.pinchOpen({ selector: toSelectorChannel(selector), percent, ...options });
|
||||
});
|
||||
await this._channel.pinchOpen({ selector: toSelectorChannel(selector), percent, ...options });
|
||||
}
|
||||
|
||||
async scroll(selector: api.AndroidSelector, direction: Direction, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.scroll({ selector: toSelectorChannel(selector), direction, percent, ...options });
|
||||
});
|
||||
await this._channel.scroll({ selector: toSelectorChannel(selector), direction, percent, ...options });
|
||||
}
|
||||
|
||||
async swipe(selector: api.AndroidSelector, direction: Direction, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.swipe({ selector: toSelectorChannel(selector), direction, percent, ...options });
|
||||
});
|
||||
await this._channel.swipe({ selector: toSelectorChannel(selector), direction, percent, ...options });
|
||||
}
|
||||
|
||||
async info(selector: api.AndroidSelector): Promise<api.AndroidElementInfo> {
|
||||
return await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
return (await channel.info({ selector: toSelectorChannel(selector) })).info;
|
||||
});
|
||||
return (await this._channel.info({ selector: toSelectorChannel(selector) })).info;
|
||||
}
|
||||
|
||||
async screenshot(options: { path?: string } = {}): Promise<Buffer> {
|
||||
return await this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
const { binary } = await channel.screenshot();
|
||||
const buffer = Buffer.from(binary, 'base64');
|
||||
if (options.path)
|
||||
await fs.promises.writeFile(options.path, buffer);
|
||||
return buffer;
|
||||
});
|
||||
const { binary } = await this._channel.screenshot();
|
||||
const buffer = Buffer.from(binary, 'base64');
|
||||
if (options.path)
|
||||
await fs.promises.writeFile(options.path, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
async close() {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.close();
|
||||
this.emit(Events.AndroidDevice.Close);
|
||||
});
|
||||
await this._channel.close();
|
||||
this.emit(Events.AndroidDevice.Close);
|
||||
}
|
||||
|
||||
async shell(command: string): Promise<Buffer> {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
const { result } = await channel.shell({ command });
|
||||
return Buffer.from(result, 'base64');
|
||||
});
|
||||
const { result } = await this._channel.shell({ command });
|
||||
return Buffer.from(result, 'base64');
|
||||
}
|
||||
|
||||
async open(command: string): Promise<AndroidSocket> {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
return AndroidSocket.from((await channel.open({ command })).socket);
|
||||
});
|
||||
return AndroidSocket.from((await this._channel.open({ command })).socket);
|
||||
}
|
||||
|
||||
async installApk(file: string | Buffer, options?: { args: string[] }): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.installApk({ file: await loadFile(file), args: options && options.args });
|
||||
});
|
||||
await this._channel.installApk({ file: await loadFile(file), args: options && options.args });
|
||||
}
|
||||
|
||||
async push(file: string | Buffer, path: string, options?: { mode: number }): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.push({ file: await loadFile(file), path, mode: options ? options.mode : undefined });
|
||||
});
|
||||
await this._channel.push({ file: await loadFile(file), path, mode: options ? options.mode : undefined });
|
||||
}
|
||||
|
||||
async launchBrowser(options: types.BrowserContextOptions & { pkg?: string } = {}): Promise<BrowserContext> {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
const contextOptions = await prepareBrowserContextParams(options);
|
||||
const { context } = await channel.launchBrowser(contextOptions);
|
||||
return BrowserContext.from(context) as BrowserContext;
|
||||
});
|
||||
const contextOptions = await prepareBrowserContextParams(options);
|
||||
const { context } = await this._channel.launchBrowser(contextOptions);
|
||||
return BrowserContext.from(context) as BrowserContext;
|
||||
}
|
||||
|
||||
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
return this._wrapApiCall(async () => {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = Waiter.createForEvent(channel, event);
|
||||
const waiter = Waiter.createForEvent(this._channel, event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
if (event !== Events.AndroidDevice.Close)
|
||||
waiter.rejectOnEvent(this, Events.AndroidDevice.Close, new Error('Device closed'));
|
||||
@ -261,15 +223,11 @@ export class AndroidSocket extends ChannelOwner<channels.AndroidSocketChannel> i
|
||||
}
|
||||
|
||||
async write(data: Buffer): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidSocketChannel) => {
|
||||
await channel.write({ data: data.toString('base64') });
|
||||
});
|
||||
await this._channel.write({ data: data.toString('base64') });
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.AndroidSocketChannel) => {
|
||||
await channel.close();
|
||||
});
|
||||
await this._channel.close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,33 +245,23 @@ export class AndroidInput implements api.AndroidInput {
|
||||
}
|
||||
|
||||
async type(text: string) {
|
||||
return this._device._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.inputType({ text });
|
||||
});
|
||||
await this._device._channel.inputType({ text });
|
||||
}
|
||||
|
||||
async press(key: api.AndroidKey) {
|
||||
return this._device._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.inputPress({ key });
|
||||
});
|
||||
await this._device._channel.inputPress({ key });
|
||||
}
|
||||
|
||||
async tap(point: types.Point) {
|
||||
return this._device._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.inputTap({ point });
|
||||
});
|
||||
await this._device._channel.inputTap({ point });
|
||||
}
|
||||
|
||||
async swipe(from: types.Point, segments: types.Point[], steps: number) {
|
||||
return this._device._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.inputSwipe({ segments, steps });
|
||||
});
|
||||
await this._device._channel.inputSwipe({ segments, steps });
|
||||
}
|
||||
|
||||
async drag(from: types.Point, to: types.Point, steps: number) {
|
||||
return this._device._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
await channel.inputDrag({ from, to, steps });
|
||||
});
|
||||
await this._device._channel.inputDrag({ from, to, steps });
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,9 +341,7 @@ export class AndroidWebView extends EventEmitter implements api.AndroidWebView {
|
||||
}
|
||||
|
||||
private async _fetchPage(): Promise<Page> {
|
||||
return this._device._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => {
|
||||
const { context } = await channel.connectToWebView({ pid: this._data.pid });
|
||||
return BrowserContext.from(context).pages()[0];
|
||||
});
|
||||
const { context } = await this._device._channel.connectToWebView({ pid: this._data.pid });
|
||||
return BrowserContext.from(context).pages()[0];
|
||||
}
|
||||
}
|
||||
|
@ -29,54 +29,42 @@ export class Artifact extends ChannelOwner<channels.ArtifactChannel> {
|
||||
async pathAfterFinished(): Promise<string | null> {
|
||||
if (this._connection.isRemote())
|
||||
throw new Error(`Path is not available when connecting remotely. Use saveAs() to save a local copy.`);
|
||||
return this._wrapApiCall(async (channel: channels.ArtifactChannel) => {
|
||||
return (await channel.pathAfterFinished()).value || null;
|
||||
});
|
||||
return (await this._channel.pathAfterFinished()).value || null;
|
||||
}
|
||||
|
||||
async saveAs(path: string): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ArtifactChannel) => {
|
||||
if (!this._connection.isRemote()) {
|
||||
await channel.saveAs({ path });
|
||||
return;
|
||||
}
|
||||
if (!this._connection.isRemote()) {
|
||||
await this._channel.saveAs({ path });
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await channel.saveAsStream();
|
||||
const stream = Stream.from(result.stream);
|
||||
await mkdirIfNeeded(path);
|
||||
await new Promise((resolve, reject) => {
|
||||
stream.stream().pipe(fs.createWriteStream(path))
|
||||
.on('finish' as any, resolve)
|
||||
.on('error' as any, reject);
|
||||
});
|
||||
const result = await this._channel.saveAsStream();
|
||||
const stream = Stream.from(result.stream);
|
||||
await mkdirIfNeeded(path);
|
||||
await new Promise((resolve, reject) => {
|
||||
stream.stream().pipe(fs.createWriteStream(path))
|
||||
.on('finish' as any, resolve)
|
||||
.on('error' as any, reject);
|
||||
});
|
||||
}
|
||||
|
||||
async failure(): Promise<string | null> {
|
||||
return this._wrapApiCall(async (channel: channels.ArtifactChannel) => {
|
||||
return (await channel.failure()).error || null;
|
||||
});
|
||||
return (await this._channel.failure()).error || null;
|
||||
}
|
||||
|
||||
async createReadStream(): Promise<Readable | null> {
|
||||
return this._wrapApiCall(async (channel: channels.ArtifactChannel) => {
|
||||
const result = await channel.stream();
|
||||
if (!result.stream)
|
||||
return null;
|
||||
const stream = Stream.from(result.stream);
|
||||
return stream.stream();
|
||||
});
|
||||
const result = await this._channel.stream();
|
||||
if (!result.stream)
|
||||
return null;
|
||||
const stream = Stream.from(result.stream);
|
||||
return stream.stream();
|
||||
}
|
||||
|
||||
async cancel(): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ArtifactChannel) => {
|
||||
return channel.cancel();
|
||||
});
|
||||
return this._channel.cancel();
|
||||
}
|
||||
|
||||
async delete(): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ArtifactChannel) => {
|
||||
return channel.delete();
|
||||
});
|
||||
return this._channel.delete();
|
||||
}
|
||||
}
|
||||
|
@ -55,17 +55,15 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
|
||||
}
|
||||
|
||||
async newContext(options: BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserChannel) => {
|
||||
options = { ...this._browserType._defaultContextOptions, ...options };
|
||||
const contextOptions = await prepareBrowserContextParams(options);
|
||||
const context = BrowserContext.from((await channel.newContext(contextOptions)).context);
|
||||
context._options = contextOptions;
|
||||
this._contexts.add(context);
|
||||
context._logger = options.logger || this._logger;
|
||||
context._setBrowserType(this._browserType);
|
||||
await this._browserType._onDidCreateContext?.(context);
|
||||
return context;
|
||||
});
|
||||
options = { ...this._browserType._defaultContextOptions, ...options };
|
||||
const contextOptions = await prepareBrowserContextParams(options);
|
||||
const context = BrowserContext.from((await this._channel.newContext(contextOptions)).context);
|
||||
context._options = contextOptions;
|
||||
this._contexts.add(context);
|
||||
context._logger = options.logger || this._logger;
|
||||
context._setBrowserType(this._browserType);
|
||||
await this._browserType._onDidCreateContext?.(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
contexts(): BrowserContext[] {
|
||||
@ -89,32 +87,24 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
|
||||
}
|
||||
|
||||
async newBrowserCDPSession(): Promise<api.CDPSession> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserChannel) => {
|
||||
return CDPSession.from((await channel.newBrowserCDPSession()).session);
|
||||
});
|
||||
return CDPSession.from((await this._channel.newBrowserCDPSession()).session);
|
||||
}
|
||||
|
||||
async startTracing(page?: Page, options: { path?: string; screenshots?: boolean; categories?: string[]; } = {}) {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserChannel) => {
|
||||
await channel.startTracing({ ...options, page: page ? page._channel : undefined });
|
||||
});
|
||||
await this._channel.startTracing({ ...options, page: page ? page._channel : undefined });
|
||||
}
|
||||
|
||||
async stopTracing(): Promise<Buffer> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserChannel) => {
|
||||
return Buffer.from((await channel.stopTracing()).binary, 'base64');
|
||||
});
|
||||
return Buffer.from((await this._channel.stopTracing()).binary, 'base64');
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
try {
|
||||
await this._wrapApiCall(async (channel: channels.BrowserChannel) => {
|
||||
if (this._shouldCloseConnectionOnClose)
|
||||
this._connection.close(kBrowserClosedError);
|
||||
else
|
||||
await channel.close();
|
||||
await this._closedPromise;
|
||||
});
|
||||
if (this._shouldCloseConnectionOnClose)
|
||||
this._connection.close(kBrowserClosedError);
|
||||
else
|
||||
await this._channel.close();
|
||||
await this._closedPromise;
|
||||
} catch (e) {
|
||||
if (isSafeCloseError(e))
|
||||
return;
|
||||
|
@ -147,7 +147,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
if (routeHandler.handle(route, request)) {
|
||||
this._routes.splice(this._routes.indexOf(routeHandler), 1);
|
||||
if (!this._routes.length)
|
||||
this._wrapApiCall(channel => this._disableInterception(channel), true).catch(() => {});
|
||||
this._wrapApiCall(() => this._disableInterception(), true).catch(() => {});
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -182,11 +182,9 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
}
|
||||
|
||||
async newPage(): Promise<Page> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
if (this._ownerPage)
|
||||
throw new Error('Please use browser.newContext()');
|
||||
return Page.from((await channel.newPage()).page);
|
||||
});
|
||||
if (this._ownerPage)
|
||||
throw new Error('Please use browser.newContext()');
|
||||
return Page.from((await this._channel.newPage()).page);
|
||||
}
|
||||
|
||||
async cookies(urls?: string | string[]): Promise<network.NetworkCookie[]> {
|
||||
@ -194,109 +192,81 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
urls = [];
|
||||
if (urls && typeof urls === 'string')
|
||||
urls = [ urls ];
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
return (await channel.cookies({ urls: urls as string[] })).cookies;
|
||||
});
|
||||
return (await this._channel.cookies({ urls: urls as string[] })).cookies;
|
||||
}
|
||||
|
||||
async addCookies(cookies: network.SetNetworkCookieParam[]): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.addCookies({ cookies });
|
||||
});
|
||||
await this._channel.addCookies({ cookies });
|
||||
}
|
||||
|
||||
async clearCookies(): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.clearCookies();
|
||||
});
|
||||
await this._channel.clearCookies();
|
||||
}
|
||||
|
||||
async grantPermissions(permissions: string[], options?: { origin?: string }): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.grantPermissions({ permissions, ...options });
|
||||
});
|
||||
await this._channel.grantPermissions({ permissions, ...options });
|
||||
}
|
||||
|
||||
async clearPermissions(): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.clearPermissions();
|
||||
});
|
||||
await this._channel.clearPermissions();
|
||||
}
|
||||
|
||||
async setGeolocation(geolocation: { longitude: number, latitude: number, accuracy?: number } | null): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.setGeolocation({ geolocation: geolocation || undefined });
|
||||
});
|
||||
await this._channel.setGeolocation({ geolocation: geolocation || undefined });
|
||||
}
|
||||
|
||||
async setExtraHTTPHeaders(headers: Headers): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
network.validateHeaders(headers);
|
||||
await channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
|
||||
});
|
||||
network.validateHeaders(headers);
|
||||
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
|
||||
}
|
||||
|
||||
async setOffline(offline: boolean): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.setOffline({ offline });
|
||||
});
|
||||
await this._channel.setOffline({ offline });
|
||||
}
|
||||
|
||||
async setHTTPCredentials(httpCredentials: { username: string, password: string } | null): Promise<void> {
|
||||
if (!isUnderTest())
|
||||
deprecate(`context.setHTTPCredentials`, `warning: method |context.setHTTPCredentials()| is deprecated. Instead of changing credentials, create another browser context with new credentials.`);
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.setHTTPCredentials({ httpCredentials: httpCredentials || undefined });
|
||||
});
|
||||
await this._channel.setHTTPCredentials({ httpCredentials: httpCredentials || undefined });
|
||||
}
|
||||
|
||||
async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
const source = await evaluationScript(script, arg);
|
||||
await channel.addInitScript({ source });
|
||||
});
|
||||
const source = await evaluationScript(script, arg);
|
||||
await this._channel.addInitScript({ source });
|
||||
}
|
||||
|
||||
async exposeBinding(name: string, callback: (source: structs.BindingSource, ...args: any[]) => any, options: { handle?: boolean } = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.exposeBinding({ name, needsHandle: options.handle });
|
||||
this._bindings.set(name, callback);
|
||||
});
|
||||
await this._channel.exposeBinding({ name, needsHandle: options.handle });
|
||||
this._bindings.set(name, callback);
|
||||
}
|
||||
|
||||
async exposeFunction(name: string, callback: Function): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.exposeBinding({ name });
|
||||
const binding = (source: structs.BindingSource, ...args: any[]) => callback(...args);
|
||||
this._bindings.set(name, binding);
|
||||
});
|
||||
await this._channel.exposeBinding({ name });
|
||||
const binding = (source: structs.BindingSource, ...args: any[]) => callback(...args);
|
||||
this._bindings.set(name, binding);
|
||||
}
|
||||
|
||||
async route(url: URLMatch, handler: network.RouteHandlerCallback, options: { times?: number } = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
this._routes.unshift(new network.RouteHandler(this._options.baseURL, url, handler, options.times));
|
||||
if (this._routes.length === 1)
|
||||
await channel.setNetworkInterceptionEnabled({ enabled: true });
|
||||
});
|
||||
this._routes.unshift(new network.RouteHandler(this._options.baseURL, url, handler, options.times));
|
||||
if (this._routes.length === 1)
|
||||
await this._channel.setNetworkInterceptionEnabled({ enabled: true });
|
||||
}
|
||||
|
||||
async unroute(url: URLMatch, handler?: network.RouteHandlerCallback): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
this._routes = this._routes.filter(route => route.url !== url || (handler && route.handler !== handler));
|
||||
if (!this._routes.length)
|
||||
await this._disableInterception(channel);
|
||||
});
|
||||
this._routes = this._routes.filter(route => route.url !== url || (handler && route.handler !== handler));
|
||||
if (!this._routes.length)
|
||||
await this._disableInterception();
|
||||
}
|
||||
|
||||
private async _disableInterception(channel: channels.BrowserContextChannel) {
|
||||
await channel.setNetworkInterceptionEnabled({ enabled: false });
|
||||
private async _disableInterception() {
|
||||
await this._channel.setNetworkInterceptionEnabled({ enabled: false });
|
||||
}
|
||||
|
||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
return this._wrapApiCall(async () => {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = Waiter.createForEvent(channel, event);
|
||||
const waiter = Waiter.createForEvent(this._channel, event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
if (event !== Events.BrowserContext.Close)
|
||||
waiter.rejectOnEvent(this, Events.BrowserContext.Close, new Error('Context closed'));
|
||||
@ -307,14 +277,12 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
}
|
||||
|
||||
async storageState(options: { path?: string } = {}): Promise<StorageState> {
|
||||
return await this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
const state = await channel.storageState();
|
||||
if (options.path) {
|
||||
await mkdirIfNeeded(options.path);
|
||||
await fs.promises.writeFile(options.path, JSON.stringify(state, undefined, 2), 'utf8');
|
||||
}
|
||||
return state;
|
||||
});
|
||||
const state = await this._channel.storageState();
|
||||
if (options.path) {
|
||||
await mkdirIfNeeded(options.path);
|
||||
await fs.promises.writeFile(options.path, JSON.stringify(state, undefined, 2), 'utf8');
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
backgroundPages(): Page[] {
|
||||
@ -329,10 +297,8 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
// channelOwner.ts's validation messages don't handle the pseudo-union type, so we're explicit here
|
||||
if (!(page instanceof Page) && !(page instanceof Frame))
|
||||
throw new Error('page: expected Page or Frame');
|
||||
return this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
const result = await channel.newCDPSession(page instanceof Page ? { page: page._channel } : { frame: page._channel });
|
||||
return CDPSession.from(result.session);
|
||||
});
|
||||
const result = await this._channel.newCDPSession(page instanceof Page ? { page: page._channel } : { frame: page._channel });
|
||||
return CDPSession.from(result.session);
|
||||
}
|
||||
|
||||
_onClose() {
|
||||
@ -344,7 +310,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
|
||||
async close(): Promise<void> {
|
||||
try {
|
||||
await this._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await this._wrapApiCall(async () => {
|
||||
await this._browserType?._onWillCloseContext?.(this);
|
||||
if (this._options.recordHar) {
|
||||
const har = await this._channel.harExport();
|
||||
@ -352,7 +318,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
await artifact.saveAs(this._options.recordHar.path);
|
||||
await artifact.delete();
|
||||
}
|
||||
await channel.close();
|
||||
await this._channel.close();
|
||||
await this._closedPromise;
|
||||
});
|
||||
} catch (e) {
|
||||
|
@ -68,21 +68,19 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
||||
|
||||
async launch(options: LaunchOptions = {}): Promise<Browser> {
|
||||
const logger = options.logger || this._defaultLaunchOptions.logger;
|
||||
return this._wrapApiCall(async (channel: channels.BrowserTypeChannel) => {
|
||||
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
|
||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||
options = { ...this._defaultLaunchOptions, ...options };
|
||||
const launchOptions: channels.BrowserTypeLaunchParams = {
|
||||
...options,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
env: options.env ? envObjectToArray(options.env) : undefined,
|
||||
};
|
||||
const browser = Browser.from((await channel.launch(launchOptions)).browser);
|
||||
browser._logger = logger;
|
||||
browser._setBrowserType(this);
|
||||
return browser;
|
||||
});
|
||||
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
|
||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||
options = { ...this._defaultLaunchOptions, ...options };
|
||||
const launchOptions: channels.BrowserTypeLaunchParams = {
|
||||
...options,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
env: options.env ? envObjectToArray(options.env) : undefined,
|
||||
};
|
||||
const browser = Browser.from((await this._channel.launch(launchOptions)).browser);
|
||||
browser._logger = logger;
|
||||
browser._setBrowserType(this);
|
||||
return browser;
|
||||
}
|
||||
|
||||
async launchServer(options: LaunchServerOptions = {}): Promise<api.BrowserServer> {
|
||||
@ -94,26 +92,24 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
||||
|
||||
async launchPersistentContext(userDataDir: string, options: LaunchPersistentContextOptions = {}): Promise<BrowserContext> {
|
||||
const logger = options.logger || this._defaultLaunchOptions.logger;
|
||||
return this._wrapApiCall(async (channel: channels.BrowserTypeChannel) => {
|
||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||
options = { ...this._defaultLaunchOptions, ...this._defaultContextOptions, ...options };
|
||||
const contextParams = await prepareBrowserContextParams(options);
|
||||
const persistentParams: channels.BrowserTypeLaunchPersistentContextParams = {
|
||||
...contextParams,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
env: options.env ? envObjectToArray(options.env) : undefined,
|
||||
channel: options.channel,
|
||||
userDataDir,
|
||||
};
|
||||
const result = await channel.launchPersistentContext(persistentParams);
|
||||
const context = BrowserContext.from(result.context);
|
||||
context._options = contextParams;
|
||||
context._logger = logger;
|
||||
context._setBrowserType(this);
|
||||
await this._onDidCreateContext?.(context);
|
||||
return context;
|
||||
});
|
||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||
options = { ...this._defaultLaunchOptions, ...this._defaultContextOptions, ...options };
|
||||
const contextParams = await prepareBrowserContextParams(options);
|
||||
const persistentParams: channels.BrowserTypeLaunchPersistentContextParams = {
|
||||
...contextParams,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
env: options.env ? envObjectToArray(options.env) : undefined,
|
||||
channel: options.channel,
|
||||
userDataDir,
|
||||
};
|
||||
const result = await this._channel.launchPersistentContext(persistentParams);
|
||||
const context = BrowserContext.from(result.context);
|
||||
context._options = contextParams;
|
||||
context._logger = logger;
|
||||
context._setBrowserType(this);
|
||||
await this._onDidCreateContext?.(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
connect(options: api.ConnectOptions & { wsEndpoint?: string }): Promise<api.Browser>;
|
||||
@ -127,10 +123,10 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
||||
|
||||
async _connect(wsEndpoint: string, params: Partial<ConnectOptions> = {}): Promise<Browser> {
|
||||
const logger = params.logger;
|
||||
return await this._wrapApiCall(async (channel: channels.BrowserTypeChannel) => {
|
||||
return await this._wrapApiCall(async () => {
|
||||
const deadline = params.timeout ? monotonicTime() + params.timeout : 0;
|
||||
let browser: Browser;
|
||||
const { pipe } = await channel.connect({ wsEndpoint, headers: params.headers, slowMo: params.slowMo, timeout: params.timeout });
|
||||
const { pipe } = await this._channel.connect({ wsEndpoint, headers: params.headers, slowMo: params.slowMo, timeout: params.timeout });
|
||||
const closePipe = () => pipe.close().catch(() => {});
|
||||
const connection = new Connection();
|
||||
connection.markAsRemote();
|
||||
@ -207,21 +203,19 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
||||
if (this.name() !== 'chromium')
|
||||
throw new Error('Connecting over CDP is only supported in Chromium.');
|
||||
const logger = params.logger;
|
||||
return this._wrapApiCall(async (channel: channels.BrowserTypeChannel) => {
|
||||
const paramsHeaders = Object.assign({ 'User-Agent': getUserAgent() }, params.headers);
|
||||
const headers = paramsHeaders ? headersObjectToArray(paramsHeaders) : undefined;
|
||||
const result = await channel.connectOverCDP({
|
||||
endpointURL,
|
||||
headers,
|
||||
slowMo: params.slowMo,
|
||||
timeout: params.timeout
|
||||
});
|
||||
const browser = Browser.from(result.browser);
|
||||
if (result.defaultContext)
|
||||
browser._contexts.add(BrowserContext.from(result.defaultContext));
|
||||
browser._logger = logger;
|
||||
browser._setBrowserType(this);
|
||||
return browser;
|
||||
const paramsHeaders = Object.assign({ 'User-Agent': getUserAgent() }, params.headers);
|
||||
const headers = paramsHeaders ? headersObjectToArray(paramsHeaders) : undefined;
|
||||
const result = await this._channel.connectOverCDP({
|
||||
endpointURL,
|
||||
headers,
|
||||
slowMo: params.slowMo,
|
||||
timeout: params.timeout
|
||||
});
|
||||
const browser = Browser.from(result.browser);
|
||||
if (result.defaultContext)
|
||||
browser._contexts.add(BrowserContext.from(result.defaultContext));
|
||||
browser._logger = logger;
|
||||
browser._setBrowserType(this);
|
||||
return browser;
|
||||
}
|
||||
}
|
||||
|
@ -42,15 +42,11 @@ export class CDPSession extends ChannelOwner<channels.CDPSessionChannel> impleme
|
||||
method: T,
|
||||
params?: Protocol.CommandParameters[T]
|
||||
): Promise<Protocol.CommandReturnValues[T]> {
|
||||
return this._wrapApiCall(async (channel: channels.CDPSessionChannel) => {
|
||||
const result = await channel.send({ method, params });
|
||||
return result.result as Protocol.CommandReturnValues[T];
|
||||
});
|
||||
const result = await this._channel.send({ method, params });
|
||||
return result.result as Protocol.CommandReturnValues[T];
|
||||
}
|
||||
|
||||
async detach() {
|
||||
return this._wrapApiCall(async (channel: channels.CDPSessionChannel) => {
|
||||
return channel.detach();
|
||||
});
|
||||
return this._channel.detach();
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
|
||||
const validator = scheme[paramsName(this._type, prop)];
|
||||
if (validator) {
|
||||
return (params: any) => {
|
||||
return this._wrapApiCall((channel, apiZone) => {
|
||||
return this._wrapApiCall(apiZone => {
|
||||
const { stackTrace, csi, callCookie } = apiZone.reported ? { csi: undefined, callCookie: undefined, stackTrace: null } : apiZone;
|
||||
apiZone.reported = true;
|
||||
if (csi && stackTrace && stackTrace.apiName)
|
||||
@ -101,12 +101,12 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
|
||||
return channel;
|
||||
}
|
||||
|
||||
async _wrapApiCall<R, C extends channels.Channel = T>(func: (channel: C, apiZone: ApiZone) => Promise<R>, isInternal = false): Promise<R> {
|
||||
async _wrapApiCall<R>(func: (apiZone: ApiZone) => Promise<R>, isInternal = false): Promise<R> {
|
||||
const logger = this._logger;
|
||||
const stack = captureRawStack();
|
||||
const apiZone = zones.zoneData<ApiZone>('apiZone', stack);
|
||||
if (apiZone)
|
||||
return func(this._channel as any, apiZone);
|
||||
return func(apiZone);
|
||||
|
||||
const stackTrace = captureStackTrace(stack);
|
||||
if (isInternal)
|
||||
@ -120,7 +120,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
|
||||
logApiCall(logger, `=> ${apiName} started`, isInternal);
|
||||
const apiZone = { stackTrace, isInternal, reported: false, csi, callCookie };
|
||||
const result = await zones.run<ApiZone, R>('apiZone', apiZone, async () => {
|
||||
return await func(this._channel as any, apiZone);
|
||||
return await func(apiZone);
|
||||
});
|
||||
csi?.onApiCallEnd(callCookie);
|
||||
logApiCall(logger, `<= ${apiName} succeeded`, isInternal);
|
||||
|
@ -40,14 +40,10 @@ export class Dialog extends ChannelOwner<channels.DialogChannel> implements api.
|
||||
}
|
||||
|
||||
async accept(promptText: string | undefined) {
|
||||
return this._wrapApiCall(async (channel: channels.DialogChannel) => {
|
||||
await channel.accept({ promptText });
|
||||
});
|
||||
await this._channel.accept({ promptText });
|
||||
}
|
||||
|
||||
async dismiss() {
|
||||
return this._wrapApiCall(async (channel: channels.DialogChannel) => {
|
||||
await channel.dismiss();
|
||||
});
|
||||
await this._channel.dismiss();
|
||||
}
|
||||
}
|
||||
|
@ -46,14 +46,12 @@ export class Electron extends ChannelOwner<channels.ElectronChannel> implements
|
||||
}
|
||||
|
||||
async launch(options: ElectronOptions = {}): Promise<ElectronApplication> {
|
||||
return this._wrapApiCall(async (channel: channels.ElectronChannel) => {
|
||||
const params: channels.ElectronLaunchParams = {
|
||||
...options,
|
||||
extraHTTPHeaders: options.extraHTTPHeaders && headersObjectToArray(options.extraHTTPHeaders),
|
||||
env: envObjectToArray(options.env ? options.env : process.env),
|
||||
};
|
||||
return ElectronApplication.from((await channel.launch(params)).electronApplication);
|
||||
});
|
||||
const params: channels.ElectronLaunchParams = {
|
||||
...options,
|
||||
extraHTTPHeaders: options.extraHTTPHeaders && headersObjectToArray(options.extraHTTPHeaders),
|
||||
env: envObjectToArray(options.env ? options.env : process.env),
|
||||
};
|
||||
return ElectronApplication.from((await this._channel.launch(params)).electronApplication);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,11 +85,9 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
|
||||
}
|
||||
|
||||
async firstWindow(): Promise<Page> {
|
||||
return this._wrapApiCall(async (channel: channels.ElectronApplicationChannel) => {
|
||||
if (this._windows.size)
|
||||
return this._windows.values().next().value;
|
||||
return this.waitForEvent('window');
|
||||
});
|
||||
if (this._windows.size)
|
||||
return this._windows.values().next().value;
|
||||
return this.waitForEvent('window');
|
||||
}
|
||||
|
||||
context(): BrowserContext {
|
||||
@ -99,16 +95,14 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
|
||||
}
|
||||
|
||||
async close() {
|
||||
return this._wrapApiCall(async (channel: channels.ElectronApplicationChannel) => {
|
||||
await channel.close();
|
||||
});
|
||||
await this._channel.close();
|
||||
}
|
||||
|
||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||
return this._wrapApiCall(async (channel: channels.ElectronApplicationChannel) => {
|
||||
return this._wrapApiCall(async () => {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = Waiter.createForEvent(channel, event);
|
||||
const waiter = Waiter.createForEvent(this._channel, event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
if (event !== Events.ElectronApplication.Close)
|
||||
waiter.rejectOnEvent(this, Events.ElectronApplication.Close, new Error('Electron application closed'));
|
||||
@ -119,23 +113,17 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
|
||||
}
|
||||
|
||||
async browserWindow(page: Page): Promise<JSHandle<BrowserWindow>> {
|
||||
return this._wrapApiCall(async (channel: channels.ElectronApplicationChannel) => {
|
||||
const result = await channel.browserWindow({ page: page._channel });
|
||||
return JSHandle.from(result.handle);
|
||||
});
|
||||
const result = await this._channel.browserWindow({ page: page._channel });
|
||||
return JSHandle.from(result.handle);
|
||||
}
|
||||
|
||||
async evaluate<R, Arg>(pageFunction: structs.PageFunctionOn<ElectronAppType, Arg, R>, arg: Arg): Promise<R> {
|
||||
return this._wrapApiCall(async (channel: channels.ElectronApplicationChannel) => {
|
||||
const result = await channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
});
|
||||
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
}
|
||||
|
||||
async evaluateHandle<R, Arg>(pageFunction: structs.PageFunctionOn<ElectronAppType, Arg, R>, arg: Arg): Promise<structs.SmartHandle<R>> {
|
||||
return this._wrapApiCall(async (channel: channels.ElectronApplicationChannel) => {
|
||||
const result = await channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
|
||||
});
|
||||
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
|
||||
}
|
||||
}
|
||||
|
@ -47,174 +47,118 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
|
||||
}
|
||||
|
||||
async ownerFrame(): Promise<Frame | null> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return Frame.fromNullable((await channel.ownerFrame()).frame);
|
||||
});
|
||||
return Frame.fromNullable((await this._elementChannel.ownerFrame()).frame);
|
||||
}
|
||||
|
||||
async contentFrame(): Promise<Frame | null> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return Frame.fromNullable((await channel.contentFrame()).frame);
|
||||
});
|
||||
return Frame.fromNullable((await this._elementChannel.contentFrame()).frame);
|
||||
}
|
||||
|
||||
async getAttribute(name: string): Promise<string | null> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
const value = (await channel.getAttribute({ name })).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
const value = (await this._elementChannel.getAttribute({ name })).value;
|
||||
return value === undefined ? null : value;
|
||||
}
|
||||
|
||||
async inputValue(): Promise<string> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return (await channel.inputValue()).value;
|
||||
});
|
||||
return (await this._elementChannel.inputValue()).value;
|
||||
}
|
||||
|
||||
async textContent(): Promise<string | null> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
const value = (await channel.textContent()).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
const value = (await this._elementChannel.textContent()).value;
|
||||
return value === undefined ? null : value;
|
||||
}
|
||||
|
||||
async innerText(): Promise<string> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return (await channel.innerText()).value;
|
||||
});
|
||||
return (await this._elementChannel.innerText()).value;
|
||||
}
|
||||
|
||||
async innerHTML(): Promise<string> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return (await channel.innerHTML()).value;
|
||||
});
|
||||
return (await this._elementChannel.innerHTML()).value;
|
||||
}
|
||||
|
||||
async isChecked(): Promise<boolean> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return (await channel.isChecked()).value;
|
||||
});
|
||||
return (await this._elementChannel.isChecked()).value;
|
||||
}
|
||||
|
||||
async isDisabled(): Promise<boolean> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return (await channel.isDisabled()).value;
|
||||
});
|
||||
return (await this._elementChannel.isDisabled()).value;
|
||||
}
|
||||
|
||||
async isEditable(): Promise<boolean> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return (await channel.isEditable()).value;
|
||||
});
|
||||
return (await this._elementChannel.isEditable()).value;
|
||||
}
|
||||
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return (await channel.isEnabled()).value;
|
||||
});
|
||||
return (await this._elementChannel.isEnabled()).value;
|
||||
}
|
||||
|
||||
async isHidden(): Promise<boolean> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return (await channel.isHidden()).value;
|
||||
});
|
||||
return (await this._elementChannel.isHidden()).value;
|
||||
}
|
||||
|
||||
async isVisible(): Promise<boolean> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return (await channel.isVisible()).value;
|
||||
});
|
||||
return (await this._elementChannel.isVisible()).value;
|
||||
}
|
||||
|
||||
async dispatchEvent(type: string, eventInit: Object = {}) {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
await channel.dispatchEvent({ type, eventInit: serializeArgument(eventInit) });
|
||||
});
|
||||
await this._elementChannel.dispatchEvent({ type, eventInit: serializeArgument(eventInit) });
|
||||
}
|
||||
|
||||
async scrollIntoViewIfNeeded(options: channels.ElementHandleScrollIntoViewIfNeededOptions = {}) {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
await channel.scrollIntoViewIfNeeded(options);
|
||||
});
|
||||
await this._elementChannel.scrollIntoViewIfNeeded(options);
|
||||
}
|
||||
|
||||
async hover(options: channels.ElementHandleHoverOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
await channel.hover(options);
|
||||
});
|
||||
await this._elementChannel.hover(options);
|
||||
}
|
||||
|
||||
async click(options: channels.ElementHandleClickOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return await channel.click(options);
|
||||
});
|
||||
return await this._elementChannel.click(options);
|
||||
}
|
||||
|
||||
async dblclick(options: channels.ElementHandleDblclickOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return await channel.dblclick(options);
|
||||
});
|
||||
return await this._elementChannel.dblclick(options);
|
||||
}
|
||||
|
||||
async tap(options: channels.ElementHandleTapOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return await channel.tap(options);
|
||||
});
|
||||
return await this._elementChannel.tap(options);
|
||||
}
|
||||
|
||||
async selectOption(values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
const result = await channel.selectOption({ ...convertSelectOptionValues(values), ...options });
|
||||
return result.values;
|
||||
});
|
||||
const result = await this._elementChannel.selectOption({ ...convertSelectOptionValues(values), ...options });
|
||||
return result.values;
|
||||
}
|
||||
|
||||
async fill(value: string, options: channels.ElementHandleFillOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return await channel.fill({ value, ...options });
|
||||
});
|
||||
return await this._elementChannel.fill({ value, ...options });
|
||||
}
|
||||
|
||||
async selectText(options: channels.ElementHandleSelectTextOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
await channel.selectText(options);
|
||||
});
|
||||
await this._elementChannel.selectText(options);
|
||||
}
|
||||
|
||||
async setInputFiles(files: string | FilePayload | string[] | FilePayload[], options: channels.ElementHandleSetInputFilesOptions = {}) {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
await channel.setInputFiles({ files: await convertInputFiles(files), ...options });
|
||||
});
|
||||
await this._elementChannel.setInputFiles({ files: await convertInputFiles(files), ...options });
|
||||
}
|
||||
|
||||
async focus(): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
await channel.focus();
|
||||
});
|
||||
await this._elementChannel.focus();
|
||||
}
|
||||
|
||||
async type(text: string, options: channels.ElementHandleTypeOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
await channel.type({ text, ...options });
|
||||
});
|
||||
await this._elementChannel.type({ text, ...options });
|
||||
}
|
||||
|
||||
async press(key: string, options: channels.ElementHandlePressOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
await channel.press({ key, ...options });
|
||||
});
|
||||
await this._elementChannel.press({ key, ...options });
|
||||
}
|
||||
|
||||
async check(options: channels.ElementHandleCheckOptions = {}) {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return await channel.check(options);
|
||||
});
|
||||
return await this._elementChannel.check(options);
|
||||
}
|
||||
|
||||
async uncheck(options: channels.ElementHandleUncheckOptions = {}) {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return await channel.uncheck(options);
|
||||
});
|
||||
return await this._elementChannel.uncheck(options);
|
||||
}
|
||||
|
||||
async setChecked(checked: boolean, options?: channels.ElementHandleCheckOptions) {
|
||||
@ -225,67 +169,51 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
|
||||
}
|
||||
|
||||
async boundingBox(): Promise<Rect | null> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
const value = (await channel.boundingBox()).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
const value = (await this._elementChannel.boundingBox()).value;
|
||||
return value === undefined ? null : value;
|
||||
}
|
||||
|
||||
async screenshot(options: channels.ElementHandleScreenshotOptions & { path?: string } = {}): Promise<Buffer> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
const copy = { ...options };
|
||||
if (!copy.type)
|
||||
copy.type = determineScreenshotType(options);
|
||||
const result = await channel.screenshot(copy);
|
||||
const buffer = Buffer.from(result.binary, 'base64');
|
||||
if (options.path) {
|
||||
await mkdirIfNeeded(options.path);
|
||||
await fs.promises.writeFile(options.path, buffer);
|
||||
}
|
||||
return buffer;
|
||||
});
|
||||
const copy = { ...options };
|
||||
if (!copy.type)
|
||||
copy.type = determineScreenshotType(options);
|
||||
const result = await this._elementChannel.screenshot(copy);
|
||||
const buffer = Buffer.from(result.binary, 'base64');
|
||||
if (options.path) {
|
||||
await mkdirIfNeeded(options.path);
|
||||
await fs.promises.writeFile(options.path, buffer);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
async $(selector: string): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return ElementHandle.fromNullable((await channel.querySelector({ selector })).element) as ElementHandle<SVGElement | HTMLElement> | null;
|
||||
});
|
||||
return ElementHandle.fromNullable((await this._elementChannel.querySelector({ selector })).element) as ElementHandle<SVGElement | HTMLElement> | null;
|
||||
}
|
||||
|
||||
async $$(selector: string): Promise<ElementHandle<SVGElement | HTMLElement>[]> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
const result = await channel.querySelectorAll({ selector });
|
||||
return result.elements.map(h => ElementHandle.from(h) as ElementHandle<SVGElement | HTMLElement>);
|
||||
});
|
||||
const result = await this._elementChannel.querySelectorAll({ selector });
|
||||
return result.elements.map(h => ElementHandle.from(h) as ElementHandle<SVGElement | HTMLElement>);
|
||||
}
|
||||
|
||||
async $eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element, Arg, R>, arg?: Arg): Promise<R> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
const result = await channel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
});
|
||||
const result = await this._elementChannel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
}
|
||||
|
||||
async $$eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element[], Arg, R>, arg?: Arg): Promise<R> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
const result = await channel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
});
|
||||
const result = await this._elementChannel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
}
|
||||
|
||||
async waitForElementState(state: 'visible' | 'hidden' | 'stable' | 'enabled' | 'disabled', options: channels.ElementHandleWaitForElementStateOptions = {}): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.ElementHandleChannel) => {
|
||||
return await channel.waitForElementState({ state, ...options });
|
||||
});
|
||||
return await this._elementChannel.waitForElementState({ state, ...options });
|
||||
}
|
||||
|
||||
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(async (channel: channels.ElementHandleChannel) => {
|
||||
const result = await channel.waitForSelector({ selector, ...options });
|
||||
return ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
|
||||
});
|
||||
const result = await this._elementChannel.waitForSelector({ selector, ...options });
|
||||
return ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,16 +56,14 @@ export class APIRequest implements api.APIRequest {
|
||||
}
|
||||
|
||||
async newContext(options: NewContextOptions = {}): Promise<APIRequestContext> {
|
||||
return await this._playwright._wrapApiCall(async (channel: channels.PlaywrightChannel) => {
|
||||
const storageState = typeof options.storageState === 'string' ?
|
||||
JSON.parse(await fs.promises.readFile(options.storageState, 'utf8')) :
|
||||
options.storageState;
|
||||
return APIRequestContext.from((await channel.newRequest({
|
||||
...options,
|
||||
extraHTTPHeaders: options.extraHTTPHeaders ? headersObjectToArray(options.extraHTTPHeaders) : undefined,
|
||||
storageState,
|
||||
})).request);
|
||||
});
|
||||
const storageState = typeof options.storageState === 'string' ?
|
||||
JSON.parse(await fs.promises.readFile(options.storageState, 'utf8')) :
|
||||
options.storageState;
|
||||
return APIRequestContext.from((await this._playwright._channel.newRequest({
|
||||
...options,
|
||||
extraHTTPHeaders: options.extraHTTPHeaders ? headersObjectToArray(options.extraHTTPHeaders) : undefined,
|
||||
storageState,
|
||||
})).request);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,10 +76,8 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
dispose(): Promise<void> {
|
||||
return this._wrapApiCall(async (channel: channels.APIRequestContextChannel) => {
|
||||
await channel.dispose();
|
||||
});
|
||||
async dispose(): Promise<void> {
|
||||
await this._channel.dispose();
|
||||
}
|
||||
|
||||
async delete(url: string, options?: RequestWithBodyOptions): Promise<APIResponse> {
|
||||
@ -127,7 +123,7 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
}
|
||||
|
||||
async fetch(urlOrRequest: string | api.Request, options: FetchOptions = {}): Promise<APIResponse> {
|
||||
return this._wrapApiCall(async (channel: channels.APIRequestContextChannel) => {
|
||||
return this._wrapApiCall(async () => {
|
||||
const request: network.Request | undefined = (urlOrRequest instanceof network.Request) ? urlOrRequest as network.Request : undefined;
|
||||
assert(request || typeof urlOrRequest === 'string', 'First argument must be either URL string or Request');
|
||||
assert((options.data === undefined ? 0 : 1) + (options.form === undefined ? 0 : 1) + (options.multipart === undefined ? 0 : 1) <= 1, `Only one of 'data', 'form' or 'multipart' can be specified`);
|
||||
@ -175,7 +171,7 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
if (postDataBuffer === undefined && jsonData === undefined && formData === undefined && multipartData === undefined)
|
||||
postDataBuffer = request?.postDataBuffer() || undefined;
|
||||
const postData = (postDataBuffer ? postDataBuffer.toString('base64') : undefined);
|
||||
const result = await channel.fetch({
|
||||
const result = await this._channel.fetch({
|
||||
url,
|
||||
params,
|
||||
method,
|
||||
@ -195,14 +191,12 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
}
|
||||
|
||||
async storageState(options: { path?: string } = {}): Promise<StorageState> {
|
||||
return await this._wrapApiCall(async (channel: channels.APIRequestContextChannel) => {
|
||||
const state = await channel.storageState();
|
||||
if (options.path) {
|
||||
await mkdirIfNeeded(options.path);
|
||||
await fs.promises.writeFile(options.path, JSON.stringify(state, undefined, 2), 'utf8');
|
||||
}
|
||||
return state;
|
||||
});
|
||||
const state = await this._channel.storageState();
|
||||
if (options.path) {
|
||||
await mkdirIfNeeded(options.path);
|
||||
await fs.promises.writeFile(options.path, JSON.stringify(state, undefined, 2), 'utf8');
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,18 +236,16 @@ export class APIResponse implements api.APIResponse {
|
||||
}
|
||||
|
||||
async body(): Promise<Buffer> {
|
||||
return this._request._wrapApiCall(async (channel: channels.APIRequestContextChannel) => {
|
||||
try {
|
||||
const result = await channel.fetchResponseBody({ fetchUid: this._fetchUid() });
|
||||
if (result.binary === undefined)
|
||||
throw new Error('Response has been disposed');
|
||||
return Buffer.from(result.binary!, 'base64');
|
||||
} catch (e) {
|
||||
if (e.message === kBrowserOrContextClosedError)
|
||||
throw new Error('Response has been disposed');
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
try {
|
||||
const result = await this._request._channel.fetchResponseBody({ fetchUid: this._fetchUid() });
|
||||
if (result.binary === undefined)
|
||||
throw new Error('Response has been disposed');
|
||||
return Buffer.from(result.binary!, 'base64');
|
||||
} catch (e) {
|
||||
if (e.message.includes(kBrowserOrContextClosedError))
|
||||
throw new Error('Response has been disposed');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async text(): Promise<string> {
|
||||
@ -267,9 +259,7 @@ export class APIResponse implements api.APIResponse {
|
||||
}
|
||||
|
||||
async dispose(): Promise<void> {
|
||||
return this._request._wrapApiCall(async (channel: channels.APIRequestContextChannel) => {
|
||||
await channel.disposeAPIResponse({ fetchUid: this._fetchUid() });
|
||||
});
|
||||
await this._request._channel.disposeAPIResponse({ fetchUid: this._fetchUid() });
|
||||
}
|
||||
|
||||
[util.inspect.custom]() {
|
||||
|
@ -44,8 +44,6 @@ export class FileChooser implements api.FileChooser {
|
||||
}
|
||||
|
||||
async setFiles(files: string | FilePayload | string[] | FilePayload[], options?: channels.ElementHandleSetInputFilesOptions) {
|
||||
return this._page._wrapApiCall(async () => {
|
||||
return this._elementHandle.setInputFiles(files, options);
|
||||
});
|
||||
return this._elementHandle.setInputFiles(files, options);
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
|
||||
}
|
||||
|
||||
async waitForNavigation(options: WaitForNavigationOptions = {}): Promise<network.Response | null> {
|
||||
return this._page!._wrapApiCall(async (channel: channels.PageChannel) => {
|
||||
return this._page!._wrapApiCall(async () => {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
const waiter = this._setupNavigationWaiter(options);
|
||||
|
||||
@ -143,7 +143,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
|
||||
state = verifyLoadState('state', state);
|
||||
if (this._loadStates.has(state))
|
||||
return;
|
||||
return this._page!._wrapApiCall(async (channel: channels.PageChannel) => {
|
||||
return this._page!._wrapApiCall(async () => {
|
||||
const waiter = this._setupNavigationWaiter(options);
|
||||
await waiter.waitForEvent<LifecycleEvent>(this._eventEmitter, 'loadstate', s => {
|
||||
waiter.log(` "${s}" event fired`);
|
||||
|
@ -27,33 +27,23 @@ export class Keyboard implements api.Keyboard {
|
||||
}
|
||||
|
||||
async down(key: string) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.keyboardDown({ key });
|
||||
});
|
||||
await this._page._channel.keyboardDown({ key });
|
||||
}
|
||||
|
||||
async up(key: string) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.keyboardUp({ key });
|
||||
});
|
||||
await this._page._channel.keyboardUp({ key });
|
||||
}
|
||||
|
||||
async insertText(text: string) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.keyboardInsertText({ text });
|
||||
});
|
||||
await this._page._channel.keyboardInsertText({ text });
|
||||
}
|
||||
|
||||
async type(text: string, options: channels.PageKeyboardTypeOptions = {}) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.keyboardType({ text, ...options });
|
||||
});
|
||||
await this._page._channel.keyboardType({ text, ...options });
|
||||
}
|
||||
|
||||
async press(key: string, options: channels.PageKeyboardPressOptions = {}) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.keyboardPress({ key, ...options });
|
||||
});
|
||||
await this._page._channel.keyboardPress({ key, ...options });
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,27 +55,19 @@ export class Mouse implements api.Mouse {
|
||||
}
|
||||
|
||||
async move(x: number, y: number, options: { steps?: number } = {}) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.mouseMove({ x, y, ...options });
|
||||
});
|
||||
await this._page._channel.mouseMove({ x, y, ...options });
|
||||
}
|
||||
|
||||
async down(options: channels.PageMouseDownOptions = {}) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.mouseDown({ ...options });
|
||||
});
|
||||
await this._page._channel.mouseDown({ ...options });
|
||||
}
|
||||
|
||||
async up(options: channels.PageMouseUpOptions = {}) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.mouseUp(options);
|
||||
});
|
||||
await this._page._channel.mouseUp(options);
|
||||
}
|
||||
|
||||
async click(x: number, y: number, options: channels.PageMouseClickOptions = {}) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.mouseClick({ x, y, ...options });
|
||||
});
|
||||
await this._page._channel.mouseClick({ x, y, ...options });
|
||||
}
|
||||
|
||||
async dblclick(x: number, y: number, options: Omit<channels.PageMouseClickOptions, 'clickCount'> = {}) {
|
||||
@ -93,9 +75,7 @@ export class Mouse implements api.Mouse {
|
||||
}
|
||||
|
||||
async wheel(deltaX: number, deltaY: number) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.mouseWheel({ deltaX, deltaY });
|
||||
});
|
||||
await this._page._channel.mouseWheel({ deltaX, deltaY });
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,8 +87,6 @@ export class Touchscreen implements api.Touchscreen {
|
||||
}
|
||||
|
||||
async tap(x: number, y: number) {
|
||||
await this._page._wrapApiCall(async channel => {
|
||||
await channel.touchscreenTap({ x, y });
|
||||
});
|
||||
await this._page._channel.touchscreenTap({ x, y });
|
||||
}
|
||||
}
|
||||
|
@ -34,39 +34,29 @@ export class JSHandle<T = any> extends ChannelOwner<channels.JSHandleChannel> im
|
||||
}
|
||||
|
||||
async evaluate<R, Arg>(pageFunction: structs.PageFunctionOn<T, Arg, R>, arg?: Arg): Promise<R> {
|
||||
return this._wrapApiCall(async (channel: channels.JSHandleChannel) => {
|
||||
const result = await channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
});
|
||||
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
}
|
||||
|
||||
async evaluateHandle<R, Arg>(pageFunction: structs.PageFunctionOn<T, Arg, R>, arg?: Arg): Promise<structs.SmartHandle<R>> {
|
||||
return this._wrapApiCall(async (channel: channels.JSHandleChannel) => {
|
||||
const result = await channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
|
||||
});
|
||||
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
|
||||
}
|
||||
|
||||
async getProperty(propertyName: string): Promise<JSHandle> {
|
||||
return this._wrapApiCall(async (channel: channels.JSHandleChannel) => {
|
||||
const result = await channel.getProperty({ name: propertyName });
|
||||
return JSHandle.from(result.handle);
|
||||
});
|
||||
const result = await this._channel.getProperty({ name: propertyName });
|
||||
return JSHandle.from(result.handle);
|
||||
}
|
||||
|
||||
async getProperties(): Promise<Map<string, JSHandle>> {
|
||||
return this._wrapApiCall(async (channel: channels.JSHandleChannel) => {
|
||||
const map = new Map<string, JSHandle>();
|
||||
for (const { name, value } of (await channel.getPropertyList()).properties)
|
||||
map.set(name, JSHandle.from(value));
|
||||
return map;
|
||||
});
|
||||
const map = new Map<string, JSHandle>();
|
||||
for (const { name, value } of (await this._channel.getPropertyList()).properties)
|
||||
map.set(name, JSHandle.from(value));
|
||||
return map;
|
||||
}
|
||||
|
||||
async jsonValue(): Promise<T> {
|
||||
return this._wrapApiCall(async (channel: channels.JSHandleChannel) => {
|
||||
return parseResult((await channel.jsonValue()).value);
|
||||
});
|
||||
return parseResult((await this._channel.jsonValue()).value);
|
||||
}
|
||||
|
||||
asElement(): T extends Node ? api.ElementHandle<T> : null {
|
||||
@ -74,9 +64,7 @@ export class JSHandle<T = any> extends ChannelOwner<channels.JSHandleChannel> im
|
||||
}
|
||||
|
||||
async dispose() {
|
||||
return this._wrapApiCall(async (channel: channels.JSHandleChannel) => {
|
||||
return await channel.dispose();
|
||||
});
|
||||
return await this._channel.dispose();
|
||||
}
|
||||
|
||||
override toString(): string {
|
||||
|
@ -37,8 +37,8 @@ export class Locator implements api.Locator {
|
||||
timeout = this._frame.page()._timeoutSettings.timeout({ timeout });
|
||||
const deadline = timeout ? monotonicTime() + timeout : 0;
|
||||
|
||||
return this._frame._wrapApiCall<R>(async (channel: channels.FrameChannel) => {
|
||||
const result = await channel.waitForSelector({ selector: this._selector, strict: true, state: 'attached', timeout });
|
||||
return this._frame._wrapApiCall<R>(async () => {
|
||||
const result = await this._frame._channel.waitForSelector({ selector: this._selector, strict: true, state: 'attached', timeout });
|
||||
const handle = ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
|
||||
if (!handle)
|
||||
throw new Error(`Could not resolve ${this._selector} to DOM Element`);
|
||||
@ -224,21 +224,17 @@ export class Locator implements api.Locator {
|
||||
waitFor(options: channels.FrameWaitForSelectorOptions & { state: 'attached' | 'visible' }): Promise<void>;
|
||||
waitFor(options?: channels.FrameWaitForSelectorOptions): Promise<void>;
|
||||
async waitFor(options?: channels.FrameWaitForSelectorOptions): Promise<void> {
|
||||
return this._frame._wrapApiCall(async (channel: channels.FrameChannel) => {
|
||||
await channel.waitForSelector({ selector: this._selector, strict: true, omitReturnValue: true, ...options });
|
||||
});
|
||||
await this._frame._channel.waitForSelector({ selector: this._selector, strict: true, omitReturnValue: true, ...options });
|
||||
}
|
||||
|
||||
async _expect(expression: string, options: FrameExpectOptions): Promise<{ matches: boolean, received?: any, log?: string[] }> {
|
||||
return this._frame._wrapApiCall(async (channel: channels.FrameChannel) => {
|
||||
const params: channels.FrameExpectParams = { selector: this._selector, expression, ...options, isNot: !!options.isNot };
|
||||
if (options.expectedValue)
|
||||
params.expectedValue = serializeArgument(options.expectedValue);
|
||||
const result = (await channel.expect(params));
|
||||
if (result.received !== undefined)
|
||||
result.received = parseResult(result.received);
|
||||
return result;
|
||||
});
|
||||
const params: channels.FrameExpectParams = { selector: this._selector, expression, ...options, isNot: !!options.isNot };
|
||||
if (options.expectedValue)
|
||||
params.expectedValue = serializeArgument(options.expectedValue);
|
||||
const result = (await this._frame._channel.expect(params));
|
||||
if (result.received !== undefined)
|
||||
result.received = parseResult(result.received);
|
||||
return result;
|
||||
}
|
||||
|
||||
[util.inspect.custom]() {
|
||||
|
@ -142,8 +142,8 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
|
||||
|
||||
_actualHeaders(): Promise<RawHeaders> {
|
||||
if (!this._actualHeadersPromise) {
|
||||
this._actualHeadersPromise = this._wrapApiCall(async (channel: channels.RequestChannel) => {
|
||||
return new RawHeaders((await channel.rawRequestHeaders()).headers);
|
||||
this._actualHeadersPromise = this._wrapApiCall(async () => {
|
||||
return new RawHeaders((await this._channel.rawRequestHeaders()).headers);
|
||||
});
|
||||
}
|
||||
return this._actualHeadersPromise;
|
||||
@ -162,14 +162,12 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
|
||||
}
|
||||
|
||||
async response(): Promise<Response | null> {
|
||||
return this._wrapApiCall(async (channel: channels.RequestChannel) => {
|
||||
return Response.fromNullable((await channel.response()).response);
|
||||
});
|
||||
return Response.fromNullable((await this._channel.response()).response);
|
||||
}
|
||||
|
||||
async _internalResponse(): Promise<Response | null> {
|
||||
return this._wrapApiCall(async (channel: channels.RequestChannel) => {
|
||||
return Response.fromNullable((await channel.response()).response);
|
||||
return this._wrapApiCall(async () => {
|
||||
return Response.fromNullable((await this._channel.response()).response);
|
||||
}, true);
|
||||
}
|
||||
|
||||
@ -205,9 +203,7 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
|
||||
const response = await this.response();
|
||||
if (!response)
|
||||
throw new Error('Unable to fetch sizes for failed request');
|
||||
return response._wrapApiCall(async (channel: channels.ResponseChannel) => {
|
||||
return (await channel.sizes()).sizes;
|
||||
});
|
||||
return (await response._channel.sizes()).sizes;
|
||||
}
|
||||
|
||||
_finalRequest(): Request {
|
||||
@ -240,56 +236,52 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
|
||||
}
|
||||
|
||||
async abort(errorCode?: string) {
|
||||
return this._wrapApiCall(async (channel: channels.RouteChannel) => {
|
||||
await this._raceWithPageClose(channel.abort({ errorCode }));
|
||||
});
|
||||
await this._raceWithPageClose(this._channel.abort({ errorCode }));
|
||||
}
|
||||
|
||||
async fulfill(options: { response?: api.APIResponse, status?: number, headers?: Headers, contentType?: string, body?: string | Buffer, path?: string } = {}) {
|
||||
return this._wrapApiCall(async (channel: channels.RouteChannel) => {
|
||||
let fetchResponseUid;
|
||||
let { status: statusOption, headers: headersOption, body } = options;
|
||||
if (options.response) {
|
||||
statusOption ||= options.response.status();
|
||||
headersOption ||= options.response.headers();
|
||||
if (options.body === undefined && options.path === undefined && options.response instanceof APIResponse)
|
||||
fetchResponseUid = (options.response as APIResponse)._fetchUid();
|
||||
}
|
||||
let fetchResponseUid;
|
||||
let { status: statusOption, headers: headersOption, body } = options;
|
||||
if (options.response) {
|
||||
statusOption ||= options.response.status();
|
||||
headersOption ||= options.response.headers();
|
||||
if (options.body === undefined && options.path === undefined && options.response instanceof APIResponse)
|
||||
fetchResponseUid = (options.response as APIResponse)._fetchUid();
|
||||
}
|
||||
|
||||
let isBase64 = false;
|
||||
let length = 0;
|
||||
if (options.path) {
|
||||
const buffer = await fs.promises.readFile(options.path);
|
||||
body = buffer.toString('base64');
|
||||
isBase64 = true;
|
||||
length = buffer.length;
|
||||
} else if (isString(body)) {
|
||||
isBase64 = false;
|
||||
length = Buffer.byteLength(body);
|
||||
} else if (body) {
|
||||
length = body.length;
|
||||
body = body.toString('base64');
|
||||
isBase64 = true;
|
||||
}
|
||||
let isBase64 = false;
|
||||
let length = 0;
|
||||
if (options.path) {
|
||||
const buffer = await fs.promises.readFile(options.path);
|
||||
body = buffer.toString('base64');
|
||||
isBase64 = true;
|
||||
length = buffer.length;
|
||||
} else if (isString(body)) {
|
||||
isBase64 = false;
|
||||
length = Buffer.byteLength(body);
|
||||
} else if (body) {
|
||||
length = body.length;
|
||||
body = body.toString('base64');
|
||||
isBase64 = true;
|
||||
}
|
||||
|
||||
const headers: Headers = {};
|
||||
for (const header of Object.keys(headersOption || {}))
|
||||
headers[header.toLowerCase()] = String(headersOption![header]);
|
||||
if (options.contentType)
|
||||
headers['content-type'] = String(options.contentType);
|
||||
else if (options.path)
|
||||
headers['content-type'] = mime.getType(options.path) || 'application/octet-stream';
|
||||
if (length && !('content-length' in headers))
|
||||
headers['content-length'] = String(length);
|
||||
const headers: Headers = {};
|
||||
for (const header of Object.keys(headersOption || {}))
|
||||
headers[header.toLowerCase()] = String(headersOption![header]);
|
||||
if (options.contentType)
|
||||
headers['content-type'] = String(options.contentType);
|
||||
else if (options.path)
|
||||
headers['content-type'] = mime.getType(options.path) || 'application/octet-stream';
|
||||
if (length && !('content-length' in headers))
|
||||
headers['content-length'] = String(length);
|
||||
|
||||
await this._raceWithPageClose(channel.fulfill({
|
||||
status: statusOption || 200,
|
||||
headers: headersObjectToArray(headers),
|
||||
body,
|
||||
isBase64,
|
||||
fetchResponseUid
|
||||
}));
|
||||
});
|
||||
await this._raceWithPageClose(this._channel.fulfill({
|
||||
status: statusOption || 200,
|
||||
headers: headersObjectToArray(headers),
|
||||
body,
|
||||
isBase64,
|
||||
fetchResponseUid
|
||||
}));
|
||||
}
|
||||
|
||||
async continue(options: { url?: string, method?: string, headers?: Headers, postData?: string | Buffer } = {}) {
|
||||
@ -301,9 +293,9 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
|
||||
}
|
||||
|
||||
private async _continue(options: { url?: string, method?: string, headers?: Headers, postData?: string | Buffer }, isInternal?: boolean) {
|
||||
return await this._wrapApiCall(async (channel: channels.RouteChannel) => {
|
||||
return await this._wrapApiCall(async () => {
|
||||
const postDataBuffer = isString(options.postData) ? Buffer.from(options.postData, 'utf8') : options.postData;
|
||||
await this._raceWithPageClose(channel.continue({
|
||||
await this._raceWithPageClose(this._channel.continue({
|
||||
url: options.url,
|
||||
method: options.method,
|
||||
headers: options.headers ? headersObjectToArray(options.headers) : undefined,
|
||||
@ -381,9 +373,9 @@ export class Response extends ChannelOwner<channels.ResponseChannel> implements
|
||||
|
||||
async _actualHeaders(): Promise<RawHeaders> {
|
||||
if (!this._actualHeadersPromise) {
|
||||
this._actualHeadersPromise = this._wrapApiCall(async (channel: channels.ResponseChannel) => {
|
||||
return new RawHeaders((await channel.rawResponseHeaders()).headers);
|
||||
});
|
||||
this._actualHeadersPromise = (async () => {
|
||||
return new RawHeaders((await this._channel.rawResponseHeaders()).headers);
|
||||
})();
|
||||
}
|
||||
return this._actualHeadersPromise;
|
||||
}
|
||||
@ -409,9 +401,7 @@ export class Response extends ChannelOwner<channels.ResponseChannel> implements
|
||||
}
|
||||
|
||||
async body(): Promise<Buffer> {
|
||||
return this._wrapApiCall(async (channel: channels.ResponseChannel) => {
|
||||
return Buffer.from((await channel.body()).binary, 'base64');
|
||||
});
|
||||
return Buffer.from((await this._channel.body()).binary, 'base64');
|
||||
}
|
||||
|
||||
async text(): Promise<string> {
|
||||
@ -433,15 +423,11 @@ export class Response extends ChannelOwner<channels.ResponseChannel> implements
|
||||
}
|
||||
|
||||
async serverAddr(): Promise<RemoteAddr|null> {
|
||||
return this._wrapApiCall(async (channel: channels.ResponseChannel) => {
|
||||
return (await channel.serverAddr()).value || null;
|
||||
});
|
||||
return (await this._channel.serverAddr()).value || null;
|
||||
}
|
||||
|
||||
async securityDetails(): Promise<SecurityDetails|null> {
|
||||
return this._wrapApiCall(async (channel: channels.ResponseChannel) => {
|
||||
return (await channel.securityDetails()).value || null;
|
||||
});
|
||||
return (await this._channel.securityDetails()).value || null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,10 +471,10 @@ export class WebSocket extends ChannelOwner<channels.WebSocketChannel> implement
|
||||
}
|
||||
|
||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||
return this._wrapApiCall(async (channel: channels.WebSocketChannel) => {
|
||||
return this._wrapApiCall(async () => {
|
||||
const timeout = this._page._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = Waiter.createForEvent(channel, event);
|
||||
const waiter = Waiter.createForEvent(this._channel, event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
|
||||
if (event !== Events.WebSocket.Error)
|
||||
waiter.rejectOnEvent(this, Events.WebSocket.Error, new Error('Socket error'));
|
||||
|
@ -173,7 +173,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||
if (routeHandler.handle(route, request)) {
|
||||
this._routes.splice(this._routes.indexOf(routeHandler), 1);
|
||||
if (!this._routes.length)
|
||||
this._wrapApiCall(channel => this._disableInterception(channel), true).catch(() => {});
|
||||
this._wrapApiCall(() => this._disableInterception(), true).catch(() => {});
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -440,11 +440,11 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||
async unroute(url: URLMatch, handler?: RouteHandlerCallback): Promise<void> {
|
||||
this._routes = this._routes.filter(route => route.url !== url || (handler && route.handler !== handler));
|
||||
if (!this._routes.length)
|
||||
await this._disableInterception(this._channel);
|
||||
await this._disableInterception();
|
||||
}
|
||||
|
||||
private async _disableInterception(channel: channels.PageChannel) {
|
||||
await channel.setNetworkInterceptionEnabled({ enabled: false });
|
||||
private async _disableInterception() {
|
||||
await this._channel.setNetworkInterceptionEnabled({ enabled: false });
|
||||
}
|
||||
|
||||
async screenshot(options: channels.PageScreenshotOptions & { path?: string } = {}): Promise<Buffer> {
|
||||
@ -470,12 +470,10 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||
|
||||
async close(options: { runBeforeUnload?: boolean } = { runBeforeUnload: undefined }) {
|
||||
try {
|
||||
await this._wrapApiCall(async (channel: channels.PageChannel) => {
|
||||
if (this._ownedContext)
|
||||
await this._ownedContext.close();
|
||||
else
|
||||
await channel.close(options);
|
||||
});
|
||||
if (this._ownedContext)
|
||||
await this._ownedContext.close();
|
||||
else
|
||||
await this._channel.close(options);
|
||||
} catch (e) {
|
||||
if (isSafeCloseError(e))
|
||||
return;
|
||||
|
@ -46,29 +46,25 @@ export class Tracing implements api.Tracing {
|
||||
async start(options: { name?: string, title?: string, snapshots?: boolean, screenshots?: boolean, sources?: boolean } = {}) {
|
||||
if (options.sources)
|
||||
this._context._instrumentation!.addListener(this._instrumentationListener);
|
||||
await this._context._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.tracingStart(options);
|
||||
await channel.tracingStartChunk({ title: options.title });
|
||||
await this._context._wrapApiCall(async () => {
|
||||
await this._context._channel.tracingStart(options);
|
||||
await this._context._channel.tracingStartChunk({ title: options.title });
|
||||
});
|
||||
}
|
||||
|
||||
async startChunk(options: { title?: string } = {}) {
|
||||
this._sources = new Set();
|
||||
await this._context._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await channel.tracingStartChunk(options);
|
||||
});
|
||||
await this._context._channel.tracingStartChunk(options);
|
||||
}
|
||||
|
||||
async stopChunk(options: { path?: string } = {}) {
|
||||
await this._context._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await this._doStopChunk(channel, options.path);
|
||||
});
|
||||
await this._doStopChunk(this._context._channel, options.path);
|
||||
}
|
||||
|
||||
async stop(options: { path?: string } = {}) {
|
||||
await this._context._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
|
||||
await this._doStopChunk(channel, options.path);
|
||||
await channel.tracingStop();
|
||||
await this._context._wrapApiCall(async () => {
|
||||
await this._doStopChunk(this._context._channel, options.path);
|
||||
await this._context._channel.tracingStop();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -48,17 +48,13 @@ export class Worker extends ChannelOwner<channels.WorkerChannel> implements api.
|
||||
|
||||
async evaluate<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<R> {
|
||||
assertMaxArguments(arguments.length, 2);
|
||||
return this._wrapApiCall(async (channel: channels.WorkerChannel) => {
|
||||
const result = await channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
});
|
||||
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
}
|
||||
|
||||
async evaluateHandle<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<structs.SmartHandle<R>> {
|
||||
assertMaxArguments(arguments.length, 2);
|
||||
return this._wrapApiCall(async (channel: channels.WorkerChannel) => {
|
||||
const result = await channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
|
||||
});
|
||||
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
|
||||
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user