chore(protocol): make timeout a protocol-level field (#41712)

Co-authored-by: Copilot App <[email protected]>
This commit is contained in:
Simon Knott
2026-07-14 15:44:03 +02:00
committed by GitHub
co-authored by Copilot App
parent 60ecab05aa
commit 33173da843
56 changed files with 762 additions and 1004 deletions
+31 -32
View File
@@ -25,7 +25,7 @@ import { ChannelOwner } from './channelOwner';
import { TargetClosedError, isTargetClosedError } from './errors';
import { Events } from './events';
import { Waiter } from './waiter';
import { TimeoutSettings } from './timeoutSettings';
import { TimeoutSettings, kNoTimeout } from './timeoutSettings';
import { connectToEndpoint } from './connect';
import type { Page } from './page';
@@ -57,7 +57,7 @@ export class Android extends ChannelOwner<channels.AndroidChannel> implements ap
}
async devices(options: { port?: number } = {}): Promise<AndroidDevice[]> {
const { devices } = await this._channel.devices(options, undefined);
const { devices } = await this._channel.devices(options, kNoTimeout);
return devices.map(d => AndroidDevice.from(d));
}
@@ -71,8 +71,8 @@ export class Android extends ChannelOwner<channels.AndroidChannel> implements ap
return await this._wrapApiCall(async () => {
const deadline = options.timeout ? monotonicTime() + options.timeout : 0;
const headers = { 'x-playwright-browser': 'android', ...options.headers };
const connectParams: channels.LocalUtilsConnectParams = { endpoint, headers, slowMo: options.slowMo, timeout: options.timeout || 0 };
const connection = await connectToEndpoint(this._connection, connectParams);
const connectParams: channels.LocalUtilsConnectParams = { endpoint, headers, slowMo: options.slowMo };
const connection = await connectToEndpoint(this._connection, connectParams, { signal: undefined, timeout: options.timeout || 0 });
let device: AndroidDevice;
connection.on('close', () => {
@@ -166,11 +166,11 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
}
async wait(selector: api.AndroidSelector, options: { state?: 'gone' } & types.TimeoutOptions = {}) {
await this._channel.wait({ androidSelector: toSelectorChannel(selector), ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.wait({ androidSelector: toSelectorChannel(selector), ...options }, this._timeoutSettings.timeout(options));
}
async fill(selector: api.AndroidSelector, text: string, options: types.TimeoutOptions = {}) {
await this._channel.fill({ androidSelector: toSelectorChannel(selector), text, ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.fill({ androidSelector: toSelectorChannel(selector), text, ...options }, this._timeoutSettings.timeout(options));
}
async press(selector: api.AndroidSelector, key: api.AndroidKey, options: types.TimeoutOptions = {}) {
@@ -179,43 +179,43 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
}
async tap(selector: api.AndroidSelector, options: { duration?: number } & types.TimeoutOptions = {}) {
await this._channel.tap({ androidSelector: toSelectorChannel(selector), ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.tap({ androidSelector: toSelectorChannel(selector), ...options }, this._timeoutSettings.timeout(options));
}
async drag(selector: api.AndroidSelector, dest: types.Point, options: SpeedOptions & types.TimeoutOptions = {}) {
await this._channel.drag({ androidSelector: toSelectorChannel(selector), dest, ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.drag({ androidSelector: toSelectorChannel(selector), dest, ...options }, this._timeoutSettings.timeout(options));
}
async fling(selector: api.AndroidSelector, direction: Direction, options: SpeedOptions & types.TimeoutOptions = {}) {
await this._channel.fling({ androidSelector: toSelectorChannel(selector), direction, ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.fling({ androidSelector: toSelectorChannel(selector), direction, ...options }, this._timeoutSettings.timeout(options));
}
async longTap(selector: api.AndroidSelector, options: types.TimeoutOptions = {}) {
await this._channel.longTap({ androidSelector: toSelectorChannel(selector), ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.longTap({ androidSelector: toSelectorChannel(selector), ...options }, this._timeoutSettings.timeout(options));
}
async pinchClose(selector: api.AndroidSelector, percent: number, options: SpeedOptions & types.TimeoutOptions = {}) {
await this._channel.pinchClose({ androidSelector: toSelectorChannel(selector), percent, ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.pinchClose({ androidSelector: toSelectorChannel(selector), percent, ...options }, this._timeoutSettings.timeout(options));
}
async pinchOpen(selector: api.AndroidSelector, percent: number, options: SpeedOptions & types.TimeoutOptions = {}) {
await this._channel.pinchOpen({ androidSelector: toSelectorChannel(selector), percent, ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.pinchOpen({ androidSelector: toSelectorChannel(selector), percent, ...options }, this._timeoutSettings.timeout(options));
}
async scroll(selector: api.AndroidSelector, direction: Direction, percent: number, options: SpeedOptions & types.TimeoutOptions = {}) {
await this._channel.scroll({ androidSelector: toSelectorChannel(selector), direction, percent, ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.scroll({ androidSelector: toSelectorChannel(selector), direction, percent, ...options }, this._timeoutSettings.timeout(options));
}
async swipe(selector: api.AndroidSelector, direction: Direction, percent: number, options: SpeedOptions & types.TimeoutOptions = {}) {
await this._channel.swipe({ androidSelector: toSelectorChannel(selector), direction, percent, ...options, timeout: this._timeoutSettings.timeout(options) }, options.signal);
await this._channel.swipe({ androidSelector: toSelectorChannel(selector), direction, percent, ...options }, this._timeoutSettings.timeout(options));
}
async info(selector: api.AndroidSelector): Promise<api.AndroidElementInfo> {
return (await this._channel.info({ androidSelector: toSelectorChannel(selector) }, undefined)).info;
return (await this._channel.info({ androidSelector: toSelectorChannel(selector) }, kNoTimeout)).info;
}
async screenshot(options: { path?: string } = {}): Promise<Buffer> {
const { binary } = await this._channel.screenshot({}, undefined);
const { binary } = await this._channel.screenshot({}, kNoTimeout);
if (options.path)
await fs.promises.writeFile(options.path, binary);
return binary;
@@ -230,7 +230,7 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
if (this._shouldCloseConnectionOnClose)
this._connection.close();
else
await this._channel.close({}, undefined);
await this._channel.close({}, kNoTimeout);
} catch (e) {
if (isTargetClosedError(e))
return;
@@ -243,25 +243,25 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
}
async shell(command: string): Promise<Buffer> {
const { result } = await this._channel.shell({ command }, undefined);
const { result } = await this._channel.shell({ command }, kNoTimeout);
return result;
}
async open(command: string): Promise<AndroidSocket> {
return AndroidSocket.from((await this._channel.open({ command }, undefined)).socket);
return AndroidSocket.from((await this._channel.open({ command }, kNoTimeout)).socket);
}
async installApk(file: string | Buffer, options?: { args: string[] }): Promise<void> {
await this._channel.installApk({ file: await loadFile(file), args: options && options.args }, undefined);
await this._channel.installApk({ file: await loadFile(file), args: options && options.args }, kNoTimeout);
}
async push(file: string | Buffer, path: string, options?: { mode: number }): Promise<void> {
await this._channel.push({ file: await loadFile(file), path, mode: options ? options.mode : undefined }, undefined);
await this._channel.push({ file: await loadFile(file), path, mode: options ? options.mode : undefined }, kNoTimeout);
}
async launchBrowser(options: types.BrowserContextOptions & { pkg?: string } = {}): Promise<BrowserContext> {
const contextOptions = await prepareBrowserContextParams(options);
const result = await this._channel.launchBrowser(contextOptions, undefined);
const result = await this._channel.launchBrowser(contextOptions, kNoTimeout);
const context = BrowserContext.from(result.context);
const selectors = this._android._playwright.selectors;
selectors._contextsForSelectors.add(context);
@@ -272,9 +272,8 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
return await this._wrapApiCall(async () => {
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const { timeout, signal } = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const signal = typeof optionsOrPredicate === 'function' ? undefined : (optionsOrPredicate as types.TimeoutOptions).signal;
const waiter = Waiter.createForEvent(this, event);
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
waiter.rejectOnSignal(signal);
@@ -299,11 +298,11 @@ export class AndroidSocket extends ChannelOwner<channels.AndroidSocketChannel> i
}
async write(data: Buffer): Promise<void> {
await this._channel.write({ data }, undefined);
await this._channel.write({ data }, kNoTimeout);
}
async close(): Promise<void> {
await this._channel.close({}, undefined);
await this._channel.close({}, kNoTimeout);
}
async [Symbol.asyncDispose]() {
@@ -325,23 +324,23 @@ export class AndroidInput implements api.AndroidInput {
}
async type(text: string) {
await this._device._channel.inputType({ text }, undefined);
await this._device._channel.inputType({ text }, kNoTimeout);
}
async press(key: api.AndroidKey) {
await this._device._channel.inputPress({ key }, undefined);
await this._device._channel.inputPress({ key }, kNoTimeout);
}
async tap(point: types.Point) {
await this._device._channel.inputTap({ point }, undefined);
await this._device._channel.inputTap({ point }, kNoTimeout);
}
async swipe(from: types.Point, segments: types.Point[], steps: number) {
await this._device._channel.inputSwipe({ segments, steps }, undefined);
await this._device._channel.inputSwipe({ segments, steps }, kNoTimeout);
}
async drag(from: types.Point, to: types.Point, steps: number) {
await this._device._channel.inputDrag({ from, to, steps }, undefined);
await this._device._channel.inputDrag({ from, to, steps }, kNoTimeout);
}
}
@@ -425,7 +424,7 @@ export class AndroidWebView extends EventEmitter implements api.AndroidWebView {
}
private async _fetchPage(): Promise<Page> {
const { context } = await this._device._channel.connectToWebView({ socketName: this._data.socketName }, undefined);
const { context } = await this._device._channel.connectToWebView({ socketName: this._data.socketName }, kNoTimeout);
return BrowserContext.from(context).pages()[0];
}
}
@@ -19,6 +19,7 @@ import fs from 'fs';
import { ChannelOwner } from './channelOwner';
import { Stream } from './stream';
import { mkdirIfNeeded } from './fileUtils';
import { kNoTimeout } from './timeoutSettings';
import type * as channels from './channels';
import type { Readable } from 'stream';
@@ -31,16 +32,16 @@ export class Artifact extends ChannelOwner<channels.ArtifactChannel> {
async pathAfterFinished(): Promise<string> {
if (this._connection.isRemote())
throw new Error(`Path is not available when connecting remotely. Use saveAs() to save a local copy.`);
return (await this._channel.pathAfterFinished({}, undefined)).value;
return (await this._channel.pathAfterFinished({}, kNoTimeout)).value;
}
async saveAs(path: string): Promise<void> {
if (!this._connection.isRemote()) {
await this._channel.saveAs({ path }, undefined);
await this._channel.saveAs({ path }, kNoTimeout);
return;
}
const result = await this._channel.saveAsStream({}, undefined);
const result = await this._channel.saveAsStream({}, kNoTimeout);
const stream = Stream.from(result.stream);
await mkdirIfNeeded(path);
await new Promise((resolve, reject) => {
@@ -51,11 +52,11 @@ export class Artifact extends ChannelOwner<channels.ArtifactChannel> {
}
async failure(): Promise<string | null> {
return (await this._channel.failure({}, undefined)).error || null;
return (await this._channel.failure({}, kNoTimeout)).error || null;
}
async createReadStream(): Promise<Readable> {
const result = await this._channel.stream({}, undefined);
const result = await this._channel.stream({}, kNoTimeout);
const stream = Stream.from(result.stream);
return stream.stream();
}
@@ -75,10 +76,10 @@ export class Artifact extends ChannelOwner<channels.ArtifactChannel> {
}
async cancel(): Promise<void> {
return await this._channel.cancel({}, undefined);
return await this._channel.cancel({}, kNoTimeout);
}
async delete(): Promise<void> {
return await this._channel.delete({}, undefined);
return await this._channel.delete({}, kNoTimeout);
}
}
@@ -23,6 +23,7 @@ import { ChannelOwner } from './channelOwner';
import { isTargetClosedError } from './errors';
import { Events } from './events';
import { mkdirIfNeeded } from './fileUtils';
import { kNoTimeout } from './timeoutSettings';
import type { BrowserType } from './browserType';
import type { Page } from './page';
@@ -75,14 +76,14 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
for (const page of context.pages())
page._onClose();
context._onClose();
await this._channel.disconnectFromReusedContext({ reason }, undefined);
await this._channel.disconnectFromReusedContext({ reason }, kNoTimeout);
}
async _innerNewContext(userOptions: BrowserContextOptions = {}, forReuse: boolean): Promise<BrowserContext> {
const options = this._browserType._playwright.selectors._withSelectorOptions(userOptions);
await this._instrumentation.runBeforeCreateBrowserContext(options);
const contextOptions = await prepareBrowserContextParams(options);
const response = forReuse ? await this._channel.newContextForReuse(contextOptions, undefined) : await this._channel.newContext(contextOptions, undefined);
const response = forReuse ? await this._channel.newContextForReuse(contextOptions, kNoTimeout) : await this._channel.newContext(contextOptions, kNoTimeout);
const context = BrowserContext.from(response.context);
if (forReuse)
context._forReuse = true;
@@ -132,12 +133,12 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
}
async bind(title: string, options: { workspaceDir?: string, metadata?: Record<string, any>, host?: string, port?: number } = {}): Promise<{ endpoint: string }> {
const { endpoint } = await this._channel.startServer({ title, ...options }, undefined);
const { endpoint } = await this._channel.startServer({ title, ...options }, kNoTimeout);
return { endpoint };
}
async unbind(): Promise<void> {
await this._channel.stopServer({}, undefined);
await this._channel.stopServer({}, kNoTimeout);
}
async newPage(options: BrowserContextOptions = {}): Promise<Page> {
@@ -155,16 +156,16 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
}
async newBrowserCDPSession(): Promise<api.CDPSession> {
return CDPSession.from((await this._channel.newBrowserCDPSession({}, undefined)).session);
return CDPSession.from((await this._channel.newBrowserCDPSession({}, kNoTimeout)).session);
}
async startTracing(page?: Page, options: { path?: string; screenshots?: boolean; categories?: string[]; } = {}) {
this._path = options.path;
await this._channel.startTracing({ ...options, page: page ? page._channel : undefined }, undefined);
await this._channel.startTracing({ ...options, page: page ? page._channel : undefined }, kNoTimeout);
}
async stopTracing(): Promise<Buffer> {
const artifact = Artifact.from((await this._channel.stopTracing({}, undefined)).artifact);
const artifact = Artifact.from((await this._channel.stopTracing({}, kNoTimeout)).artifact);
const buffer = await artifact.readIntoBuffer();
await artifact.delete();
if (this._path) {
@@ -185,7 +186,7 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
if (this._shouldCloseConnectionOnClose)
this._connection.close();
else
await this._channel.close(options, undefined);
await this._channel.close(options, kNoTimeout);
await this._closedPromise;
} catch (e) {
if (isTargetClosedError(e))
@@ -43,10 +43,10 @@ import { Tracing } from './tracing';
import { Waiter } from './waiter';
import { WebError } from './webError';
import { Worker } from './worker';
import { TimeoutSettings } from './timeoutSettings';
import { TimeoutSettings, kNoTimeout } from './timeoutSettings';
import { mkdirIfNeeded } from './fileUtils';
import type { BrowserContextOptions, Headers, SetStorageState, StorageState, TimeoutOptions, WaitForEventOptions } from './types';
import type { BrowserContextOptions, Headers, SetStorageState, StorageState, WaitForEventOptions } from './types';
import type * as structs from '../../types/structs';
import type * as api from '../../types/types';
import type { URLMatch } from '@isomorphic/urlMatch';
@@ -149,9 +149,9 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
// a) removing "dialog" listener subscription (client->server)
// b) actual "dialog" event (server->client)
if (dialogObject.type() === 'beforeunload')
dialog.accept({}, undefined).catch(() => {});
dialog.accept({}, kNoTimeout).catch(() => {});
else
dialog.dismiss({}, undefined).catch(() => {});
dialog.dismiss({}, kNoTimeout).catch(() => {});
}
});
this._channel.on('request', ({ request, page }) => this._onRequest(network.Request.from(request), Page.fromNullable(page)));
@@ -304,7 +304,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
async newPage(): Promise<Page> {
if (this._ownerPage)
throw new Error('Please use browser.newContext()');
return Page.from((await this._channel.newPage({}, undefined)).page);
return Page.from((await this._channel.newPage({}, kNoTimeout)).page);
}
async cookies(urls?: string | string[]): Promise<network.NetworkCookie[]> {
@@ -312,11 +312,11 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
urls = [];
if (urls && typeof urls === 'string')
urls = [urls];
return (await this._channel.cookies({ urls: urls as string[] }, undefined)).cookies;
return (await this._channel.cookies({ urls: urls as string[] }, kNoTimeout)).cookies;
}
async addCookies(cookies: network.SetNetworkCookieParam[]): Promise<void> {
await this._channel.addCookies({ cookies }, undefined);
await this._channel.addCookies({ cookies }, kNoTimeout);
}
async clearCookies(options: network.ClearNetworkCookieOptions = {}): Promise<void> {
@@ -330,47 +330,47 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
path: isString(options.path) ? options.path : undefined,
pathRegexSource: isRegExp(options.path) ? options.path.source : undefined,
pathRegexFlags: isRegExp(options.path) ? options.path.flags : undefined,
}, undefined);
}, kNoTimeout);
}
async grantPermissions(permissions: string[], options?: { origin?: string }): Promise<void> {
await this._channel.grantPermissions({ permissions, ...options }, undefined);
await this._channel.grantPermissions({ permissions, ...options }, kNoTimeout);
}
async clearPermissions(): Promise<void> {
await this._channel.clearPermissions({}, undefined);
await this._channel.clearPermissions({}, kNoTimeout);
}
async setGeolocation(geolocation: { longitude: number, latitude: number, accuracy?: number } | null): Promise<void> {
await this._channel.setGeolocation({ geolocation: geolocation || undefined }, undefined);
await this._channel.setGeolocation({ geolocation: geolocation || undefined }, kNoTimeout);
}
async setExtraHTTPHeaders(headers: Headers): Promise<void> {
network.validateHeaders(headers);
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) }, undefined);
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) }, kNoTimeout);
}
async setOffline(offline: boolean): Promise<void> {
await this._channel.setOffline({ offline }, undefined);
await this._channel.setOffline({ offline }, kNoTimeout);
}
async setHTTPCredentials(httpCredentials: { username: string, password: string } | null): Promise<void> {
await this._channel.setHTTPCredentials({ httpCredentials: httpCredentials || undefined }, undefined);
await this._channel.setHTTPCredentials({ httpCredentials: httpCredentials || undefined }, kNoTimeout);
}
async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any) {
const source = await evaluationScript(script, arg);
return DisposableObject.from((await this._channel.addInitScript({ source }, undefined)).disposable);
return DisposableObject.from((await this._channel.addInitScript({ source }, kNoTimeout)).disposable);
}
async exposeBinding(name: string, callback: (source: structs.BindingSource, ...args: any[]) => any): Promise<DisposableObject> {
const result = await this._channel.exposeBinding({ name }, undefined);
const result = await this._channel.exposeBinding({ name }, kNoTimeout);
this._bindings.set(name, callback);
return DisposableObject.from(result.disposable);
}
async exposeFunction(name: string, callback: Function): Promise<DisposableObject> {
const result = await this._channel.exposeBinding({ name }, undefined);
const result = await this._channel.exposeBinding({ name }, kNoTimeout);
const binding = (source: structs.BindingSource, ...args: any[]) => callback(...args);
this._bindings.set(name, binding);
return DisposableObject.from(result.disposable);
@@ -435,12 +435,12 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
private async _updateInterceptionPatterns(options: { internal: true } | { title: string }) {
const patterns = network.RouteHandler.prepareInterceptionPatterns(this._routes);
await this._wrapApiCall(() => this._channel.setNetworkInterceptionPatterns({ patterns }, undefined), options);
await this._wrapApiCall(() => this._channel.setNetworkInterceptionPatterns({ patterns }, kNoTimeout), options);
}
private async _updateWebSocketInterceptionPatterns(options: { internal: true } | { title: string }) {
const patterns = network.WebSocketRouteHandler.prepareInterceptionPatterns(this._webSocketRoutes);
await this._wrapApiCall(() => this._channel.setWebSocketInterceptionPatterns({ patterns }, undefined), options);
await this._wrapApiCall(() => this._channel.setWebSocketInterceptionPatterns({ patterns }, kNoTimeout), options);
}
_effectiveCloseReason(): string | undefined {
@@ -449,9 +449,8 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
return await this._wrapApiCall(async () => {
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const { timeout, signal } = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const signal = typeof optionsOrPredicate === 'function' ? undefined : (optionsOrPredicate as TimeoutOptions).signal;
const waiter = Waiter.createForEvent(this, event);
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
waiter.rejectOnSignal(signal);
@@ -464,7 +463,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
}
async storageState(options: { path?: string, indexedDB?: boolean, credentials?: boolean } = {}): Promise<StorageState> {
const state = await this._channel.storageState({ indexedDB: options.indexedDB, credentials: options.credentials }, undefined);
const state = await this._channel.storageState({ indexedDB: options.indexedDB, credentials: options.credentials }, kNoTimeout);
if (options.path) {
await mkdirIfNeeded(options.path);
await fs.promises.writeFile(options.path, JSON.stringify(state, undefined, 2), 'utf8');
@@ -474,7 +473,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
async setStorageState(storageState: string | SetStorageState): Promise<void> {
const state = await prepareStorageState(storageState);
await this._channel.setStorageState({ storageState: state }, undefined);
await this._channel.setStorageState({ storageState: state }, kNoTimeout);
}
backgroundPages(): Page[] {
@@ -489,7 +488,7 @@ 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');
const result = await this._channel.newCDPSession(page instanceof Page ? { page: page._channel } : { frame: page._channel }, undefined);
const result = await this._channel.newCDPSession(page instanceof Page ? { page: page._channel } : { frame: page._channel }, kNoTimeout);
return CDPSession.from(result.session);
}
@@ -515,23 +514,23 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
await this.request.dispose(options);
await this._instrumentation.runBeforeCloseBrowserContext(this);
await this.tracing._exportAllHars();
await this._channel.close(options, undefined);
await this._channel.close(options, kNoTimeout);
await this._closedPromise;
}
async _enableRecorder(params: channels.BrowserContextEnableRecorderParams, eventSink?: RecorderEventSink) {
if (eventSink)
this._onRecorderEventSink = eventSink;
await this._channel.enableRecorder(params, undefined);
await this._channel.enableRecorder(params, kNoTimeout);
}
async _disableRecorder() {
this._onRecorderEventSink = undefined;
await this._channel.disableRecorder({}, undefined);
await this._channel.disableRecorder({}, kNoTimeout);
}
async _exposeConsoleApi() {
await this._channel.exposeConsoleApi({}, undefined);
await this._channel.exposeConsoleApi({}, kNoTimeout);
}
}
@@ -74,10 +74,9 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
env: options.env ? envObjectToArray(options.env) : undefined,
timeout: new TimeoutSettings().launchTimeout(options),
};
return await this._wrapApiCall(async () => {
const browser = Browser.from((await this._channel.launch(launchOptions, options.signal)).browser);
const browser = Browser.from((await this._channel.launch(launchOptions, new TimeoutSettings().launchTimeout(options))).browser);
browser._connectToBrowserType(this, options, logger);
return browser;
});
@@ -107,10 +106,9 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
env: options.env ? envObjectToArray(options.env) : undefined,
channel: options.channel,
userDataDir: (path.isAbsolute(userDataDir) || !userDataDir) ? userDataDir : path.resolve(userDataDir),
timeout: new TimeoutSettings().launchTimeout(options),
};
const context = await this._wrapApiCall(async () => {
const result = await this._channel.launchPersistentContext(persistentParams, options.signal);
const result = await this._channel.launchPersistentContext(persistentParams, new TimeoutSettings().launchTimeout(options));
const browser = Browser.from(result.browser);
browser._connectToBrowserType(this, options, logger);
const context = BrowserContext.from(result.context);
@@ -168,11 +166,10 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
transport: transport as any,
headers: params.headers ? headersObjectToArray(params.headers) : undefined,
slowMo: params.slowMo,
timeout: new TimeoutSettings().timeout(params),
isLocal: params.isLocal,
noDefaults: params.noDefaults,
artifactsDir: params.artifactsDir,
}, undefined);
}, new TimeoutSettings().timeout(params));
return await this._browserFromConnectResult(result);
}
@@ -189,8 +186,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
throw new Error('Connecting to workers is only supported in Chromium.');
const result = await this._channel.connectToWorker({
endpoint,
timeout: new TimeoutSettings().timeout(options),
}, undefined);
}, new TimeoutSettings().timeout(options));
return Worker.from(result.worker);
}
}
@@ -15,6 +15,7 @@
*/
import { ChannelOwner } from './channelOwner';
import { kNoTimeout } from './timeoutSettings';
import type * as api from '../../types/types';
import type { Protocol } from '../server/chromium/protocol';
@@ -48,11 +49,11 @@ export class CDPSession extends ChannelOwner<channels.CDPSessionChannel> impleme
method: T,
params?: Protocol.CommandParameters[T]
): Promise<Protocol.CommandReturnValues[T]> {
const result = await this._channel.send({ method, params }, undefined);
const result = await this._channel.send({ method, params }, kNoTimeout);
return result.result as Protocol.CommandReturnValues[T];
}
async detach() {
return await this._channel.detach({}, undefined);
return await this._channel.detach({}, kNoTimeout);
}
}
@@ -151,19 +151,20 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
const validator = maybeFindValidator(this._type, prop, 'Params');
const { internal } = getMetainfo({ type: this._type, method: prop }) || {};
if (validator) {
return async (params: any, signal: AbortSignal | undefined) => {
return async (params: any, options: { signal?: AbortSignal, timeout?: number } = {}) => {
return await this._wrapApiCall(async apiZone => {
const validatedParams = validator(params, '', this._validatorToWireContext());
const { signal, timeout = 0 } = options;
if (!apiZone.internal && !apiZone.reported) {
// Reporting/tracing/logging this api call for the first time.
apiZone.reported = true;
this._instrumentation.onApiCallBegin(apiZone, { type: this._type, method: prop, params });
logApiCall(this._logger, `=> ${apiZone.apiName} started`);
return await this._connection.sendMessageToServer(this, prop, validatedParams, { ...apiZone, signal });
return await this._connection.sendMessageToServer(this, prop, validatedParams, { ...apiZone, signal, timeout });
}
// Since this api call is either internal, or has already been reported/traced once,
// passing as internal.
return await this._connection.sendMessageToServer(this, prop, validatedParams, { internal: true, signal });
return await this._connection.sendMessageToServer(this, prop, validatedParams, { internal: true, signal, timeout });
}, { internal });
};
}
File diff suppressed because it is too large Load Diff
+8 -7
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { kNoTimeout } from './timeoutSettings';
import type { BrowserContext } from './browserContext';
import type * as api from '../../types/types';
@@ -25,31 +26,31 @@ export class Clock implements api.Clock {
}
async install(options: { time?: number | string | Date } = { }) {
await this._browserContext._channel.clockInstall({ ...(options.time !== undefined ? parseTime(options.time) : {}) }, undefined);
await this._browserContext._channel.clockInstall({ ...(options.time !== undefined ? parseTime(options.time) : {}) }, kNoTimeout);
}
async fastForward(ticks: number | string) {
await this._browserContext._channel.clockFastForward({ ...parseTicks(ticks) }, undefined);
await this._browserContext._channel.clockFastForward({ ...parseTicks(ticks) }, kNoTimeout);
}
async pauseAt(time: number | string | Date) {
await this._browserContext._channel.clockPauseAt({ ...parseTime(time) }, undefined);
await this._browserContext._channel.clockPauseAt({ ...parseTime(time) }, kNoTimeout);
}
async resume() {
await this._browserContext._channel.clockResume({}, undefined);
await this._browserContext._channel.clockResume({}, kNoTimeout);
}
async runFor(ticks: number | string) {
await this._browserContext._channel.clockRunFor({ ...parseTicks(ticks) }, undefined);
await this._browserContext._channel.clockRunFor({ ...parseTicks(ticks) }, kNoTimeout);
}
async setFixedTime(time: string | number | Date) {
await this._browserContext._channel.clockSetFixedTime({ ...parseTime(time) }, undefined);
await this._browserContext._channel.clockSetFixedTime({ ...parseTime(time) }, kNoTimeout);
}
async setSystemTime(time: string | number | Date) {
await this._browserContext._channel.clockSetSystemTime({ ...parseTime(time) }, undefined);
await this._browserContext._channel.clockSetSystemTime({ ...parseTime(time) }, kNoTimeout);
}
}
+10 -10
View File
@@ -20,6 +20,7 @@ import { Browser } from './browser';
import { ChannelOwner } from './channelOwner';
import { Connection } from './connection';
import { Events } from './events';
import { kNoTimeout } from './timeoutSettings';
import type { Playwright } from './playwright';
import type { ConnectOptions, HeadersArray } from './types';
@@ -34,11 +35,10 @@ export async function connectToBrowser(playwright: Playwright, params: ConnectOp
headers,
exposeNetwork: params.exposeNetwork,
slowMo: params.slowMo,
timeout: params.timeout || 0,
};
if ((params as any).__testHookRedirectPortForwarding)
connectParams.socksProxyRedirectPortForTest = (params as any).__testHookRedirectPortForwarding;
const connection = await connectToEndpoint(playwright._connection, connectParams);
const connection = await connectToEndpoint(playwright._connection, connectParams, { signal: undefined, timeout: params.timeout || 0 });
let browser: Browser;
connection.on('close', () => {
// Emulate all pages, contexts and the browser closing upon disconnect.
@@ -74,10 +74,10 @@ export async function connectToBrowser(playwright: Playwright, params: ConnectOp
}
}
export async function connectToEndpoint(parentConnection: Connection, params: channels.LocalUtilsConnectParams): Promise<Connection> {
export async function connectToEndpoint(parentConnection: Connection, params: channels.LocalUtilsConnectParams, timeout: channels.TimeoutOptions): Promise<Connection> {
const localUtils = parentConnection.localUtils();
const transport = localUtils ? new JsonPipeTransport(localUtils) : new WebSocketTransport();
const connectHeaders = await transport.connect(params);
const connectHeaders = await transport.connect(params, timeout);
const connection = new Connection(localUtils, parentConnection._instrumentation, connectHeaders);
connection.markAsRemote();
connection.on('close', () => transport.close());
@@ -100,7 +100,7 @@ export async function connectToEndpoint(parentConnection: Connection, params: ch
}
interface Transport {
connect(params: channels.LocalUtilsConnectParams): Promise<HeadersArray>;
connect(params: channels.LocalUtilsConnectParams, timeout: channels.TimeoutOptions): Promise<HeadersArray>;
send(message: any): Promise<void>;
onMessage(callback: (message: object) => void): void;
onClose(callback: (reason?: string) => void): void;
@@ -115,14 +115,14 @@ class JsonPipeTransport implements Transport {
this._owner = owner;
}
async connect(params: channels.LocalUtilsConnectParams) {
const { pipe, headers: connectHeaders } = await this._owner._channel.connect(params, undefined);
async connect(params: channels.LocalUtilsConnectParams, timeout: channels.TimeoutOptions) {
const { pipe, headers: connectHeaders } = await this._owner._channel.connect(params, timeout);
this._pipe = pipe;
return connectHeaders;
}
async send(message: object) {
await this._pipe!.send({ message }, undefined);
await this._pipe!.send({ message }, kNoTimeout);
}
onMessage(callback: (message: object) => void) {
@@ -134,14 +134,14 @@ class JsonPipeTransport implements Transport {
}
async close() {
await this._pipe!.close({}, undefined).catch(() => {});
await this._pipe!.close({}, kNoTimeout).catch(() => {});
}
}
class WebSocketTransport implements Transport {
private _ws: WebSocket | undefined;
async connect(params: channels.LocalUtilsConnectParams) {
async connect(params: channels.LocalUtilsConnectParams, timeout: channels.TimeoutOptions) {
this._ws = new window.WebSocket(params.endpoint);
return [];
}
@@ -47,6 +47,7 @@ import { Stream } from './stream';
import { Tracing } from './tracing';
import { Worker } from './worker';
import { WritableStream } from './writableStream';
import { kNoTimeout } from './timeoutSettings';
import type { ClientInstrumentation } from './clientInstrumentation';
import type { HeadersArray } from './types';
import type { ValidatorContext } from '@protocol/validator';
@@ -60,7 +61,7 @@ class Root extends ChannelOwner<channels.RootChannel> {
async initialize(): Promise<Playwright> {
return Playwright.from((await this._channel.initialize({
sdkLanguage: 'javascript',
}, undefined)).playwright);
}, kNoTimeout)).playwright);
}
}
@@ -174,7 +175,7 @@ export class Connection extends EventEmitter {
this._tracingCount--;
}
async sendMessageToServer(object: ChannelOwner, method: string, params: any, options: { apiName?: string, title?: string, internal?: boolean, frames?: channels.StackFrame[], stepId?: string, signal?: AbortSignal }): Promise<any> {
async sendMessageToServer(object: ChannelOwner, method: string, params: any, options: { apiName?: string, title?: string, internal?: boolean, frames?: channels.StackFrame[], stepId?: string, signal?: AbortSignal, timeout: number }): Promise<any> {
// Fire-and-forget: server intentionally never replies to __waitInfo__,
// so silently drop it after the connection is closed or the object was collected.
if (method === '__waitInfo__' && (this._closedError || object._wasCollected))
@@ -197,7 +198,7 @@ export class Connection extends EventEmitter {
debugLogger.log('channel', 'SEND> ' + JSON.stringify(message));
}
const location = options.frames?.[0] ? { file: options.frames[0].file, line: options.frames[0].line, column: options.frames[0].column } : undefined;
const metadata: channels.Metadata = { title: options.title, location, internal: options.internal, stepId: options.stepId };
const metadata: channels.Metadata = { title: options.title, location, internal: options.internal, stepId: options.stepId, timeout: options.timeout };
if (this._tracingCount && options.frames && type !== 'LocalUtils')
this._localUtils?.addStackToTracingNoReply({ callData: { stack: options.frames ?? [], id } }).catch(() => {});
// We need to exit zones before calling into the server, otherwise
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { kNoTimeout } from './timeoutSettings';
import type * as api from '../../types/types';
import type * as channels from './channels';
@@ -25,18 +26,18 @@ export class Coverage implements api.Coverage {
}
async startJSCoverage(options: channels.PageStartJSCoverageOptions = {}) {
await this._channel.startJSCoverage(options, undefined);
await this._channel.startJSCoverage(options, kNoTimeout);
}
async stopJSCoverage(): Promise<channels.PageStopJSCoverageResult['entries']> {
return (await this._channel.stopJSCoverage({}, undefined)).entries;
return (await this._channel.stopJSCoverage({}, kNoTimeout)).entries;
}
async startCSSCoverage(options: channels.PageStartCSSCoverageOptions = {}) {
await this._channel.startCSSCoverage(options, undefined);
await this._channel.startCSSCoverage(options, kNoTimeout);
}
async stopCSSCoverage(): Promise<channels.PageStopCSSCoverageResult['entries']> {
return (await this._channel.stopCSSCoverage({}, undefined)).entries;
return (await this._channel.stopCSSCoverage({}, kNoTimeout)).entries;
}
}
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { kNoTimeout } from './timeoutSettings';
import type { BrowserContext } from './browserContext';
import type * as api from '../../types/types';
import type * as channels from './channels';
@@ -26,20 +27,20 @@ export class Credentials implements api.Credentials {
}
async install(): Promise<void> {
await this._browserContext._channel.credentialsInstall({}, undefined);
await this._browserContext._channel.credentialsInstall({}, kNoTimeout);
}
async create(rpId: string, options: Omit<channels.BrowserContextCredentialsCreateParams, 'rpId'> = {}): Promise<channels.VirtualCredential> {
const { credential } = await this._browserContext._channel.credentialsCreate({ ...options, rpId }, undefined);
const { credential } = await this._browserContext._channel.credentialsCreate({ ...options, rpId }, kNoTimeout);
return credential;
}
async get(options: channels.BrowserContextCredentialsGetParams = {}): Promise<channels.VirtualCredential[]> {
const { credentials } = await this._browserContext._channel.credentialsGet(options, undefined);
const { credentials } = await this._browserContext._channel.credentialsGet(options, kNoTimeout);
return credentials;
}
async delete(id: string): Promise<void> {
await this._browserContext._channel.credentialsDelete({ id }, undefined);
await this._browserContext._channel.credentialsDelete({ id }, kNoTimeout);
}
}
@@ -16,6 +16,7 @@
import { ChannelOwner } from './channelOwner';
import { Events } from './events';
import { kNoTimeout } from './timeoutSettings';
import type * as api from '../../types/types';
import type * as channels from './channels';
@@ -38,19 +39,19 @@ export class Debugger extends ChannelOwner<channels.DebuggerChannel> implements
}
async requestPause(): Promise<void> {
await this._channel.requestPause({}, undefined);
await this._channel.requestPause({}, kNoTimeout);
}
async resume(): Promise<void> {
await this._channel.resume({}, undefined);
await this._channel.resume({}, kNoTimeout);
}
async next(): Promise<void> {
await this._channel.next({}, undefined);
await this._channel.next({}, kNoTimeout);
}
async runTo(location: { file: string, line?: number, column?: number }): Promise<void> {
await this._channel.runTo({ location }, undefined);
await this._channel.runTo({ location }, kNoTimeout);
}
pausedDetails(): PausedDetails | null {
@@ -17,6 +17,7 @@
import { ChannelOwner } from './channelOwner';
import { Page } from './page';
import { isTargetClosedError } from './errors';
import { kNoTimeout } from './timeoutSettings';
import type * as api from '../../types/types';
import type * as channels from './channels';
@@ -53,12 +54,12 @@ export class Dialog extends ChannelOwner<channels.DialogChannel> implements api.
}
async accept(promptText: string | undefined) {
await this._channel.accept({ promptText }, undefined);
await this._channel.accept({ promptText }, kNoTimeout);
}
async dismiss() {
try {
await this._channel.dismiss({}, undefined);
await this._channel.dismiss({}, kNoTimeout);
} catch (e) {
if (isTargetClosedError(e))
return;
@@ -16,6 +16,7 @@
import { ChannelOwner } from './channelOwner';
import { isTargetClosedError } from './errors';
import { kNoTimeout } from './timeoutSettings';
import type * as channels from './channels';
@@ -34,7 +35,7 @@ export class DisposableObject<T extends channels.DisposableChannel = channels.Di
async dispose() {
try {
await this._channel.dispose({}, undefined);
await this._channel.dispose({}, kNoTimeout);
} catch (e) {
if (isTargetClosedError(e))
return;
@@ -22,7 +22,7 @@ import { TargetClosedError, isTargetClosedError } from './errors';
import { Events } from './events';
import { JSHandle, parseResult, serializeArgument } from './jsHandle';
import { Waiter } from './waiter';
import { TimeoutSettings } from './timeoutSettings';
import { TimeoutSettings, kNoTimeout } from './timeoutSettings';
import type { Page } from './page';
import type { BrowserContextOptions, Headers, TimeoutOptions, WaitForEventOptions } from './types';
@@ -62,9 +62,8 @@ export class Electron extends ChannelOwner<channels.ElectronChannel> implements
env: options.env ? envObjectToArray(options.env) : undefined,
tracesDir: options.tracesDir,
artifactsDir: options.artifactsDir,
timeout: new TimeoutSettings().launchTimeout(options),
};
const app = ElectronApplication.from((await this._channel.launch(params, undefined)).electronApplication);
const app = ElectronApplication.from((await this._channel.launch(params, new TimeoutSettings().launchTimeout(options))).electronApplication);
this._playwright.selectors._contextsForSelectors.add(app._context);
app.once(Events.ElectronApplication.Close, () => this._playwright.selectors._contextsForSelectors.delete(app._context));
await app._context._initializeHarFromOptions(options.recordHar);
@@ -140,9 +139,8 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
return await this._wrapApiCall(async () => {
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const { timeout, signal } = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const signal = typeof optionsOrPredicate === 'function' ? undefined : (optionsOrPredicate as TimeoutOptions).signal;
const waiter = Waiter.createForEvent(this, event);
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
waiter.rejectOnSignal(signal);
@@ -155,17 +153,17 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
}
async browserWindow(page: Page): Promise<JSHandle<BrowserWindow>> {
const result = await this._channel.browserWindow({ page: page._channel }, undefined);
const result = await this._channel.browserWindow({ page: page._channel }, kNoTimeout);
return JSHandle.from(result.handle);
}
async evaluate<R, Arg>(pageFunction: structs.PageFunctionOn<ElectronAppType, Arg, R>, arg: Arg): Promise<R> {
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return parseResult(result.value);
}
async evaluateHandle<R, Arg>(pageFunction: structs.PageFunctionOn<ElectronAppType, Arg, R>, arg: Arg): Promise<structs.SmartHandle<R>> {
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
}
}
@@ -25,6 +25,7 @@ import { Frame } from './frame';
import { JSHandle, parseResult, serializeArgument } from './jsHandle';
import { fileUploadSizeLimit, mkdirIfNeeded } from './fileUtils';
import { WritableStream } from './writableStream';
import { kNoTimeout } from './timeoutSettings';
import type { BrowserContext } from './browserContext';
import type { ChannelOwner } from './channelOwner';
@@ -57,94 +58,94 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
}
async ownerFrame(): Promise<Frame | null> {
return Frame.fromNullable((await this._elementChannel.ownerFrame({}, undefined)).frame);
return Frame.fromNullable((await this._elementChannel.ownerFrame({}, kNoTimeout)).frame);
}
async contentFrame(): Promise<Frame | null> {
return Frame.fromNullable((await this._elementChannel.contentFrame({}, undefined)).frame);
return Frame.fromNullable((await this._elementChannel.contentFrame({}, kNoTimeout)).frame);
}
async getAttribute(name: string): Promise<string | null> {
const value = (await this._elementChannel.getAttribute({ name }, undefined)).value;
const value = (await this._elementChannel.getAttribute({ name }, kNoTimeout)).value;
return value === undefined ? null : value;
}
async inputValue(): Promise<string> {
return (await this._elementChannel.inputValue({}, undefined)).value;
return (await this._elementChannel.inputValue({}, kNoTimeout)).value;
}
async textContent(): Promise<string | null> {
const value = (await this._elementChannel.textContent({}, undefined)).value;
const value = (await this._elementChannel.textContent({}, kNoTimeout)).value;
return value === undefined ? null : value;
}
async innerText(): Promise<string> {
return (await this._elementChannel.innerText({}, undefined)).value;
return (await this._elementChannel.innerText({}, kNoTimeout)).value;
}
async innerHTML(): Promise<string> {
return (await this._elementChannel.innerHTML({}, undefined)).value;
return (await this._elementChannel.innerHTML({}, kNoTimeout)).value;
}
async isChecked(): Promise<boolean> {
return (await this._elementChannel.isChecked({}, undefined)).value;
return (await this._elementChannel.isChecked({}, kNoTimeout)).value;
}
async isDisabled(): Promise<boolean> {
return (await this._elementChannel.isDisabled({}, undefined)).value;
return (await this._elementChannel.isDisabled({}, kNoTimeout)).value;
}
async isEditable(): Promise<boolean> {
return (await this._elementChannel.isEditable({}, undefined)).value;
return (await this._elementChannel.isEditable({}, kNoTimeout)).value;
}
async isEnabled(): Promise<boolean> {
return (await this._elementChannel.isEnabled({}, undefined)).value;
return (await this._elementChannel.isEnabled({}, kNoTimeout)).value;
}
async isHidden(): Promise<boolean> {
return (await this._elementChannel.isHidden({}, undefined)).value;
return (await this._elementChannel.isHidden({}, kNoTimeout)).value;
}
async isVisible(): Promise<boolean> {
return (await this._elementChannel.isVisible({}, undefined)).value;
return (await this._elementChannel.isVisible({}, kNoTimeout)).value;
}
async dispatchEvent(type: string, eventInit: Object = {}) {
await this._elementChannel.dispatchEvent({ type, eventInit: serializeArgument(eventInit) }, undefined);
await this._elementChannel.dispatchEvent({ type, eventInit: serializeArgument(eventInit) }, kNoTimeout);
}
async scrollIntoViewIfNeeded(options: channels.ElementHandleScrollIntoViewIfNeededOptions & TimeoutOptions = {}) {
await this._elementChannel.scrollIntoViewIfNeeded({ ...options, timeout: this._frame._timeout(options) }, options.signal);
await this._elementChannel.scrollIntoViewIfNeeded({ ...options }, this._frame._timeout(options));
}
async hover(options: channels.ElementHandleHoverOptions & TimeoutOptions = {}): Promise<void> {
await this._elementChannel.hover({ ...options, timeout: this._frame._timeout(options) }, options.signal);
await this._elementChannel.hover({ ...options }, this._frame._timeout(options));
}
async click(options: channels.ElementHandleClickOptions & TimeoutOptions = {}): Promise<void> {
return await this._elementChannel.click({ ...options, timeout: this._frame._timeout(options) }, options.signal);
return await this._elementChannel.click({ ...options }, this._frame._timeout(options));
}
async dblclick(options: channels.ElementHandleDblclickOptions & TimeoutOptions = {}): Promise<void> {
return await this._elementChannel.dblclick({ ...options, timeout: this._frame._timeout(options) }, options.signal);
return await this._elementChannel.dblclick({ ...options }, this._frame._timeout(options));
}
async tap(options: channels.ElementHandleTapOptions & TimeoutOptions = {}): Promise<void> {
return await this._elementChannel.tap({ ...options, timeout: this._frame._timeout(options) }, options.signal);
return await this._elementChannel.tap({ ...options }, this._frame._timeout(options));
}
async selectOption(values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> {
const result = await this._elementChannel.selectOption({ ...convertSelectOptionValues(values), ...options, timeout: this._frame._timeout(options) }, options.signal);
const result = await this._elementChannel.selectOption({ ...convertSelectOptionValues(values), ...options }, this._frame._timeout(options));
return result.values;
}
async fill(value: string, options: channels.ElementHandleFillOptions & TimeoutOptions = {}): Promise<void> {
return await this._elementChannel.fill({ value, ...options, timeout: this._frame._timeout(options) }, options.signal);
return await this._elementChannel.fill({ value, ...options }, this._frame._timeout(options));
}
async selectText(options: channels.ElementHandleSelectTextOptions & TimeoutOptions = {}): Promise<void> {
await this._elementChannel.selectText({ ...options, timeout: this._frame._timeout(options) }, options.signal);
await this._elementChannel.selectText({ ...options }, this._frame._timeout(options));
}
async setInputFiles(files: string | FilePayload | string[] | FilePayload[], options: channels.ElementHandleSetInputFilesOptions & TimeoutOptions = {}) {
@@ -152,27 +153,27 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
if (!frame)
throw new Error('Cannot set input files to detached element');
const converted = await convertInputFiles(files, frame.page().context());
await this._elementChannel.setInputFiles({ ...converted, ...options, timeout: this._frame._timeout(options) }, options.signal);
await this._elementChannel.setInputFiles({ ...converted, ...options }, this._frame._timeout(options));
}
async focus(): Promise<void> {
await this._elementChannel.focus({}, undefined);
await this._elementChannel.focus({}, kNoTimeout);
}
async type(text: string, options: channels.ElementHandleTypeOptions & TimeoutOptions = {}): Promise<void> {
await this._elementChannel.type({ text, ...options, timeout: this._frame._timeout(options) }, options.signal);
await this._elementChannel.type({ text, ...options }, this._frame._timeout(options));
}
async press(key: string, options: channels.ElementHandlePressOptions & TimeoutOptions = {}): Promise<void> {
await this._elementChannel.press({ key, ...options, timeout: this._frame._timeout(options) }, options.signal);
await this._elementChannel.press({ key, ...options }, this._frame._timeout(options));
}
async check(options: channels.ElementHandleCheckOptions & TimeoutOptions = {}) {
return await this._elementChannel.check({ ...options, timeout: this._frame._timeout(options) }, options.signal);
return await this._elementChannel.check({ ...options }, this._frame._timeout(options));
}
async uncheck(options: channels.ElementHandleUncheckOptions & TimeoutOptions = {}) {
return await this._elementChannel.uncheck({ ...options, timeout: this._frame._timeout(options) }, options.signal);
return await this._elementChannel.uncheck({ ...options }, this._frame._timeout(options));
}
async setChecked(checked: boolean, options?: channels.ElementHandleCheckOptions) {
@@ -183,13 +184,13 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
}
async boundingBox(): Promise<Rect | null> {
const value = (await this._elementChannel.boundingBox({}, undefined)).value;
const value = (await this._elementChannel.boundingBox({}, kNoTimeout)).value;
return value === undefined ? null : value;
}
async screenshot(options: Omit<channels.ElementHandleScreenshotOptions, 'mask'> & TimeoutOptions & { path?: string, mask?: api.Locator[] } = {}): Promise<Buffer> {
const mask = options.mask as Locator[] | undefined;
const copy: channels.ElementHandleScreenshotParams = { ...options, mask: undefined, timeout: this._frame._timeout(options) };
const copy: channels.ElementHandleScreenshotParams = { ...options, mask: undefined };
if (!copy.type)
copy.type = determineScreenshotType(options);
if (mask) {
@@ -198,7 +199,7 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
selector: locator._selector,
}));
}
const result = await this._elementChannel.screenshot(copy, options.signal);
const result = await this._elementChannel.screenshot(copy, this._frame._timeout(options));
if (options.path) {
await mkdirIfNeeded(options.path);
await fs.promises.writeFile(options.path, result.binary);
@@ -207,32 +208,32 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
}
async $(selector: string): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
return ElementHandle.fromNullable((await this._elementChannel.querySelector({ selector }, undefined)).element) as ElementHandle<SVGElement | HTMLElement> | null;
return ElementHandle.fromNullable((await this._elementChannel.querySelector({ selector }, kNoTimeout)).element) as ElementHandle<SVGElement | HTMLElement> | null;
}
async $$(selector: string): Promise<ElementHandle<SVGElement | HTMLElement>[]> {
const result = await this._elementChannel.querySelectorAll({ selector }, undefined);
const result = await this._elementChannel.querySelectorAll({ selector }, kNoTimeout);
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> {
const result = await this._elementChannel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._elementChannel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return parseResult(result.value);
}
async $$eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element[], Arg, R>, arg?: Arg): Promise<R> {
const result = await this._elementChannel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._elementChannel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return parseResult(result.value);
}
async waitForElementState(state: 'visible' | 'hidden' | 'stable' | 'enabled' | 'disabled', options: TimeoutOptions = {}): Promise<void> {
return await this._elementChannel.waitForElementState({ state, ...options, timeout: this._frame._timeout(options) }, options.signal);
return await this._elementChannel.waitForElementState({ state, ...options }, this._frame._timeout(options));
}
waitForSelector(selector: string, options: channels.ElementHandleWaitForSelectorOptions & TimeoutOptions & { state: 'attached' | 'visible' }): Promise<ElementHandle<SVGElement | HTMLElement>>;
waitForSelector(selector: string, options?: channels.ElementHandleWaitForSelectorOptions & TimeoutOptions): Promise<ElementHandle<SVGElement | HTMLElement> | null>;
async waitForSelector(selector: string, options: channels.ElementHandleWaitForSelectorOptions & TimeoutOptions = {}): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
const result = await this._elementChannel.waitForSelector({ selector, ...options, timeout: this._frame._timeout(options) }, options.signal);
const result = await this._elementChannel.waitForSelector({ selector, ...options }, this._frame._timeout(options));
return ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
}
}
@@ -298,7 +299,7 @@ export async function convertInputFiles(files: string | FilePayload | string[] |
lastModifiedMs
};
})),
}, undefined), { internal: true });
}, kNoTimeout), { internal: true });
for (let i = 0; i < files.length; i++) {
const writable = WritableStream.from(writableStreams[i]);
await stream.promises.pipeline(fs.createReadStream(files[i]), writable.stream());
+8 -9
View File
@@ -27,7 +27,7 @@ import { TargetClosedError, isTargetClosedError } from './errors';
import { RawHeaders } from './network';
import { Tracing } from './tracing';
import { mkdirIfNeeded } from './fileUtils';
import { TimeoutSettings } from './timeoutSettings';
import { TimeoutSettings, kNoTimeout } from './timeoutSettings';
import type { Playwright } from './playwright';
import type { ClientCertificate, FilePayload, Headers, RemoteAddr, SecurityDetails, SetStorageState, StorageState, TimeoutOptions } from './types';
@@ -79,7 +79,7 @@ export class APIRequest implements api.APIRequest {
storageState,
tracesDir: this._playwright._defaultLaunchOptions?.tracesDir, // We do not expose tracesDir in the API, so do not allow options to accidentally override it.
clientCertificates: await toClientCertificatesProtocol(options.clientCertificates),
}, options.signal)).request);
}, kNoTimeout)).request);
this._contexts.add(context);
context._request = this;
context._timeoutSettings.setDefaultTimeout(options.timeout ?? this._playwright._defaultContextTimeout);
@@ -114,7 +114,7 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
await this._instrumentation.runBeforeCloseRequestContext(this);
await this.tracing._exportAllHars();
try {
await this._channel.dispose(options, undefined);
await this._channel.dispose(options, kNoTimeout);
} catch (e) {
if (isTargetClosedError(e))
return;
@@ -255,19 +255,18 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
jsonData,
formData,
multipartData,
timeout: this._timeoutSettings.timeout(options),
failOnStatusCode: options.failOnStatusCode,
ignoreHTTPSErrors: options.ignoreHTTPSErrors,
maxRedirects: options.maxRedirects,
maxRetries: options.maxRetries,
...fixtures
}, options.signal);
}, this._timeoutSettings.timeout(options));
return new APIResponse(this, result.response);
});
}
async storageState(options: { path?: string, indexedDB?: boolean } = {}): Promise<StorageState> {
const state = await this._channel.storageState({ indexedDB: options.indexedDB }, undefined);
const state = await this._channel.storageState({ indexedDB: options.indexedDB }, kNoTimeout);
if (options.path) {
await mkdirIfNeeded(options.path);
await fs.promises.writeFile(options.path, JSON.stringify(state, undefined, 2), 'utf8');
@@ -354,7 +353,7 @@ export class APIResponse implements api.APIResponse {
async body(): Promise<Buffer> {
return await this._request._wrapApiCall(async () => {
try {
const result = await this._request._channel.fetchResponseBody({ fetchUid: this._fetchUid() }, undefined);
const result = await this._request._channel.fetchResponseBody({ fetchUid: this._fetchUid() }, kNoTimeout);
if (result.binary === undefined)
throw new Error('Response has been disposed');
return result.binary;
@@ -381,7 +380,7 @@ export class APIResponse implements api.APIResponse {
}
async dispose(): Promise<void> {
await this._request._channel.disposeAPIResponse({ fetchUid: this._fetchUid() }, undefined);
await this._request._channel.disposeAPIResponse({ fetchUid: this._fetchUid() }, kNoTimeout);
}
private _inspect() {
@@ -394,7 +393,7 @@ export class APIResponse implements api.APIResponse {
}
async _fetchLog(): Promise<string[]> {
const { log } = await this._request._channel.fetchLog({ fetchUid: this._fetchUid() }, undefined);
const { log } = await this._request._channel.fetchLog({ fetchUid: this._fetchUid() }, kNoTimeout);
return log;
}
}
+55 -56
View File
@@ -32,7 +32,7 @@ import { FrameLocator, Locator, testIdAttributeName } from './locator';
import * as network from './network';
import { kLifecycleEvents } from './types';
import { Waiter } from './waiter';
import { TimeoutSettings } from './timeoutSettings';
import { TimeoutSettings, kNoTimeout } from './timeoutSettings';
import type { LocatorOptions } from './locator';
import type { Page } from './page';
@@ -107,19 +107,19 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
return this._page!;
}
_timeout(options?: TimeoutOptions): number {
_timeout(options?: TimeoutOptions): channels.TimeoutOptions {
const timeoutSettings = this._page?._timeoutSettings || new TimeoutSettings();
return timeoutSettings.timeout(options || {});
}
_navigationTimeout(options?: TimeoutOptions): number {
_navigationTimeout(options?: TimeoutOptions): channels.TimeoutOptions {
const timeoutSettings = this._page?._timeoutSettings || new TimeoutSettings();
return timeoutSettings.navigationTimeout(options || {});
}
async goto(url: string, options: channels.FrameGotoOptions & TimeoutOptions = {}): Promise<network.Response | null> {
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
return network.Response.fromNullable((await this._channel.goto({ url, ...options, waitUntil, timeout: this._navigationTimeout(options) }, options.signal)).response);
return network.Response.fromNullable((await this._channel.goto({ url, ...options, waitUntil }, this._navigationTimeout(options))).response);
}
private _setupNavigationWaiter(options: TimeoutOptions): Waiter {
@@ -129,7 +129,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
waiter.rejectOnEvent(this._page!, Events.Page.Close, () => this._page!._closeErrorWithReason());
waiter.rejectOnEvent(this._page!, Events.Page.Crash, new Error('Navigation failed because page crashed!'));
waiter.rejectOnEvent<Frame>(this._page!, Events.Page.FrameDetached, new Error('Navigating frame was detached!'), frame => frame === this);
const timeout = this._page!._timeoutSettings.navigationTimeout(options);
const { timeout } = this._page!._timeoutSettings.navigationTimeout(options);
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded.`);
waiter.rejectOnSignal(options.signal);
return waiter;
@@ -199,29 +199,29 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
}
async frameElement(): Promise<ElementHandle> {
return ElementHandle.from((await this._channel.frameElement({}, undefined)).element);
return ElementHandle.from((await this._channel.frameElement({}, kNoTimeout)).element);
}
async evaluateHandle<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<structs.SmartHandle<R>> {
assertMaxArguments(arguments.length, 2);
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
}
async evaluate<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<R> {
assertMaxArguments(arguments.length, 2);
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return parseResult(result.value);
}
async _evaluateExposeUtilityScript<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<R> {
assertMaxArguments(arguments.length, 2);
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return parseResult(result.value);
}
async $(selector: string, options?: { strict?: boolean }): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
const result = await this._channel.querySelector({ selector, ...options }, undefined);
const result = await this._channel.querySelector({ selector, ...options }, kNoTimeout);
return ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
}
@@ -232,42 +232,42 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
throw new Error('options.visibility is not supported, did you mean options.state?');
if ((options as any).waitFor && (options as any).waitFor !== 'visible')
throw new Error('options.waitFor is not supported, did you mean options.state?');
const result = await this._channel.waitForSelector({ selector, ...options, timeout: this._timeout(options) }, options.signal);
const result = await this._channel.waitForSelector({ selector, ...options }, this._timeout(options));
return ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
}
async dispatchEvent(selector: string, type: string, eventInit?: any, options: channels.FrameDispatchEventOptions & TimeoutOptions = {}): Promise<void> {
await this._channel.dispatchEvent({ selector, type, eventInit: serializeArgument(eventInit), ...options, timeout: this._timeout(options) }, options.signal);
await this._channel.dispatchEvent({ selector, type, eventInit: serializeArgument(eventInit), ...options }, this._timeout(options));
}
async $eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element, Arg, R>, arg?: Arg): Promise<R> {
assertMaxArguments(arguments.length, 3);
const result = await this._channel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return parseResult(result.value);
}
async $$eval<R, Arg>(selector: string, pageFunction: structs.PageFunctionOn<Element[], Arg, R>, arg?: Arg): Promise<R> {
assertMaxArguments(arguments.length, 3);
const result = await this._channel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return parseResult(result.value);
}
async $$(selector: string): Promise<ElementHandle<SVGElement | HTMLElement>[]> {
const result = await this._channel.querySelectorAll({ selector }, undefined);
const result = await this._channel.querySelectorAll({ selector }, kNoTimeout);
return result.elements.map(e => ElementHandle.from(e) as ElementHandle<SVGElement | HTMLElement>);
}
async _queryCount(selector: string): Promise<number> {
return (await this._channel.queryCount({ selector }, undefined)).value;
return (await this._channel.queryCount({ selector }, kNoTimeout)).value;
}
async content(): Promise<string> {
return (await this._channel.content({}, undefined)).value;
return (await this._channel.content({}, kNoTimeout)).value;
}
async setContent(html: string, options: channels.FrameSetContentOptions & TimeoutOptions = {}): Promise<void> {
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
await this._channel.setContent({ html, ...options, waitUntil, timeout: this._navigationTimeout(options) }, options.signal);
await this._channel.setContent({ html, ...options, waitUntil }, this._navigationTimeout(options));
}
name(): string {
@@ -296,7 +296,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
copy.content = (await fs.promises.readFile(copy.path)).toString();
copy.content = addSourceUrlToScript(copy.content, copy.path);
}
return ElementHandle.from((await this._channel.addScriptTag({ ...copy }, undefined)).element);
return ElementHandle.from((await this._channel.addScriptTag({ ...copy }, kNoTimeout)).element);
}
async addStyleTag(options: { url?: string; path?: string; content?: string; } = {}): Promise<ElementHandle> {
@@ -305,19 +305,19 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
copy.content = (await fs.promises.readFile(copy.path)).toString();
copy.content += '/*# sourceURL=' + copy.path.replace(/\n/g, '') + '*/';
}
return ElementHandle.from((await this._channel.addStyleTag({ ...copy }, undefined)).element);
return ElementHandle.from((await this._channel.addStyleTag({ ...copy }, kNoTimeout)).element);
}
async click(selector: string, options: channels.FrameClickOptions & TimeoutOptions = {}) {
return await this._channel.click({ selector, ...options, timeout: this._timeout(options) }, options.signal);
return await this._channel.click({ selector, ...options }, this._timeout(options));
}
async dblclick(selector: string, options: channels.FrameDblclickOptions & TimeoutOptions = {}) {
return await this._channel.dblclick({ selector, ...options, timeout: this._timeout(options) }, options.signal);
return await this._channel.dblclick({ selector, ...options }, this._timeout(options));
}
async dragAndDrop(source: string, target: string, options: channels.FrameDragAndDropOptions & TimeoutOptions = {}) {
return await this._channel.dragAndDrop({ source, target, ...options, timeout: this._timeout(options) }, options.signal);
return await this._channel.dragAndDrop({ source, target, ...options }, this._timeout(options));
}
async _drop(selector: string, payload: DropPayload, options: Omit<channels.FrameDropOptions, 'payloads' | 'localPaths' | 'streams' | 'data'> & TimeoutOptions = {}) {
@@ -334,24 +334,23 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
...fileParams,
data: dataArray,
...options,
timeout: this._timeout(options),
}, options.signal);
}, this._timeout(options));
}
async tap(selector: string, options: channels.FrameTapOptions & TimeoutOptions = {}) {
return await this._channel.tap({ selector, ...options, timeout: this._timeout(options) }, options.signal);
return await this._channel.tap({ selector, ...options }, this._timeout(options));
}
async fill(selector: string, value: string, options: channels.FrameFillOptions & TimeoutOptions = {}) {
return await this._channel.fill({ selector, value, ...options, timeout: this._timeout(options) }, options.signal);
return await this._channel.fill({ selector, value, ...options }, this._timeout(options));
}
async _highlight(selector: string, style?: string) {
return await this._channel.highlight({ selector, style }, undefined);
return await this._channel.highlight({ selector, style }, kNoTimeout);
}
async _hideHighlight(selector: string) {
return await this._channel.hideHighlight({ selector }, undefined);
return await this._channel.hideHighlight({ selector }, kNoTimeout);
}
locator(selector: string, options?: LocatorOptions): Locator {
@@ -391,82 +390,82 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
}
async focus(selector: string, options: channels.FrameFocusOptions & TimeoutOptions = {}) {
await this._channel.focus({ selector, ...options, timeout: this._timeout(options) }, options.signal);
await this._channel.focus({ selector, ...options }, this._timeout(options));
}
async textContent(selector: string, options: channels.FrameTextContentOptions & TimeoutOptions = {}): Promise<null|string> {
const value = (await this._channel.textContent({ selector, ...options, timeout: this._timeout(options) }, options.signal)).value;
const value = (await this._channel.textContent({ selector, ...options }, this._timeout(options))).value;
return value === undefined ? null : value;
}
async innerText(selector: string, options: channels.FrameInnerTextOptions & TimeoutOptions = {}): Promise<string> {
return (await this._channel.innerText({ selector, ...options, timeout: this._timeout(options) }, options.signal)).value;
return (await this._channel.innerText({ selector, ...options }, this._timeout(options))).value;
}
async innerHTML(selector: string, options: channels.FrameInnerHTMLOptions & TimeoutOptions = {}): Promise<string> {
return (await this._channel.innerHTML({ selector, ...options, timeout: this._timeout(options) }, options.signal)).value;
return (await this._channel.innerHTML({ selector, ...options }, this._timeout(options))).value;
}
async getAttribute(selector: string, name: string, options: channels.FrameGetAttributeOptions & TimeoutOptions = {}): Promise<string | null> {
const value = (await this._channel.getAttribute({ selector, name, ...options, timeout: this._timeout(options) }, options.signal)).value;
const value = (await this._channel.getAttribute({ selector, name, ...options }, this._timeout(options))).value;
return value === undefined ? null : value;
}
async inputValue(selector: string, options: channels.FrameInputValueOptions & TimeoutOptions = {}): Promise<string> {
return (await this._channel.inputValue({ selector, ...options, timeout: this._timeout(options) }, options.signal)).value;
return (await this._channel.inputValue({ selector, ...options }, this._timeout(options))).value;
}
async isChecked(selector: string, options: channels.FrameIsCheckedOptions & TimeoutOptions = {}): Promise<boolean> {
return (await this._channel.isChecked({ selector, ...options, timeout: this._timeout(options) }, options.signal)).value;
return (await this._channel.isChecked({ selector, ...options }, this._timeout(options))).value;
}
async isDisabled(selector: string, options: channels.FrameIsDisabledOptions & TimeoutOptions = {}): Promise<boolean> {
return (await this._channel.isDisabled({ selector, ...options, timeout: this._timeout(options) }, options.signal)).value;
return (await this._channel.isDisabled({ selector, ...options }, this._timeout(options))).value;
}
async isEditable(selector: string, options: channels.FrameIsEditableOptions & TimeoutOptions = {}): Promise<boolean> {
return (await this._channel.isEditable({ selector, ...options, timeout: this._timeout(options) }, options.signal)).value;
return (await this._channel.isEditable({ selector, ...options }, this._timeout(options))).value;
}
async isEnabled(selector: string, options: channels.FrameIsEnabledOptions & TimeoutOptions = {}): Promise<boolean> {
return (await this._channel.isEnabled({ selector, ...options, timeout: this._timeout(options) }, options.signal)).value;
return (await this._channel.isEnabled({ selector, ...options }, this._timeout(options))).value;
}
async isHidden(selector: string, options: channels.FrameIsHiddenOptions & TimeoutOptions = {}): Promise<boolean> {
return (await this._channel.isHidden({ selector, ...options }, options.signal)).value;
return (await this._channel.isHidden({ selector, ...options }, kNoTimeout)).value;
}
async isVisible(selector: string, options: channels.FrameIsVisibleOptions & TimeoutOptions = {}): Promise<boolean> {
return (await this._channel.isVisible({ selector, ...options }, options.signal)).value;
return (await this._channel.isVisible({ selector, ...options }, kNoTimeout)).value;
}
async hover(selector: string, options: channels.FrameHoverOptions & TimeoutOptions = {}) {
await this._channel.hover({ selector, ...options, timeout: this._timeout(options) }, options.signal);
await this._channel.hover({ selector, ...options }, this._timeout(options));
}
async selectOption(selector: string, values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions & StrictOptions = {}): Promise<string[]> {
return (await this._channel.selectOption({ selector, ...convertSelectOptionValues(values), ...options, timeout: this._timeout(options) }, options.signal)).values;
return (await this._channel.selectOption({ selector, ...convertSelectOptionValues(values), ...options }, this._timeout(options))).values;
}
async setInputFiles(selector: string, files: string | FilePayload | string[] | FilePayload[], options: channels.FrameSetInputFilesOptions & TimeoutOptions = {}): Promise<void> {
const converted = await convertInputFiles(files, this.page().context());
await this._channel.setInputFiles({ selector, ...converted, ...options, timeout: this._timeout(options) }, options.signal);
await this._channel.setInputFiles({ selector, ...converted, ...options }, this._timeout(options));
}
async type(selector: string, text: string, options: channels.FrameTypeOptions & TimeoutOptions = {}) {
await this._channel.type({ selector, text, ...options, timeout: this._timeout(options) }, options.signal);
await this._channel.type({ selector, text, ...options }, this._timeout(options));
}
async press(selector: string, key: string, options: channels.FramePressOptions & TimeoutOptions = {}) {
await this._channel.press({ selector, key, ...options, timeout: this._timeout(options) }, options.signal);
await this._channel.press({ selector, key, ...options }, this._timeout(options));
}
async check(selector: string, options: channels.FrameCheckOptions & TimeoutOptions = {}) {
await this._channel.check({ selector, ...options, timeout: this._timeout(options) }, options.signal);
await this._channel.check({ selector, ...options }, this._timeout(options));
}
async uncheck(selector: string, options: channels.FrameUncheckOptions & TimeoutOptions = {}) {
await this._channel.uncheck({ selector, ...options, timeout: this._timeout(options) }, options.signal);
await this._channel.uncheck({ selector, ...options }, this._timeout(options));
}
async setChecked(selector: string, checked: boolean, options?: channels.FrameCheckOptions) {
@@ -477,7 +476,7 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
}
async waitForTimeout(timeout: number) {
await this._channel.waitForTimeout({ waitTimeout: timeout }, undefined);
await this._channel.waitForTimeout({ waitTimeout: timeout }, kNoTimeout);
}
async waitForFunction<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg, options: WaitForFunctionOptions = {}): Promise<structs.SmartHandle<R>> {
@@ -489,20 +488,20 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
expression: String(pageFunction),
isFunction: typeof pageFunction === 'function',
arg: serializeArgument(arg),
timeout: this._timeout(options),
}, options.signal);
}, this._timeout(options));
return JSHandle.from(result.handle!) as any as structs.SmartHandle<R>;
}
async title(): Promise<string> {
return (await this._channel.title({}, undefined)).value;
return (await this._channel.title({}, kNoTimeout)).value;
}
async _expect(expression: string, options: Omit<channels.FrameExpectParams, 'expression'>, signal: AbortSignal | undefined): Promise<ExpectResult> {
const params: channels.FrameExpectParams = { expression, ...options, isNot: !!options.isNot };
params.expectedValue = serializeArgument(options.expectedValue);
async _expect(expression: string, options: Omit<channels.FrameExpectParams, 'expression'> & { timeout: number }, signal: AbortSignal | undefined): Promise<ExpectResult> {
const { timeout, ...rest } = options;
const params: channels.FrameExpectParams = { expression, ...rest, isNot: !!rest.isNot };
params.expectedValue = serializeArgument(rest.expectedValue);
try {
await this._channel.expect(params, signal);
await this._channel.expect(params, { signal, timeout });
return { matches: !params.isNot };
} catch (e) {
if (e instanceof AbortError)
@@ -17,6 +17,7 @@
import { debugLogger } from '@utils/debugLogger';
import { isRegExp, isString } from '@isomorphic/rtti';
import { kNoTimeout } from './timeoutSettings';
import type { BrowserContext } from './browserContext';
import type { LocalUtils } from './localUtils';
import type { Route } from './network';
@@ -127,7 +128,7 @@ export class HarRouter {
urlRegexSource: isRegExp(urlMatch) ? urlMatch.source : undefined,
urlRegexFlags: isRegExp(urlMatch) ? urlMatch.flags : undefined,
notFound: this._notFoundAction,
}, undefined);
}, kNoTimeout);
this._apiRequestRegistrations.push({ context, registrationId });
}
@@ -137,7 +138,7 @@ export class HarRouter {
dispose() {
for (const { context, registrationId } of this._apiRequestRegistrations)
context._channel.unrouteAPIRequestsFromHar({ registrationId }, undefined).catch(() => {});
context._channel.unrouteAPIRequestsFromHar({ registrationId }, kNoTimeout).catch(() => {});
this._apiRequestRegistrations = [];
this._localUtils.harClose({ harId: this._harId }).catch(() => {});
}
+12 -11
View File
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import { kNoTimeout } from './timeoutSettings';
import type { Page } from './page';
import type * as api from '../../types/types';
import type * as channels from './channels';
@@ -27,23 +28,23 @@ export class Keyboard implements api.Keyboard {
}
async down(key: string) {
await this._page._channel.keyboardDown({ key }, undefined);
await this._page._channel.keyboardDown({ key }, kNoTimeout);
}
async up(key: string) {
await this._page._channel.keyboardUp({ key }, undefined);
await this._page._channel.keyboardUp({ key }, kNoTimeout);
}
async insertText(text: string) {
await this._page._channel.keyboardInsertText({ text }, undefined);
await this._page._channel.keyboardInsertText({ text }, kNoTimeout);
}
async type(text: string, options: channels.PageKeyboardTypeOptions = {}) {
await this._page._channel.keyboardType({ text, ...options }, undefined);
await this._page._channel.keyboardType({ text, ...options }, kNoTimeout);
}
async press(key: string, options: channels.PageKeyboardPressOptions = {}) {
await this._page._channel.keyboardPress({ key, ...options }, undefined);
await this._page._channel.keyboardPress({ key, ...options }, kNoTimeout);
}
}
@@ -55,19 +56,19 @@ export class Mouse implements api.Mouse {
}
async move(x: number, y: number, options: { steps?: number } = {}) {
await this._page._channel.mouseMove({ x, y, ...options }, undefined);
await this._page._channel.mouseMove({ x, y, ...options }, kNoTimeout);
}
async down(options: channels.PageMouseDownOptions = {}) {
await this._page._channel.mouseDown({ ...options }, undefined);
await this._page._channel.mouseDown({ ...options }, kNoTimeout);
}
async up(options: channels.PageMouseUpOptions = {}) {
await this._page._channel.mouseUp(options, undefined);
await this._page._channel.mouseUp(options, kNoTimeout);
}
async click(x: number, y: number, options: channels.PageMouseClickOptions = {}) {
await this._page._channel.mouseClick({ x, y, ...options }, undefined);
await this._page._channel.mouseClick({ x, y, ...options }, kNoTimeout);
}
async dblclick(x: number, y: number, options: Omit<channels.PageMouseClickOptions, 'clickCount'> = {}) {
@@ -77,7 +78,7 @@ export class Mouse implements api.Mouse {
}
async wheel(deltaX: number, deltaY: number) {
await this._page._channel.mouseWheel({ deltaX, deltaY }, undefined);
await this._page._channel.mouseWheel({ deltaX, deltaY }, kNoTimeout);
}
}
@@ -89,6 +90,6 @@ export class Touchscreen implements api.Touchscreen {
}
async tap(x: number, y: number) {
await this._page._channel.touchscreenTap({ x, y }, undefined);
await this._page._channel.touchscreenTap({ x, y }, kNoTimeout);
}
}
@@ -17,6 +17,7 @@
import { parseSerializedValue, serializeValue } from '@protocol/serializers';
import { ChannelOwner } from './channelOwner';
import { isTargetClosedError } from './errors';
import { kNoTimeout } from './timeoutSettings';
import type * as structs from '../../types/structs';
import type * as api from '../../types/types';
@@ -37,29 +38,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> {
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return parseResult(result.value);
}
async evaluateHandle<R, Arg>(pageFunction: structs.PageFunctionOn<T, Arg, R>, arg?: Arg): Promise<structs.SmartHandle<R>> {
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
}
async getProperty(propertyName: string): Promise<JSHandle> {
const result = await this._channel.getProperty({ name: propertyName }, undefined);
const result = await this._channel.getProperty({ name: propertyName }, kNoTimeout);
return JSHandle.from(result.handle);
}
async getProperties(): Promise<Map<string, JSHandle>> {
const map = new Map<string, JSHandle>();
for (const { name, value } of (await this._channel.getPropertyList({}, undefined)).properties)
for (const { name, value } of (await this._channel.getPropertyList({}, kNoTimeout)).properties)
map.set(name, JSHandle.from(value));
return map;
}
async jsonValue(): Promise<T> {
return parseResult((await this._channel.jsonValue({}, undefined)).value);
return parseResult((await this._channel.jsonValue({}, kNoTimeout)).value);
}
asElement(): T extends Node ? api.ElementHandle<T> : null {
@@ -72,7 +73,7 @@ export class JSHandle<T = any> extends ChannelOwner<channels.JSHandleChannel> im
async dispose() {
try {
await this._channel.dispose({}, undefined);
await this._channel.dispose({}, kNoTimeout);
} catch (e) {
if (isTargetClosedError(e))
return;
@@ -15,6 +15,7 @@
*/
import { ChannelOwner } from './channelOwner';
import { kNoTimeout } from './timeoutSettings';
import type { Size } from './types';
import type * as channels from './channels';
@@ -40,34 +41,34 @@ export class LocalUtils extends ChannelOwner<channels.LocalUtilsChannel> {
}
async zip(params: channels.LocalUtilsZipParams): Promise<void> {
return await this._channel.zip(params, undefined);
return await this._channel.zip(params, kNoTimeout);
}
async harOpen(params: channels.LocalUtilsHarOpenParams): Promise<channels.LocalUtilsHarOpenResult> {
return await this._channel.harOpen(params, undefined);
return await this._channel.harOpen(params, kNoTimeout);
}
async harLookup(params: channels.LocalUtilsHarLookupParams): Promise<channels.LocalUtilsHarLookupResult> {
return await this._channel.harLookup(params, undefined);
return await this._channel.harLookup(params, kNoTimeout);
}
async harClose(params: channels.LocalUtilsHarCloseParams): Promise<void> {
return await this._channel.harClose(params, undefined);
return await this._channel.harClose(params, kNoTimeout);
}
async harUnzip(params: channels.LocalUtilsHarUnzipParams): Promise<void> {
return await this._channel.harUnzip(params, undefined);
return await this._channel.harUnzip(params, kNoTimeout);
}
async tracingStarted(params: channels.LocalUtilsTracingStartedParams): Promise<channels.LocalUtilsTracingStartedResult> {
return await this._channel.tracingStarted(params, undefined);
return await this._channel.tracingStarted(params, kNoTimeout);
}
async traceDiscarded(params: channels.LocalUtilsTraceDiscardedParams): Promise<void> {
return await this._channel.traceDiscarded(params, undefined);
return await this._channel.traceDiscarded(params, kNoTimeout);
}
async addStackToTracingNoReply(params: channels.LocalUtilsAddStackToTracingNoReplyParams): Promise<void> {
return await this._channel.addStackToTracingNoReply(params, undefined);
return await this._channel.addStackToTracingNoReply(params, kNoTimeout);
}
}
@@ -24,6 +24,7 @@ import { monotonicTime } from '@isomorphic/time';
import { ElementHandle } from './elementHandle';
import { serializeArgument } from './jsHandle';
import { DisposableStub } from './disposable';
import { kNoTimeout } from './timeoutSettings';
import type { ExpectResult, Frame } from './frame';
import type { DropPayload, FilePayload, FrameExpectParams, Rect, SelectOption, SelectOptionOptions, TimeoutOptions } from './types';
@@ -78,11 +79,11 @@ export class Locator implements api.Locator {
}
private async _withElement<R>(task: (handle: ElementHandle<SVGElement | HTMLElement>, timeout?: number) => Promise<R>, options: { title: string, internal?: boolean, timeout?: number, signal?: AbortSignal }): Promise<R> {
const timeout = this._frame._timeout({ timeout: options.timeout });
const timeout = this._frame._timeout({ timeout: options.timeout }).timeout;
const deadline = timeout ? monotonicTime() + timeout : 0;
return await this._frame._wrapApiCall<R>(async () => {
const result = await this._frame._channel.waitForSelector({ selector: this._selector, strict: true, state: 'attached', timeout }, options.signal);
const result = await this._frame._channel.waitForSelector({ selector: this._selector, strict: true, state: 'attached' }, { signal: options.signal, 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`);
@@ -261,7 +262,7 @@ export class Locator implements api.Locator {
}
async blur(options?: TimeoutOptions): Promise<void> {
await this._frame._channel.blur({ selector: this._selector, strict: true, ...options, timeout: this._frame._timeout(options) }, options?.signal);
await this._frame._channel.blur({ selector: this._selector, strict: true, ...options }, this._frame._timeout(options));
}
async count(): Promise<number> {
@@ -269,7 +270,7 @@ export class Locator implements api.Locator {
}
async normalize(): Promise<Locator> {
const { resolvedSelector } = await this._frame._channel.resolveSelector({ selector: this._selector }, undefined);
const { resolvedSelector } = await this._frame._channel.resolveSelector({ selector: this._selector }, kNoTimeout);
return new Locator(this._frame, resolvedSelector);
}
@@ -327,7 +328,7 @@ export class Locator implements api.Locator {
}
async ariaSnapshot(options: TimeoutOptions & { mode?: 'ai' | 'default', depth?: number, boxes?: boolean } = {}): Promise<string> {
const result = await this._frame._channel.ariaSnapshot({ timeout: this._frame._timeout(options), mode: options.mode, selector: this._selector, depth: options.depth, boxes: options.boxes }, options.signal);
const result = await this._frame._channel.ariaSnapshot({ mode: options.mode, selector: this._selector, depth: options.depth, boxes: options.boxes }, this._frame._timeout(options));
return result.snapshot;
}
@@ -389,7 +390,7 @@ export class Locator implements api.Locator {
waitFor(options: channels.FrameWaitForSelectorOptions & TimeoutOptions & { state: 'attached' | 'visible' }): Promise<void>;
waitFor(options?: channels.FrameWaitForSelectorOptions & TimeoutOptions): Promise<void>;
async waitFor(options?: channels.FrameWaitForSelectorOptions & TimeoutOptions): Promise<void> {
await this._frame._channel.waitForSelector({ selector: this._selector, strict: true, omitReturnValue: true, ...options, timeout: this._frame._timeout(options) }, options?.signal);
await this._frame._channel.waitForSelector({ selector: this._selector, strict: true, omitReturnValue: true, ...options }, this._frame._timeout(options));
}
async waitForFunction<R, Arg>(pageFunction: structs.PageFunctionOn<SVGElement | HTMLElement, Arg, R>, arg?: Arg, options?: TimeoutOptions): Promise<void> {
@@ -399,8 +400,7 @@ export class Locator implements api.Locator {
expression: String(pageFunction),
isFunction: typeof pageFunction === 'function',
arg: serializeArgument(arg),
timeout: this._frame._timeout(options),
}, options?.signal);
}, this._frame._timeout(options));
}
+28 -28
View File
@@ -32,10 +32,11 @@ import { APIResponse } from './fetch';
import { Events } from './events';
import { isTargetClosedError } from './errors';
import { ChannelOwner } from './channelOwner';
import { kNoTimeout } from './timeoutSettings';
import type { BrowserContext } from './browserContext';
import type { Page } from './page';
import type { Headers, RemoteAddr, SecurityDetails, TimeoutOptions, WaitForEventOptions } from './types';
import type { Headers, RemoteAddr, SecurityDetails, WaitForEventOptions } from './types';
import type { Serializable } from '../../types/structs';
import type * as api from '../../types/types';
import type { HeadersArray } from '@isomorphic/types';
@@ -179,7 +180,7 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
if (!this._actualHeadersPromise) {
this._actualHeadersPromise = this._wrapApiCall(async () => {
return new RawHeaders((await this._channel.rawRequestHeaders({}, undefined)).headers);
return new RawHeaders((await this._channel.rawRequestHeaders({}, kNoTimeout)).headers);
}, { internal: true });
}
return await this._actualHeadersPromise;
@@ -198,11 +199,11 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
}
async response(): Promise<Response | null> {
return Response.fromNullable((await this._channel.response({}, undefined)).response);
return Response.fromNullable((await this._channel.response({}, kNoTimeout)).response);
}
async _internalResponse(): Promise<Response | null> {
return Response.fromNullable((await this._channel.response({}, undefined)).response);
return Response.fromNullable((await this._channel.response({}, kNoTimeout)).response);
}
existingResponse(): Response | null {
@@ -261,7 +262,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 (await response._channel.sizes({}, undefined)).sizes;
return (await response._channel.sizes({}, kNoTimeout)).sizes;
}
_setResponseEndTiming(responseEndTiming: number) {
@@ -336,13 +337,13 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
async abort(errorCode?: string) {
await this._handleRoute(async () => {
await this._raceWithTargetClose(this._channel.abort({ errorCode }, undefined));
await this._raceWithTargetClose(this._channel.abort({ errorCode }, kNoTimeout));
});
}
async _redirectNavigationRequest(url: string) {
await this._handleRoute(async () => {
await this._raceWithTargetClose(this._channel.redirectNavigationRequest({ url }, undefined));
await this._raceWithTargetClose(this._channel.redirectNavigationRequest({ url }, kNoTimeout));
});
}
@@ -423,7 +424,7 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
body,
isBase64,
fetchResponseUid
}, undefined));
}, kNoTimeout));
}
async continue(options: FallbackOverrides = {}) {
@@ -452,7 +453,7 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
headers: options.headers ? headersObjectToArray(options.headers) : undefined,
postData: options.postDataBuffer,
isFallback,
}, undefined));
}, kNoTimeout));
}
}
@@ -493,14 +494,14 @@ export class WebSocketRoute extends ChannelOwner<channels.WebSocketRouteChannel>
},
close: async (options: { code?: number, reason?: string } = {}) => {
await this._channel.closeServer({ ...options, wasClean: true }, undefined).catch(() => {});
await this._channel.closeServer({ ...options, wasClean: true }, kNoTimeout).catch(() => {});
},
send: (message: string | Buffer) => {
if (isString(message))
this._channel.sendToServer({ message, isBase64: false }, undefined).catch(() => {});
this._channel.sendToServer({ message, isBase64: false }, kNoTimeout).catch(() => {});
else
this._channel.sendToServer({ message: message.toString('base64'), isBase64: true }, undefined).catch(() => {});
this._channel.sendToServer({ message: message.toString('base64'), isBase64: true }, kNoTimeout).catch(() => {});
},
async [Symbol.asyncDispose]() {
@@ -512,28 +513,28 @@ export class WebSocketRoute extends ChannelOwner<channels.WebSocketRouteChannel>
if (this._onPageMessage)
this._onPageMessage(isBase64 ? Buffer.from(message, 'base64') : message);
else if (this._connected)
this._channel.sendToServer({ message, isBase64 }, undefined).catch(() => {});
this._channel.sendToServer({ message, isBase64 }, kNoTimeout).catch(() => {});
});
this._channel.on('messageFromServer', ({ message, isBase64 }) => {
if (this._onServerMessage)
this._onServerMessage(isBase64 ? Buffer.from(message, 'base64') : message);
else
this._channel.sendToPage({ message, isBase64 }, undefined).catch(() => {});
this._channel.sendToPage({ message, isBase64 }, kNoTimeout).catch(() => {});
});
this._channel.on('closePage', ({ code, reason, wasClean }) => {
if (this._onPageClose)
this._onPageClose(code, reason);
else
this._channel.closeServer({ code, reason, wasClean }, undefined).catch(() => {});
this._channel.closeServer({ code, reason, wasClean }, kNoTimeout).catch(() => {});
});
this._channel.on('closeServer', ({ code, reason, wasClean }) => {
if (this._onServerClose)
this._onServerClose(code, reason);
else
this._channel.closePage({ code, reason, wasClean }, undefined).catch(() => {});
this._channel.closePage({ code, reason, wasClean }, kNoTimeout).catch(() => {});
});
}
@@ -546,22 +547,22 @@ export class WebSocketRoute extends ChannelOwner<channels.WebSocketRouteChannel>
}
async close(options: { code?: number, reason?: string } = {}) {
await this._channel.closePage({ ...options, wasClean: true }, undefined).catch(() => {});
await this._channel.closePage({ ...options, wasClean: true }, kNoTimeout).catch(() => {});
}
connectToServer() {
if (this._connected)
throw new Error('Already connected to the server');
this._connected = true;
this._channel.connect({}, undefined).catch(() => {});
this._channel.connect({}, kNoTimeout).catch(() => {});
return this._server;
}
send(message: string | Buffer) {
if (isString(message))
this._channel.sendToPage({ message, isBase64: false }, undefined).catch(() => {});
this._channel.sendToPage({ message, isBase64: false }, kNoTimeout).catch(() => {});
else
this._channel.sendToPage({ message: message.toString('base64'), isBase64: true }, undefined).catch(() => {});
this._channel.sendToPage({ message: message.toString('base64'), isBase64: true }, kNoTimeout).catch(() => {});
}
onMessage(handler: (message: string | Buffer) => any) {
@@ -581,7 +582,7 @@ export class WebSocketRoute extends ChannelOwner<channels.WebSocketRouteChannel>
return;
// Ensure that websocket is "open" and can send messages without an actual server connection.
// If this happens after the page has been closed, ignore the error.
await this._channel.ensureOpened({}, undefined).catch(() => {});
await this._channel.ensureOpened({}, kNoTimeout).catch(() => {});
}
}
@@ -701,7 +702,7 @@ export class Response extends ChannelOwner<channels.ResponseChannel> implements
async _actualHeaders(): Promise<RawHeaders> {
if (!this._actualHeadersPromise) {
this._actualHeadersPromise = (async () => {
return new RawHeaders((await this._channel.rawResponseHeaders({}, undefined)).headers);
return new RawHeaders((await this._channel.rawResponseHeaders({}, kNoTimeout)).headers);
})();
}
return await this._actualHeadersPromise;
@@ -728,7 +729,7 @@ export class Response extends ChannelOwner<channels.ResponseChannel> implements
}
async body(): Promise<Buffer> {
return (await this._channel.body({}, undefined)).binary;
return (await this._channel.body({}, kNoTimeout)).binary;
}
async text(): Promise<string> {
@@ -750,15 +751,15 @@ export class Response extends ChannelOwner<channels.ResponseChannel> implements
}
async serverAddr(): Promise<RemoteAddr|null> {
return (await this._channel.serverAddr({}, undefined)).value || null;
return (await this._channel.serverAddr({}, kNoTimeout)).value || null;
}
async securityDetails(): Promise<SecurityDetails|null> {
return (await this._channel.securityDetails({}, undefined)).value || null;
return (await this._channel.securityDetails({}, kNoTimeout)).value || null;
}
async httpVersion(): Promise<string> {
return (await this._channel.httpVersion({}, undefined)).value;
return (await this._channel.httpVersion({}, kNoTimeout)).value;
}
}
@@ -803,9 +804,8 @@ export class WebSocket extends ChannelOwner<channels.WebSocketChannel> implement
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
return await this._wrapApiCall(async () => {
const timeout = this._page._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const { timeout, signal } = this._page._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const signal = typeof optionsOrPredicate === 'function' ? undefined : (optionsOrPredicate as TimeoutOptions).signal;
const waiter = Waiter.createForEvent(this, event);
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
waiter.rejectOnSignal(signal);
+39 -39
View File
@@ -45,7 +45,7 @@ import { Video } from './video';
import { Screencast } from './screencast';
import { Waiter } from './waiter';
import { Worker } from './worker';
import { TimeoutSettings } from './timeoutSettings';
import { TimeoutSettings, kNoTimeout } from './timeoutSettings';
import { mkdirIfNeeded } from './fileUtils';
import { ConsoleMessage } from './consoleMessage';
import type { BrowserContext } from './browserContext';
@@ -306,16 +306,16 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
}
async pickLocator(): Promise<Locator> {
const { selector } = await this._channel.pickLocator({}, undefined);
const { selector } = await this._channel.pickLocator({}, kNoTimeout);
return this.locator(selector);
}
async cancelPickLocator(): Promise<void> {
await this._channel.cancelPickLocator({}, undefined);
await this._channel.cancelPickLocator({}, kNoTimeout);
}
async hideHighlight(): Promise<void> {
await this._channel.hideHighlight({}, undefined);
await this._channel.hideHighlight({}, kNoTimeout);
}
async $(selector: string, options?: { strict?: boolean }): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
@@ -360,21 +360,21 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
}
async exposeFunction(name: string, callback: Function) {
const result = await this._channel.exposeBinding({ name }, undefined);
const result = await this._channel.exposeBinding({ name }, kNoTimeout);
const binding = (source: structs.BindingSource, ...args: any[]) => callback(...args);
this._bindings.set(name, binding);
return DisposableObject.from(result.disposable);
}
async exposeBinding(name: string, callback: (source: structs.BindingSource, ...args: any[]) => any) {
const result = await this._channel.exposeBinding({ name }, undefined);
const result = await this._channel.exposeBinding({ name }, kNoTimeout);
this._bindings.set(name, callback);
return DisposableObject.from(result.disposable);
}
async setExtraHTTPHeaders(headers: Headers) {
validateHeaders(headers);
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) }, undefined);
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) }, kNoTimeout);
}
url(): string {
@@ -395,7 +395,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
async reload(options: channels.PageReloadOptions & TimeoutOptions = {}): Promise<Response | null> {
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
return Response.fromNullable((await this._channel.reload({ ...options, waitUntil, timeout: this._timeoutSettings.navigationTimeout(options) }, options.signal)).response);
return Response.fromNullable((await this._channel.reload({ ...options, waitUntil }, this._timeoutSettings.navigationTimeout(options))).response);
}
async addLocatorHandler(locator: Locator, handler: (locator: Locator) => any, options: { times?: number, noWaitAfter?: boolean } = {}): Promise<void> {
@@ -403,7 +403,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
throw new Error(`Locator must belong to the main frame of this page`);
if (options.times === 0)
return;
const { uid } = await this._channel.registerLocatorHandler({ selector: locator._selector, noWaitAfter: options.noWaitAfter }, undefined);
const { uid } = await this._channel.registerLocatorHandler({ selector: locator._selector, noWaitAfter: options.noWaitAfter }, kNoTimeout);
this._locatorHandlers.set(uid, { locator, handler, times: options.times });
}
@@ -420,7 +420,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
} finally {
if (remove)
this._locatorHandlers.delete(uid);
this._channel.resolveLocatorHandlerNoReply({ uid, remove }, undefined).catch(() => {});
this._channel.resolveLocatorHandlerNoReply({ uid, remove }, kNoTimeout).catch(() => {});
}
}
@@ -428,7 +428,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
for (const [uid, data] of this._locatorHandlers) {
if (data.locator._equals(locator)) {
this._locatorHandlers.delete(uid);
await this._channel.unregisterLocatorHandler({ uid }, undefined).catch(() => {});
await this._channel.unregisterLocatorHandler({ uid }, kNoTimeout).catch(() => {});
}
}
}
@@ -477,9 +477,8 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
private async _waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions, logLine?: string): Promise<any> {
return await this._wrapApiCall(async () => {
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const { timeout, signal } = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const signal = typeof optionsOrPredicate === 'function' ? undefined : (optionsOrPredicate as TimeoutOptions).signal;
const waiter = Waiter.createForEvent(this, event);
if (logLine)
waiter.log(logLine);
@@ -497,16 +496,16 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
async goBack(options: channels.PageGoBackOptions & TimeoutOptions = {}): Promise<Response | null> {
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
return Response.fromNullable((await this._channel.goBack({ ...options, waitUntil, timeout: this._timeoutSettings.navigationTimeout(options) }, options.signal)).response);
return Response.fromNullable((await this._channel.goBack({ ...options, waitUntil }, this._timeoutSettings.navigationTimeout(options))).response);
}
async goForward(options: channels.PageGoForwardOptions & TimeoutOptions = {}): Promise<Response | null> {
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
return Response.fromNullable((await this._channel.goForward({ ...options, waitUntil, timeout: this._timeoutSettings.navigationTimeout(options) }, options.signal)).response);
return Response.fromNullable((await this._channel.goForward({ ...options, waitUntil }, this._timeoutSettings.navigationTimeout(options))).response);
}
async requestGC() {
await this._channel.requestGC({}, undefined);
await this._channel.requestGC({}, kNoTimeout);
}
async emulateMedia(options: { media?: 'screen' | 'print' | null, colorScheme?: 'dark' | 'light' | 'no-preference' | null, reducedMotion?: 'reduce' | 'no-preference' | null, forcedColors?: 'active' | 'none' | null, contrast?: 'no-preference' | 'more' | null } = {}) {
@@ -516,12 +515,12 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
reducedMotion: options.reducedMotion === null ? 'no-override' : options.reducedMotion,
forcedColors: options.forcedColors === null ? 'no-override' : options.forcedColors,
contrast: options.contrast === null ? 'no-override' : options.contrast,
}, undefined);
}, kNoTimeout);
}
async setViewportSize(viewportSize: Size) {
this._viewportSize = viewportSize;
await this._channel.setViewportSize({ viewportSize }, undefined);
await this._channel.setViewportSize({ viewportSize }, kNoTimeout);
}
viewportSize(): Size | null {
@@ -535,7 +534,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any) {
const source = await evaluationScript(script, arg);
return DisposableObject.from((await this._channel.addInitScript({ source }, undefined)).disposable);
return DisposableObject.from((await this._channel.addInitScript({ source }, kNoTimeout)).disposable);
}
async route(url: URLMatch, handler: RouteHandlerCallback, options: { times?: number } = {}): Promise<DisposableStub> {
@@ -595,17 +594,17 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
private async _updateInterceptionPatterns(options: { internal: true } | { title: string }) {
const patterns = RouteHandler.prepareInterceptionPatterns(this._routes);
await this._wrapApiCall(() => this._channel.setNetworkInterceptionPatterns({ patterns }, undefined), options);
await this._wrapApiCall(() => this._channel.setNetworkInterceptionPatterns({ patterns }, kNoTimeout), options);
}
private async _updateWebSocketInterceptionPatterns(options: { internal: true } | { title: string }) {
const patterns = WebSocketRouteHandler.prepareInterceptionPatterns(this._webSocketRoutes);
await this._wrapApiCall(() => this._channel.setWebSocketInterceptionPatterns({ patterns }, undefined), options);
await this._wrapApiCall(() => this._channel.setWebSocketInterceptionPatterns({ patterns }, kNoTimeout), options);
}
async screenshot(options: Omit<channels.PageScreenshotOptions, 'mask'> & TimeoutOptions & { path?: string, mask?: api.Locator[] } = {}): Promise<Buffer> {
const mask = options.mask as Locator[] | undefined;
const copy: channels.PageScreenshotParams = { ...options, mask: undefined, timeout: this._timeoutSettings.timeout(options) };
const copy: channels.PageScreenshotParams = { ...options, mask: undefined };
if (!copy.type)
copy.type = determineScreenshotType(options);
if (mask) {
@@ -614,7 +613,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
selector: locator._selector,
}));
}
const result = await this._channel.screenshot(copy, options.signal);
const result = await this._channel.screenshot(copy, this._timeoutSettings.timeout(options));
if (options.path) {
await mkdirIfNeeded(options.path);
await fs.promises.writeFile(options.path, result.binary);
@@ -623,6 +622,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
}
async _expectScreenshot(options: ExpectScreenshotOptions): Promise<{ actual?: Buffer, previous?: Buffer, diff?: Buffer, errorMessage?: string, log?: string[], timedOut?: boolean}> {
const { timeout, ...optionsWithoutTimeout } = options;
const mask = options?.mask ? options?.mask.map(locator => ({
frame: (locator as Locator)._frame._channel,
selector: (locator as Locator)._selector,
@@ -633,11 +633,11 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
} : undefined;
try {
const result = await this._channel.expectScreenshot({
...options,
...optionsWithoutTimeout,
isNot: !!options.isNot,
locator,
mask,
}, undefined);
}, { signal: undefined, timeout });
return { actual: result.actual };
} catch (e) {
if (!(e instanceof PlaywrightError))
@@ -652,7 +652,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
}
async bringToFront(): Promise<void> {
await this._channel.bringToFront({}, undefined);
await this._channel.bringToFront({}, kNoTimeout);
}
async [Symbol.asyncDispose]() {
@@ -667,9 +667,9 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
if (this._ownedContext)
await this._ownedContext.close();
else if (options.runBeforeUnload)
await this._channel.runBeforeUnload({}, undefined);
await this._channel.runBeforeUnload({}, kNoTimeout);
else
await this._channel.close({ reason: options.reason }, undefined);
await this._channel.close({ reason: options.reason }, kNoTimeout);
} catch (e) {
if (isTargetClosedError(e) && !options.runBeforeUnload)
return;
@@ -702,20 +702,20 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
}
async clearConsoleMessages(): Promise<void> {
await this._channel.clearConsoleMessages({}, undefined);
await this._channel.clearConsoleMessages({}, kNoTimeout);
}
async consoleMessages(options?: { filter?: 'all' | 'since-navigation' }): Promise<ConsoleMessage[]> {
const { messages } = await this._channel.consoleMessages({ filter: options?.filter }, undefined);
const { messages } = await this._channel.consoleMessages({ filter: options?.filter }, kNoTimeout);
return messages.map(message => new ConsoleMessage(message, this, null));
}
async clearPageErrors(): Promise<void> {
await this._channel.clearPageErrors({}, undefined);
await this._channel.clearPageErrors({}, kNoTimeout);
}
async pageErrors(options?: { filter?: 'all' | 'since-navigation' }): Promise<Error[]> {
const { errors } = await this._channel.pageErrors({ filter: options?.filter }, undefined);
const { errors } = await this._channel.pageErrors({ filter: options?.filter }, kNoTimeout);
return errors.map(error => parseError(error));
}
@@ -844,7 +844,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
}
async requests() {
const { requests } = await this._channel.requests({}, undefined);
const { requests } = await this._channel.requests({}, kNoTimeout);
return requests.map(request => Request.from(request));
}
@@ -861,7 +861,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
this._browserContext.setDefaultNavigationTimeout(0);
this._browserContext.setDefaultTimeout(0);
this._instrumentation?.onWillPause({ keepTestTimeout: !!_options?.__testHookKeepTestTimeout });
await this._closedOrCrashedScope.safeRace(this.context()._channel.pause({}, undefined));
await this._closedOrCrashedScope.safeRace(this.context()._channel.pause({}, kNoTimeout));
this._browserContext.setDefaultNavigationTimeout(defaultNavigationTimeout);
this._browserContext.setDefaultTimeout(defaultTimeout);
}
@@ -879,7 +879,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
if (options.margin && typeof options.margin[index] === 'number')
transportOptions.margin![index] = transportOptions.margin![index] + 'px';
}
const result = await this._channel.pdf(transportOptions, undefined);
const result = await this._channel.pdf(transportOptions, kNoTimeout);
if (options.path) {
await fs.promises.mkdir(path.dirname(options.path), { recursive: true });
await fs.promises.writeFile(options.path, result.pdf);
@@ -888,12 +888,12 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
}
async ariaSnapshot(options: TimeoutOptions & { mode?: 'ai' | 'default', depth?: number, boxes?: boolean } = {}): Promise<string> {
const result = await this.mainFrame()._channel.ariaSnapshot({ timeout: this._timeoutSettings.timeout(options), mode: options.mode, depth: options.depth, boxes: options.boxes }, options.signal);
const result = await this.mainFrame()._channel.ariaSnapshot({ mode: options.mode, depth: options.depth, boxes: options.boxes }, this._timeoutSettings.timeout(options));
return result.snapshot;
}
async _setDockTile(image: Buffer) {
await this._channel.setDockTile({ image }, undefined);
await this._channel.setDockTile({ image }, kNoTimeout);
}
}
@@ -915,9 +915,9 @@ export class BindingCall extends ChannelOwner<channels.BindingCallChannel> {
frame
};
const result = await func(source, ...this._initializer.args.map(parseResult));
this._channel.resolve({ result: serializeArgument(result) }, undefined).catch(() => {});
this._channel.resolve({ result: serializeArgument(result) }, kNoTimeout).catch(() => {});
} catch (e) {
this._channel.reject({ error: serializeError(e) }, undefined).catch(() => {});
this._channel.reject({ error: serializeError(e) }, kNoTimeout).catch(() => {});
}
}
}
@@ -16,6 +16,7 @@
import { Artifact } from './artifact';
import { DisposableStub } from './disposable';
import { kNoTimeout } from './timeoutSettings';
import type * as api from '../../types/types';
import type { Page } from './page';
@@ -45,7 +46,7 @@ export class Screencast implements api.Screencast {
quality: options.quality,
sendFrames: !!options.onFrame,
record: !!options.path,
}, undefined);
}, kNoTimeout);
if (result.artifact) {
this._artifact = Artifact.from(result.artifact);
this._savePath = options.path;
@@ -57,7 +58,7 @@ export class Screencast implements api.Screencast {
await this._page._wrapApiCall(async () => {
this._started = false;
this._onFrame = null;
await this._page._channel.screencastStop({}, undefined);
await this._page._channel.screencastStop({}, kNoTimeout);
if (this._savePath)
await this._artifact?.saveAs(this._savePath);
this._artifact = undefined;
@@ -66,28 +67,28 @@ export class Screencast implements api.Screencast {
}
async showActions(options?: { duration?: number, position?: 'top-left' | 'top' | 'top-right' | 'bottom-left' | 'bottom' | 'bottom-right', fontSize?: number, cursor?: 'none' | 'pointer' }): Promise<DisposableStub> {
await this._page._channel.screencastShowActions({ duration: options?.duration, position: options?.position, fontSize: options?.fontSize, cursor: options?.cursor }, undefined);
return new DisposableStub(() => this._page._channel.screencastHideActions({}, undefined));
await this._page._channel.screencastShowActions({ duration: options?.duration, position: options?.position, fontSize: options?.fontSize, cursor: options?.cursor }, kNoTimeout);
return new DisposableStub(() => this._page._channel.screencastHideActions({}, kNoTimeout));
}
async hideActions(): Promise<void> {
await this._page._channel.screencastHideActions({}, undefined);
await this._page._channel.screencastHideActions({}, kNoTimeout);
}
async showOverlay(html: string, options?: { duration?: number }): Promise<DisposableStub> {
const { id } = await this._page._channel.screencastShowOverlay({ html, duration: options?.duration }, undefined);
return new DisposableStub(() => this._page._channel.screencastRemoveOverlay({ id }, undefined));
const { id } = await this._page._channel.screencastShowOverlay({ html, duration: options?.duration }, kNoTimeout);
return new DisposableStub(() => this._page._channel.screencastRemoveOverlay({ id }, kNoTimeout));
}
async showChapter(title: string, options?: { description?: string, duration?: number }): Promise<void> {
await this._page._channel.screencastChapter({ title, ...options }, undefined);
await this._page._channel.screencastChapter({ title, ...options }, kNoTimeout);
}
async showOverlays(): Promise<void> {
await this._page._channel.screencastSetOverlayVisible({ visible: true }, undefined);
await this._page._channel.screencastSetOverlayVisible({ visible: true }, kNoTimeout);
}
async hideOverlays(): Promise<void> {
await this._page._channel.screencastSetOverlayVisible({ visible: false }, undefined);
await this._page._channel.screencastSetOverlayVisible({ visible: false }, kNoTimeout);
}
}
@@ -16,6 +16,7 @@
import { evaluationScript } from './clientHelper';
import { setTestIdAttribute } from './locator';
import { kNoTimeout } from './timeoutSettings';
import type { SelectorEngine } from './types';
import type * as api from '../../types/types';
@@ -34,7 +35,7 @@ export class Selectors implements api.Selectors {
const source = await evaluationScript(script, undefined, false);
const selectorEngine: channels.SelectorEngine = { ...options, name, source };
for (const context of this._contextsForSelectors)
await context._channel.registerSelectorEngine({ selectorEngine }, undefined);
await context._channel.registerSelectorEngine({ selectorEngine }, kNoTimeout);
this._selectorEngines.push(selectorEngine);
}
@@ -43,7 +44,7 @@ export class Selectors implements api.Selectors {
setTestIdAttribute(attributeName);
for (const context of this._contextsForSelectors) {
context._options.testIdAttributeName = attributeName;
context._channel.setTestIdAttributeName({ testIdAttributeName: attributeName }, undefined).catch(() => {});
context._channel.setTestIdAttributeName({ testIdAttributeName: attributeName }, kNoTimeout).catch(() => {});
}
}
@@ -17,6 +17,7 @@
import { Readable } from 'stream';
import { ChannelOwner } from './channelOwner';
import { kNoTimeout } from './timeoutSettings';
import type * as channels from './channels';
@@ -43,7 +44,7 @@ class ReadableStreamImpl extends Readable {
}
override async _read() {
const result = await this._channel.read({ size: 1024 * 1024 }, undefined);
const result = await this._channel.read({ size: 1024 * 1024 }, kNoTimeout);
if (result.binary.byteLength)
this.push(result.binary);
else
@@ -52,7 +53,7 @@ class ReadableStreamImpl extends Readable {
override _destroy(error: Error | null, callback: (error: Error | null | undefined) => void): void {
// Stream might be destroyed after the connection was closed.
this._channel.close({}, undefined).catch(e => null);
this._channel.close({}, kNoTimeout).catch(e => null);
super._destroy(error, callback);
}
}
@@ -18,6 +18,13 @@
import { DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT, DEFAULT_PLAYWRIGHT_TIMEOUT } from '@isomorphic/time';
import { debugMode } from '@utils/debug';
import type * as channels from './channels';
type TimeoutInput = { timeout?: number, signal?: AbortSignal };
// Sentinel for internal calls that intentionally opt out of a deadline.
export const kNoTimeout: channels.TimeoutOptions = { signal: undefined, timeout: 0 };
export class TimeoutSettings {
private _parent: TimeoutSettings | undefined;
private _defaultTimeout: number | undefined;
@@ -43,7 +50,19 @@ export class TimeoutSettings {
return this._defaultTimeout;
}
navigationTimeout(options: { timeout?: number }): number {
navigationTimeout(options: TimeoutInput): channels.TimeoutOptions {
return { signal: options.signal, timeout: this._navigationTimeout(options) };
}
timeout(options: TimeoutInput): channels.TimeoutOptions {
return { signal: options.signal, timeout: this._timeout(options) };
}
launchTimeout(options: TimeoutInput): channels.TimeoutOptions {
return { signal: options.signal, timeout: this._launchTimeout(options) };
}
private _navigationTimeout(options: { timeout?: number }): number {
if (typeof options.timeout === 'number')
return options.timeout;
if (this._defaultNavigationTimeout !== undefined)
@@ -53,11 +72,11 @@ export class TimeoutSettings {
if (this._defaultTimeout !== undefined)
return this._defaultTimeout;
if (this._parent)
return this._parent.navigationTimeout(options);
return this._parent._navigationTimeout(options);
return DEFAULT_PLAYWRIGHT_TIMEOUT;
}
timeout(options: { timeout?: number }): number {
private _timeout(options: { timeout?: number }): number {
if (typeof options.timeout === 'number')
return options.timeout;
if (debugMode() === 'inspector')
@@ -65,17 +84,17 @@ export class TimeoutSettings {
if (this._defaultTimeout !== undefined)
return this._defaultTimeout;
if (this._parent)
return this._parent.timeout(options);
return this._parent._timeout(options);
return DEFAULT_PLAYWRIGHT_TIMEOUT;
}
launchTimeout(options: { timeout?: number }): number {
private _launchTimeout(options: { timeout?: number }): number {
if (typeof options.timeout === 'number')
return options.timeout;
if (debugMode() === 'inspector')
return 0;
if (this._parent)
return this._parent.launchTimeout(options);
return this._parent._launchTimeout(options);
return DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT;
}
}
+13 -12
View File
@@ -18,6 +18,7 @@ import { isRegExp, isString } from '@isomorphic/rtti';
import { Artifact } from './artifact';
import { ChannelOwner } from './channelOwner';
import { DisposableStub } from './disposable';
import { kNoTimeout } from './timeoutSettings';
import type { Page } from './page';
import type * as api from '../../types/types';
@@ -50,15 +51,15 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
snapshots: options.snapshots,
screenshots: options.screenshots,
live: options.live,
}, undefined);
const { traceName } = await this._channel.tracingStartChunk({ name: options.name, title: options.title }, undefined);
}, kNoTimeout);
const { traceName } = await this._channel.tracingStartChunk({ name: options.name, title: options.title }, kNoTimeout);
await this._startCollectingStacks(traceName, this._isLive);
});
}
async startChunk(options: { name?: string, title?: string } = {}) {
await this._wrapApiCall(async () => {
const { traceName } = await this._channel.tracingStartChunk(options, undefined);
const { traceName } = await this._channel.tracingStartChunk(options, kNoTimeout);
await this._startCollectingStacks(traceName, this._isLive);
});
}
@@ -66,12 +67,12 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
async group(name: string, options: { location?: { file: string, line?: number, column?: number } } = {}) {
if (options.location)
this._additionalSources.add(options.location.file);
await this._channel.tracingGroup({ name, location: options.location }, undefined);
await this._channel.tracingGroup({ name, location: options.location }, kNoTimeout);
return new DisposableStub(() => this.groupEnd());
}
async groupEnd() {
await this._channel.tracingGroupEnd({}, undefined);
await this._channel.tracingGroupEnd({}, kNoTimeout);
}
private async _startCollectingStacks(traceName: string, live: boolean) {
@@ -92,7 +93,7 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
async stop(options: { path?: string } = {}) {
await this._wrapApiCall(async () => {
await this._doStopChunk(options.path);
await this._channel.tracingStop({}, undefined);
await this._channel.tracingStop({}, kNoTimeout);
});
}
@@ -136,7 +137,7 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
harPath: isZip ? undefined : har,
resourcesDir: options.resourcesDir,
},
}, undefined);
}, kNoTimeout);
this._harRecorders.set(harId, { path: har, resourcesDir: options.resourcesDir });
return harId;
}
@@ -150,7 +151,7 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
const isZip = harParams.path.endsWith('.zip');
if (isLocal) {
const { entries } = await this._channel.harExport({ harId, mode: 'entries' }, undefined);
const { entries } = await this._channel.harExport({ harId, mode: 'entries' }, kNoTimeout);
if (!isZip) {
// Server wrote HAR and resources to the user's chosen paths.
return;
@@ -162,7 +163,7 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
return;
}
const { artifact: artifactChannel } = await this._channel.harExport({ harId, mode: 'archive' }, undefined);
const { artifact: artifactChannel } = await this._channel.harExport({ harId, mode: 'archive' }, kNoTimeout);
const artifact = Artifact.from(artifactChannel!);
if (isZip) {
await artifact.saveAs(harParams.path);
@@ -191,7 +192,7 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
if (!filePath) {
// Not interested in artifacts.
await this._channel.tracingStopChunk({ mode: 'discard' }, undefined);
await this._channel.tracingStopChunk({ mode: 'discard' }, kNoTimeout);
if (this._stacksId)
await this._connection.localUtils()!.traceDiscarded({ stacksId: this._stacksId });
return;
@@ -204,12 +205,12 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
const isLocal = !this._connection.isRemote();
if (isLocal) {
const result = await this._channel.tracingStopChunk({ mode: 'entries' }, undefined);
const result = await this._channel.tracingStopChunk({ mode: 'entries' }, kNoTimeout);
await localUtils.zip({ zipFile: filePath, entries: result.entries!, mode: 'write', stacksId: this._stacksId, includeSources: this._includeSources, additionalSources });
return;
}
const result = await this._channel.tracingStopChunk({ mode: 'archive' }, undefined);
const result = await this._channel.tracingStopChunk({ mode: 'archive' }, kNoTimeout);
// The artifact may be missing if the browser closed while stopping tracing.
if (!result.artifact) {
+1 -1
View File
@@ -147,4 +147,4 @@ export type AnnotateOptions = { duration?: number, position?: AnnotatePosition,
export type RemoteAddr = channels.RemoteAddr;
export type SecurityDetails = channels.SecurityDetails;
export type FrameExpectParams = Omit<channels.FrameExpectParams, 'selector'|'expression'|'expectedValue'> & { expectedValue?: any };
export type FrameExpectParams = Omit<channels.FrameExpectParams, 'selector'|'expression'|'expectedValue'> & { expectedValue?: any, timeout: number };
@@ -55,7 +55,7 @@ export class Waiter {
const owner = this._channelOwner;
owner._wrapApiCall(async apiZone => {
if (apiZone.internal || apiZone.reported) {
void owner._connection.sendMessageToServer(owner, '__waitInfo__', info, { internal: true });
void owner._connection.sendMessageToServer(owner, '__waitInfo__', info, { internal: true, timeout: 0 });
return;
}
apiZone.reported = true;
@@ -66,7 +66,7 @@ export class Waiter {
if (!apiZone.title)
apiZone.title = options.title;
owner._instrumentation.onApiCallBegin(apiZone, { type: owner._type, method: '__waitInfo__', params: info });
void owner._connection.sendMessageToServer(owner, '__waitInfo__', info, apiZone);
void owner._connection.sendMessageToServer(owner, '__waitInfo__', info, { ...apiZone, timeout: 0 });
}, options).catch(() => {});
}
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { kNoTimeout } from './timeoutSettings';
import type { Page } from './page';
import type * as api from '../../types/types';
@@ -27,24 +28,24 @@ export class WebStorage implements api.WebStorage {
}
async items(): Promise<Array<{ name: string, value: string }>> {
const { items } = await this._page._channel.webStorageItems({ kind: this._kind }, undefined);
const { items } = await this._page._channel.webStorageItems({ kind: this._kind }, kNoTimeout);
return items;
}
async getItem(name: string): Promise<string | null> {
const { value } = await this._page._channel.webStorageGetItem({ kind: this._kind, name }, undefined);
const { value } = await this._page._channel.webStorageGetItem({ kind: this._kind, name }, kNoTimeout);
return value ?? null;
}
async setItem(name: string, value: string): Promise<void> {
await this._page._channel.webStorageSetItem({ kind: this._kind, name, value }, undefined);
await this._page._channel.webStorageSetItem({ kind: this._kind, name, value }, kNoTimeout);
}
async removeItem(name: string): Promise<void> {
await this._page._channel.webStorageRemoveItem({ kind: this._kind, name }, undefined);
await this._page._channel.webStorageRemoveItem({ kind: this._kind, name }, kNoTimeout);
}
async clear(): Promise<void> {
await this._page._channel.webStorageClear({ kind: this._kind }, undefined);
await this._page._channel.webStorageClear({ kind: this._kind }, kNoTimeout);
}
}
@@ -20,7 +20,7 @@ import { ConsoleMessage } from './consoleMessage';
import { isTargetClosedError, TargetClosedError } from './errors';
import { Events } from './events';
import { JSHandle, assertMaxArguments, parseResult, serializeArgument } from './jsHandle';
import { TimeoutSettings } from './timeoutSettings';
import { TimeoutSettings, kNoTimeout } from './timeoutSettings';
import { Waiter } from './waiter';
import type { BrowserContext } from './browserContext';
@@ -28,7 +28,7 @@ import type { Page } from './page';
import type * as structs from '../../types/structs';
import type * as api from '../../types/types';
import type * as channels from './channels';
import type { TimeoutOptions, WaitForEventOptions } from './types';
import type { WaitForEventOptions } from './types';
export class Worker extends ChannelOwner<channels.WorkerChannel> implements api.Worker {
@@ -76,22 +76,21 @@ 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);
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return parseResult(result.value);
}
async evaluateHandle<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<structs.SmartHandle<R>> {
assertMaxArguments(arguments.length, 2);
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, undefined);
const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }, kNoTimeout);
return JSHandle.from(result.handle) as any as structs.SmartHandle<R>;
}
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
return await this._wrapApiCall(async () => {
const timeoutSettings = this._page?._timeoutSettings ?? this._context?._timeoutSettings ?? new TimeoutSettings();
const timeout = timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const { timeout, signal } = timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const signal = typeof optionsOrPredicate === 'function' ? undefined : (optionsOrPredicate as TimeoutOptions).signal;
const waiter = Waiter.createForEvent(this, event);
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
waiter.rejectOnSignal(signal);
@@ -106,7 +105,7 @@ export class Worker extends ChannelOwner<channels.WorkerChannel> implements api.
async _disconnect(options: { reason?: string } = {}): Promise<void> {
this._closeReason = options.reason;
try {
await this._channel.disconnect(options, undefined);
await this._channel.disconnect(options, kNoTimeout);
} catch (e) {
if (isTargetClosedError(e))
return;
@@ -17,6 +17,7 @@
import { Writable } from 'stream';
import { ChannelOwner } from './channelOwner';
import { kNoTimeout } from './timeoutSettings';
import type * as channels from './channels';
@@ -43,13 +44,13 @@ class WritableStreamImpl extends Writable {
}
override async _write(chunk: Buffer | string, encoding: BufferEncoding, callback: (error?: Error | null) => void) {
const error = await this._channel.write({ binary: typeof chunk === 'string' ? Buffer.from(chunk) : chunk }, undefined).catch(e => e);
const error = await this._channel.write({ binary: typeof chunk === 'string' ? Buffer.from(chunk) : chunk }, kNoTimeout).catch(e => e);
callback(error || null);
}
override async _final(callback: (error?: Error | null) => void) {
// Stream might be destroyed after the connection was closed.
const error = await this._channel.close({}, undefined).catch(e => e);
const error = await this._channel.close({}, kNoTimeout).catch(e => e);
callback(error || null);
}
}
+2 -74
View File
@@ -238,7 +238,6 @@ export type AndroidDeviceWebViewRemovedEvent = {
export type AndroidDeviceWaitParams = {
androidSelector: AndroidSelector,
state?: 'gone',
timeout: number,
};
export type AndroidDeviceWaitOptions = {
state?: 'gone',
@@ -247,7 +246,6 @@ export type AndroidDeviceWaitResult = void;
export type AndroidDeviceFillParams = {
androidSelector: AndroidSelector,
text: string,
timeout: number,
};
export type AndroidDeviceFillOptions = {
@@ -256,7 +254,6 @@ export type AndroidDeviceFillResult = void;
export type AndroidDeviceTapParams = {
androidSelector: AndroidSelector,
duration?: number,
timeout: number,
};
export type AndroidDeviceTapOptions = {
duration?: number,
@@ -266,7 +263,6 @@ export type AndroidDeviceDragParams = {
androidSelector: AndroidSelector,
dest: Point,
speed?: number,
timeout: number,
};
export type AndroidDeviceDragOptions = {
speed?: number,
@@ -276,7 +272,6 @@ export type AndroidDeviceFlingParams = {
androidSelector: AndroidSelector,
direction: 'up' | 'down' | 'left' | 'right',
speed?: number,
timeout: number,
};
export type AndroidDeviceFlingOptions = {
speed?: number,
@@ -284,7 +279,6 @@ export type AndroidDeviceFlingOptions = {
export type AndroidDeviceFlingResult = void;
export type AndroidDeviceLongTapParams = {
androidSelector: AndroidSelector,
timeout: number,
};
export type AndroidDeviceLongTapOptions = {
@@ -294,7 +288,6 @@ export type AndroidDevicePinchCloseParams = {
androidSelector: AndroidSelector,
percent: number,
speed?: number,
timeout: number,
};
export type AndroidDevicePinchCloseOptions = {
speed?: number,
@@ -304,7 +297,6 @@ export type AndroidDevicePinchOpenParams = {
androidSelector: AndroidSelector,
percent: number,
speed?: number,
timeout: number,
};
export type AndroidDevicePinchOpenOptions = {
speed?: number,
@@ -315,7 +307,6 @@ export type AndroidDeviceScrollParams = {
direction: 'up' | 'down' | 'left' | 'right',
percent: number,
speed?: number,
timeout: number,
};
export type AndroidDeviceScrollOptions = {
speed?: number,
@@ -326,7 +317,6 @@ export type AndroidDeviceSwipeParams = {
direction: 'up' | 'down' | 'left' | 'right',
percent: number,
speed?: number,
timeout: number,
};
export type AndroidDeviceSwipeOptions = {
speed?: number,
@@ -610,7 +600,6 @@ export type APIRequestContextFetchParams = {
jsonData?: string,
formData?: NameValue[],
multipartData?: FormField[],
timeout: number,
failOnStatusCode?: boolean,
ignoreHTTPSErrors?: boolean,
maxRedirects?: number,
@@ -1795,7 +1784,6 @@ export type BrowserTypeLaunchParams = {
handleSIGINT?: boolean,
handleSIGTERM?: boolean,
handleSIGHUP?: boolean,
timeout: number,
env?: NameValue[],
headless?: boolean,
proxy?: {
@@ -1849,7 +1837,6 @@ export type BrowserTypeLaunchPersistentContextParams = {
handleSIGINT?: boolean,
handleSIGTERM?: boolean,
handleSIGHUP?: boolean,
timeout: number,
env?: NameValue[],
headless?: boolean,
proxy?: {
@@ -2024,7 +2011,6 @@ export type BrowserTypeConnectOverCDPParams = {
endpointURL?: string,
headers?: NameValue[],
slowMo?: number,
timeout: number,
isLocal?: boolean,
noDefaults?: boolean,
artifactsDir?: string,
@@ -2045,7 +2031,6 @@ export type BrowserTypeConnectOverCDPResult = {
};
export type BrowserTypeConnectToWorkerParams = {
endpoint: string,
timeout: number,
};
export type BrowserTypeConnectToWorkerOptions = {
@@ -2086,7 +2071,6 @@ export type ElectronLaunchParams = {
chromiumSandbox?: boolean,
cwd?: string,
env?: NameValue[],
timeout: number,
acceptDownloads?: 'accept' | 'deny' | 'internal-browser-default',
bypassCSP?: boolean,
colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override',
@@ -2376,7 +2360,6 @@ export type FrameAriaSnapshotParams = {
selector?: string,
depth?: number,
boxes?: boolean,
timeout: number,
};
export type FrameAriaSnapshotOptions = {
mode?: 'ai' | 'default',
@@ -2390,7 +2373,6 @@ export type FrameAriaSnapshotResult = {
export type FrameBlurParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameBlurOptions = {
strict?: boolean,
@@ -2402,7 +2384,6 @@ export type FrameCheckParams = {
force?: boolean,
scroll?: 'auto' | 'none',
position?: Point,
timeout: number,
trial?: boolean,
};
export type FrameCheckOptions = {
@@ -2424,7 +2405,6 @@ export type FrameClickParams = {
delay?: number,
button?: 'left' | 'right' | 'middle',
clickCount?: number,
timeout: number,
trial?: boolean,
steps?: number,
};
@@ -2452,7 +2432,6 @@ export type FrameDragAndDropParams = {
target: string,
force?: boolean,
scroll?: 'auto' | 'none',
timeout: number,
trial?: boolean,
sourcePosition?: Point,
targetPosition?: Point,
@@ -2484,7 +2463,6 @@ export type FrameDropParams = {
mimeType: string,
value: string,
}[],
timeout: number,
};
export type FrameDropOptions = {
strict?: boolean,
@@ -2511,7 +2489,6 @@ export type FrameDblclickParams = {
position?: Point,
delay?: number,
button?: 'left' | 'right' | 'middle',
timeout: number,
trial?: boolean,
steps?: number,
};
@@ -2532,7 +2509,6 @@ export type FrameDispatchEventParams = {
strict?: boolean,
type: string,
eventInit: SerializedArgument,
timeout: number,
};
export type FrameDispatchEventOptions = {
strict?: boolean,
@@ -2565,7 +2541,6 @@ export type FrameFillParams = {
strict?: boolean,
value: string,
force?: boolean,
timeout: number,
};
export type FrameFillOptions = {
strict?: boolean,
@@ -2575,7 +2550,6 @@ export type FrameFillResult = void;
export type FrameFocusParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameFocusOptions = {
strict?: boolean,
@@ -2614,7 +2588,6 @@ export type FrameGetAttributeParams = {
selector: string,
strict?: boolean,
name: string,
timeout: number,
};
export type FrameGetAttributeOptions = {
strict?: boolean,
@@ -2624,7 +2597,6 @@ export type FrameGetAttributeResult = {
};
export type FrameGotoParams = {
url: string,
timeout: number,
waitUntil?: LifecycleEvent,
referer?: string,
};
@@ -2642,7 +2614,6 @@ export type FrameHoverParams = {
scroll?: 'auto' | 'none',
modifiers?: ('Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift')[],
position?: Point,
timeout: number,
trial?: boolean,
};
export type FrameHoverOptions = {
@@ -2657,7 +2628,6 @@ export type FrameHoverResult = void;
export type FrameInnerHTMLParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameInnerHTMLOptions = {
strict?: boolean,
@@ -2668,7 +2638,6 @@ export type FrameInnerHTMLResult = {
export type FrameInnerTextParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameInnerTextOptions = {
strict?: boolean,
@@ -2679,7 +2648,6 @@ export type FrameInnerTextResult = {
export type FrameInputValueParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameInputValueOptions = {
strict?: boolean,
@@ -2690,7 +2658,6 @@ export type FrameInputValueResult = {
export type FrameIsCheckedParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameIsCheckedOptions = {
strict?: boolean,
@@ -2701,7 +2668,6 @@ export type FrameIsCheckedResult = {
export type FrameIsDisabledParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameIsDisabledOptions = {
strict?: boolean,
@@ -2712,7 +2678,6 @@ export type FrameIsDisabledResult = {
export type FrameIsEnabledParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameIsEnabledOptions = {
strict?: boolean,
@@ -2743,7 +2708,6 @@ export type FrameIsVisibleResult = {
export type FrameIsEditableParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameIsEditableOptions = {
strict?: boolean,
@@ -2757,7 +2721,6 @@ export type FramePressParams = {
key: string,
delay?: number,
noWaitAfter?: boolean,
timeout: number,
};
export type FramePressOptions = {
strict?: boolean,
@@ -2804,7 +2767,6 @@ export type FrameSelectOptionParams = {
index?: number,
}[],
force?: boolean,
timeout: number,
};
export type FrameSelectOptionOptions = {
strict?: boolean,
@@ -2822,7 +2784,6 @@ export type FrameSelectOptionResult = {
};
export type FrameSetContentParams = {
html: string,
timeout: number,
waitUntil?: LifecycleEvent,
};
export type FrameSetContentOptions = {
@@ -2841,7 +2802,6 @@ export type FrameSetInputFilesParams = {
directoryStream?: WritableStreamChannel,
localPaths?: string[],
streams?: WritableStreamChannel[],
timeout: number,
};
export type FrameSetInputFilesOptions = {
strict?: boolean,
@@ -2863,7 +2823,6 @@ export type FrameTapParams = {
scroll?: 'auto' | 'none',
modifiers?: ('Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift')[],
position?: Point,
timeout: number,
trial?: boolean,
};
export type FrameTapOptions = {
@@ -2878,7 +2837,6 @@ export type FrameTapResult = void;
export type FrameTextContentParams = {
selector: string,
strict?: boolean,
timeout: number,
};
export type FrameTextContentOptions = {
strict?: boolean,
@@ -2896,7 +2854,6 @@ export type FrameTypeParams = {
strict?: boolean,
text: string,
delay?: number,
timeout: number,
};
export type FrameTypeOptions = {
strict?: boolean,
@@ -2909,7 +2866,6 @@ export type FrameUncheckParams = {
force?: boolean,
scroll?: 'auto' | 'none',
position?: Point,
timeout: number,
trial?: boolean,
};
export type FrameUncheckOptions = {
@@ -2931,7 +2887,6 @@ export type FrameWaitForFunctionParams = {
expression: string,
isFunction?: boolean,
arg: SerializedArgument,
timeout: number,
pollingInterval?: number,
selector?: string,
strict?: boolean,
@@ -2948,7 +2903,6 @@ export type FrameWaitForFunctionResult = {
export type FrameWaitForSelectorParams = {
selector: string,
strict?: boolean,
timeout: number,
state?: 'attached' | 'detached' | 'visible' | 'hidden',
omitReturnValue?: boolean,
};
@@ -2970,7 +2924,6 @@ export type FrameExpectParams = {
expectedValue?: SerializedArgument,
useInnerText?: boolean,
isNot: boolean,
timeout: number,
};
export type FrameExpectOptions = {
selector?: string,
@@ -3145,7 +3098,6 @@ export type ElementHandleCheckParams = {
force?: boolean,
scroll?: 'auto' | 'none',
position?: Point,
timeout: number,
trial?: boolean,
};
export type ElementHandleCheckOptions = {
@@ -3164,7 +3116,6 @@ export type ElementHandleClickParams = {
delay?: number,
button?: 'left' | 'right' | 'middle',
clickCount?: number,
timeout: number,
trial?: boolean,
steps?: number,
};
@@ -3193,7 +3144,6 @@ export type ElementHandleDblclickParams = {
position?: Point,
delay?: number,
button?: 'left' | 'right' | 'middle',
timeout: number,
trial?: boolean,
steps?: number,
};
@@ -3219,7 +3169,6 @@ export type ElementHandleDispatchEventResult = void;
export type ElementHandleFillParams = {
value: string,
force?: boolean,
timeout: number,
};
export type ElementHandleFillOptions = {
force?: boolean,
@@ -3242,7 +3191,6 @@ export type ElementHandleHoverParams = {
scroll?: 'auto' | 'none',
modifiers?: ('Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift')[],
position?: Point,
timeout: number,
trial?: boolean,
};
export type ElementHandleHoverOptions = {
@@ -3306,7 +3254,6 @@ export type ElementHandleOwnerFrameResult = {
export type ElementHandlePressParams = {
key: string,
delay?: number,
timeout: number,
noWaitAfter?: boolean,
};
export type ElementHandlePressOptions = {
@@ -3334,7 +3281,6 @@ export type ElementHandleQuerySelectorAllResult = {
elements: ElementHandleChannel[],
};
export type ElementHandleScreenshotParams = {
timeout: number,
type?: 'png' | 'jpeg' | 'webp',
quality?: number,
omitBackground?: boolean,
@@ -3365,12 +3311,8 @@ export type ElementHandleScreenshotOptions = {
export type ElementHandleScreenshotResult = {
binary: Binary,
};
export type ElementHandleScrollIntoViewIfNeededParams = {
timeout: number,
};
export type ElementHandleScrollIntoViewIfNeededOptions = {
};
export type ElementHandleScrollIntoViewIfNeededParams = {};
export type ElementHandleScrollIntoViewIfNeededOptions = {};
export type ElementHandleScrollIntoViewIfNeededResult = void;
export type ElementHandleSelectOptionParams = {
elements?: ElementHandleChannel[],
@@ -3381,7 +3323,6 @@ export type ElementHandleSelectOptionParams = {
index?: number,
}[],
force?: boolean,
timeout: number,
};
export type ElementHandleSelectOptionOptions = {
elements?: ElementHandleChannel[],
@@ -3398,7 +3339,6 @@ export type ElementHandleSelectOptionResult = {
};
export type ElementHandleSelectTextParams = {
force?: boolean,
timeout: number,
};
export type ElementHandleSelectTextOptions = {
force?: boolean,
@@ -3414,7 +3354,6 @@ export type ElementHandleSetInputFilesParams = {
directoryStream?: WritableStreamChannel,
localPaths?: string[],
streams?: WritableStreamChannel[],
timeout: number,
};
export type ElementHandleSetInputFilesOptions = {
payloads?: {
@@ -3433,7 +3372,6 @@ export type ElementHandleTapParams = {
scroll?: 'auto' | 'none',
modifiers?: ('Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift')[],
position?: Point,
timeout: number,
trial?: boolean,
};
export type ElementHandleTapOptions = {
@@ -3452,7 +3390,6 @@ export type ElementHandleTextContentResult = {
export type ElementHandleTypeParams = {
text: string,
delay?: number,
timeout: number,
};
export type ElementHandleTypeOptions = {
delay?: number,
@@ -3462,7 +3399,6 @@ export type ElementHandleUncheckParams = {
force?: boolean,
scroll?: 'auto' | 'none',
position?: Point,
timeout: number,
trial?: boolean,
};
export type ElementHandleUncheckOptions = {
@@ -3474,7 +3410,6 @@ export type ElementHandleUncheckOptions = {
export type ElementHandleUncheckResult = void;
export type ElementHandleWaitForElementStateParams = {
state: 'visible' | 'hidden' | 'stable' | 'enabled' | 'disabled' | 'editable',
timeout: number,
};
export type ElementHandleWaitForElementStateOptions = {
@@ -3483,7 +3418,6 @@ export type ElementHandleWaitForElementStateResult = void;
export type ElementHandleWaitForSelectorParams = {
selector: string,
strict?: boolean,
timeout: number,
state?: 'attached' | 'detached' | 'visible' | 'hidden',
};
export type ElementHandleWaitForSelectorOptions = {
@@ -3596,7 +3530,6 @@ export type LocalUtilsConnectParams = {
headers?: any,
exposeNetwork?: string,
slowMo?: number,
timeout: number,
socksProxyRedirectPortForTest?: number,
};
export type LocalUtilsConnectOptions = {
@@ -4124,7 +4057,6 @@ export type PageExposeBindingResult = {
disposable: DisposableChannel,
};
export type PageGoBackParams = {
timeout: number,
waitUntil?: LifecycleEvent,
};
export type PageGoBackOptions = {
@@ -4134,7 +4066,6 @@ export type PageGoBackResult = {
response?: ResponseChannel,
};
export type PageGoForwardParams = {
timeout: number,
waitUntil?: LifecycleEvent,
};
export type PageGoForwardOptions = {
@@ -4172,7 +4103,6 @@ export type PageUnregisterLocatorHandlerOptions = {
};
export type PageUnregisterLocatorHandlerResult = void;
export type PageReloadParams = {
timeout: number,
waitUntil?: LifecycleEvent,
};
export type PageReloadOptions = {
@@ -4183,7 +4113,6 @@ export type PageReloadResult = {
};
export type PageExpectScreenshotParams = {
expected?: Binary,
timeout: number,
isNot: boolean,
locator?: {
frame: FrameChannel,
@@ -4243,7 +4172,6 @@ export type PageExpectScreenshotErrorDetails = {
log?: string[],
};
export type PageScreenshotParams = {
timeout: number,
type?: 'png' | 'jpeg' | 'webp',
quality?: number,
fullPage?: boolean,
@@ -358,6 +358,11 @@ export class DispatcherConnection {
params: params || {},
log: [],
};
// TODO(skn0tt): promote to top-level metadata instead of smuggling through params.
if (validMetadata.timeout)
callMetadata.params = { ...callMetadata.params, timeout: validMetadata.timeout };
const controller = dispatcher.createProgressController(callMetadata);
this._activeProgressControllers.set(callMetadata.id, controller);
@@ -367,7 +372,7 @@ export class DispatcherConnection {
// If the dispatcher has been disposed while running the instrumentation call, error out.
if (this._dispatcherByGuid.get(guid) !== dispatcher)
throw new TargetClosedError(sdkObject.closeReason());
const result = await controller.run(progress => (dispatcher as any)[method](validParams, progress), validParams?.timeout);
const result = await controller.run(progress => (dispatcher as any)[method](validParams, progress), validMetadata.timeout);
const validator = findValidator(dispatcher._type, method, 'Result');
response.result = validator(result, '', this._validatorToWireContext());
callMetadata.result = result;
@@ -276,7 +276,7 @@ export class FrameDispatcher extends Dispatcher<Frame, channels.FrameChannel, Br
}
async expect(params: channels.FrameExpectParams, progress: Progress): Promise<channels.FrameExpectResult> {
progress.log(`${renderTitleForCall(progress.metadata)}${params.timeout ? ` with timeout ${params.timeout}ms` : ''}`);
progress.log(`${renderTitleForCall(progress.metadata)}${progress.timeout ? ` with timeout ${progress.timeout}ms` : ''}`);
const expectedValue = params.expectedValue ? parseArgument(params.expectedValue) : undefined;
try {
await this._frame.expect(progress, params.selector, { ...params, expectedValue });
@@ -233,7 +233,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
frame: (params.locator.frame as FrameDispatcher)._object,
selector: params.locator.selector,
} : undefined;
progress.log(`${renderTitleForCall(progress.metadata)}${params.timeout ? ` with timeout ${params.timeout}ms` : ''}`);
progress.log(`${renderTitleForCall(progress.metadata)}${progress.timeout ? ` with timeout ${progress.timeout}ms` : ''}`);
return await this._page.expectScreenshot(progress, {
...params,
locator,
@@ -120,7 +120,6 @@ type EmulatedMedia = {
};
type ExpectScreenshotOptions = ImageComparatorOptions & ScreenshotOptions & {
timeout: number,
expected?: Buffer,
isNot?: boolean,
locator?: {
@@ -44,17 +44,17 @@ export class SocksInterceptor {
this._ids.add(id);
const validator = findValidator('SocksSupport', prop, 'Params');
params = validator(params, '', { tChannelImpl: tChannelForSocks, binary: 'toBase64', isUnderTest });
transport.send({ id, guid: this._socksSupportObjectGuid, method: prop, params, metadata: { stack: [], apiName: '', internal: true } } as any);
transport.send({ id, guid: this._socksSupportObjectGuid, method: prop, params, metadata: { stack: [], apiName: '', internal: true, timeout: 0 } } as any);
} catch (e) {
}
};
},
}) as channels.SocksSupportChannel & EventEmitter;
this._handler.on(socks.SocksProxyHandler.Events.SocksConnected, (payload: socks.SocksSocketConnectedPayload) => this._channel.socksConnected(payload, undefined));
this._handler.on(socks.SocksProxyHandler.Events.SocksData, (payload: socks.SocksSocketDataPayload) => this._channel.socksData(payload, undefined));
this._handler.on(socks.SocksProxyHandler.Events.SocksError, (payload: socks.SocksSocketErrorPayload) => this._channel.socksError(payload, undefined));
this._handler.on(socks.SocksProxyHandler.Events.SocksFailed, (payload: socks.SocksSocketFailedPayload) => this._channel.socksFailed(payload, undefined));
this._handler.on(socks.SocksProxyHandler.Events.SocksEnd, (payload: socks.SocksSocketEndPayload) => this._channel.socksEnd(payload, undefined));
this._handler.on(socks.SocksProxyHandler.Events.SocksConnected, (payload: socks.SocksSocketConnectedPayload) => this._channel.socksConnected(payload, { signal: undefined, timeout: 0 }));
this._handler.on(socks.SocksProxyHandler.Events.SocksData, (payload: socks.SocksSocketDataPayload) => this._channel.socksData(payload, { signal: undefined, timeout: 0 }));
this._handler.on(socks.SocksProxyHandler.Events.SocksError, (payload: socks.SocksSocketErrorPayload) => this._channel.socksError(payload, { signal: undefined, timeout: 0 }));
this._handler.on(socks.SocksProxyHandler.Events.SocksFailed, (payload: socks.SocksSocketFailedPayload) => this._channel.socksFailed(payload, { signal: undefined, timeout: 0 }));
this._handler.on(socks.SocksProxyHandler.Events.SocksEnd, (payload: socks.SocksSocketEndPayload) => this._channel.socksEnd(payload, { signal: undefined, timeout: 0 }));
this._channel.on('socksRequested', payload => this._handler.socketRequested(payload));
this._channel.on('socksClosed', payload => this._handler.socketClosed(payload));
this._channel.on('socksData', payload => this._handler.sendSocketData(payload));
-10
View File
@@ -62,21 +62,18 @@ AndroidDevice:
type: enum?
literals:
- gone
timeout: float
fill:
title: Fill "{text}"
parameters:
androidSelector: AndroidSelector
text: string
timeout: float
tap:
title: Tap
parameters:
androidSelector: AndroidSelector
duration: float?
timeout: float
drag:
title: Drag
@@ -84,7 +81,6 @@ AndroidDevice:
androidSelector: AndroidSelector
dest: Point
speed: float?
timeout: float
fling:
title: Fling
@@ -98,13 +94,11 @@ AndroidDevice:
- left
- right
speed: float?
timeout: float
longTap:
title: Long tap
parameters:
androidSelector: AndroidSelector
timeout: float
pinchClose:
title: Pinch close
@@ -112,7 +106,6 @@ AndroidDevice:
androidSelector: AndroidSelector
percent: float
speed: float?
timeout: float
pinchOpen:
title: Pinch open
@@ -120,7 +113,6 @@ AndroidDevice:
androidSelector: AndroidSelector
percent: float
speed: float?
timeout: float
scroll:
title: Scroll
@@ -135,7 +127,6 @@ AndroidDevice:
- right
percent: float
speed: float?
timeout: float
swipe:
title: Swipe
@@ -150,7 +141,6 @@ AndroidDevice:
- right
percent: float
speed: float?
timeout: float
info:
internal: true
-1
View File
@@ -40,7 +40,6 @@ APIRequestContext:
multipartData:
type: array?
items: FormField
timeout: float
failOnStatusCode: boolean?
ignoreHTTPSErrors: boolean?
maxRedirects: int?
-2
View File
@@ -48,7 +48,6 @@ BrowserType:
type: array?
items: NameValue
slowMo: float?
timeout: float
isLocal: boolean?
noDefaults: boolean?
artifactsDir: string?
@@ -61,6 +60,5 @@ BrowserType:
title: Connect to worker
parameters:
endpoint: string
timeout: float
returns:
worker: Worker
+1
View File
@@ -25,6 +25,7 @@ Metadata:
internal: boolean?
# Test runner step id.
stepId: string?
timeout: float?
ClientSideCallMetadata:
type: object
-1
View File
@@ -28,7 +28,6 @@ Electron:
env:
type: array?
items: NameValue
timeout: float
acceptDownloads:
type: enum?
literals:
-31
View File
@@ -87,7 +87,6 @@ Frame:
selector: string?
depth: int?
boxes: boolean?
timeout: float
returns:
snapshot: string
@@ -96,7 +95,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
flags:
slowMo: true
snapshot: true
@@ -114,7 +112,6 @@ Frame:
- auto
- none
position: Point?
timeout: float
trial: boolean?
flags:
slowMo: true
@@ -154,7 +151,6 @@ Frame:
- right
- middle
clickCount: int?
timeout: float
trial: boolean?
steps: int?
flags:
@@ -183,7 +179,6 @@ Frame:
literals:
- auto
- none
timeout: float
trial: boolean?
sourcePosition: Point?
targetPosition: Point?
@@ -224,7 +219,6 @@ Frame:
properties:
mimeType: string
value: string
timeout: float
flags:
slowMo: true
snapshot: true
@@ -261,7 +255,6 @@ Frame:
- left
- right
- middle
timeout: float
trial: boolean?
steps: int?
flags:
@@ -278,7 +271,6 @@ Frame:
strict: boolean?
type: string
eventInit: SerializedArgument
timeout: float
flags:
slowMo: true
snapshot: true
@@ -315,7 +307,6 @@ Frame:
strict: boolean?
value: string
force: boolean?
timeout: float
flags:
slowMo: true
snapshot: true
@@ -328,7 +319,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
flags:
slowMo: true
snapshot: true
@@ -365,7 +355,6 @@ Frame:
selector: string
strict: boolean?
name: string
timeout: float
returns:
value: string?
flags:
@@ -376,7 +365,6 @@ Frame:
title: Navigate to "{url}"
parameters:
url: string
timeout: float
waitUntil: LifecycleEvent?
referer: string?
returns:
@@ -408,7 +396,6 @@ Frame:
- Meta
- Shift
position: Point?
timeout: float
trial: boolean?
flags:
slowMo: true
@@ -423,7 +410,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
returns:
value: string
flags:
@@ -436,7 +422,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
returns:
value: string
flags:
@@ -449,7 +434,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
returns:
value: string
flags:
@@ -462,7 +446,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
returns:
value: boolean
flags:
@@ -475,7 +458,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
returns:
value: boolean
flags:
@@ -488,7 +470,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
returns:
value: boolean
flags:
@@ -527,7 +508,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
returns:
value: boolean
flags:
@@ -542,7 +522,6 @@ Frame:
key: string
delay: float?
noWaitAfter: boolean?
timeout: float
flags:
slowMo: true
snapshot: true
@@ -599,7 +578,6 @@ Frame:
label: string?
index: int?
force: boolean?
timeout: float
returns:
values:
type: array
@@ -615,7 +593,6 @@ Frame:
title: Set content
parameters:
html: string
timeout: float
waitUntil: LifecycleEvent?
flags:
snapshot: true
@@ -643,7 +620,6 @@ Frame:
streams:
type: array?
items: WritableStream
timeout: float
flags:
slowMo: true
snapshot: true
@@ -673,7 +649,6 @@ Frame:
- Meta
- Shift
position: Point?
timeout: float
trial: boolean?
flags:
slowMo: true
@@ -688,7 +663,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
returns:
value: string?
flags:
@@ -708,7 +682,6 @@ Frame:
strict: boolean?
text: string
delay: float?
timeout: float
flags:
slowMo: true
snapshot: true
@@ -728,7 +701,6 @@ Frame:
- auto
- none
position: Point?
timeout: float
trial: boolean?
flags:
slowMo: true
@@ -750,7 +722,6 @@ Frame:
expression: string
isFunction: boolean?
arg: SerializedArgument
timeout: float
# When present, polls on interval. Otherwise, polls on raf.
pollingInterval: float?
# When present, first argument is the matched element.
@@ -768,7 +739,6 @@ Frame:
parameters:
selector: string
strict: boolean?
timeout: float
state:
type: enum?
literals:
@@ -800,7 +770,6 @@ Frame:
expectedValue: SerializedArgument?
useInnerText: boolean?
isNot: boolean
timeout: float
errorDetails:
received:
type: object?
-17
View File
@@ -131,7 +131,6 @@ ElementHandle:
- auto
- none
position: Point?
timeout: float
trial: boolean?
flags:
slowMo: true
@@ -169,7 +168,6 @@ ElementHandle:
- right
- middle
clickCount: int?
timeout: float
trial: boolean?
steps: int?
flags:
@@ -212,7 +210,6 @@ ElementHandle:
- left
- right
- middle
timeout: float
trial: boolean?
steps: int?
flags:
@@ -237,7 +234,6 @@ ElementHandle:
parameters:
value: string
force: boolean?
timeout: float
flags:
slowMo: true
snapshot: true
@@ -283,7 +279,6 @@ ElementHandle:
- Meta
- Shift
position: Point?
timeout: float
trial: boolean?
flags:
slowMo: true
@@ -384,7 +379,6 @@ ElementHandle:
parameters:
key: string
delay: float?
timeout: float
noWaitAfter: boolean?
flags:
slowMo: true
@@ -417,7 +411,6 @@ ElementHandle:
screenshot:
title: Screenshot
parameters:
timeout: float
type:
type: enum?
literals:
@@ -434,8 +427,6 @@ ElementHandle:
scrollIntoViewIfNeeded:
title: Scroll into view
parameters:
timeout: float
flags:
slowMo: true
snapshot: true
@@ -457,7 +448,6 @@ ElementHandle:
label: string?
index: int?
force: boolean?
timeout: float
returns:
values:
type: array
@@ -473,7 +463,6 @@ ElementHandle:
title: Select text
parameters:
force: boolean?
timeout: float
flags:
slowMo: true
snapshot: true
@@ -499,7 +488,6 @@ ElementHandle:
streams:
type: array?
items: WritableStream
timeout: float
flags:
slowMo: true
snapshot: true
@@ -527,7 +515,6 @@ ElementHandle:
- Meta
- Shift
position: Point?
timeout: float
trial: boolean?
flags:
slowMo: true
@@ -550,7 +537,6 @@ ElementHandle:
parameters:
text: string
delay: float?
timeout: float
flags:
slowMo: true
snapshot: true
@@ -568,7 +554,6 @@ ElementHandle:
- auto
- none
position: Point?
timeout: float
trial: boolean?
flags:
slowMo: true
@@ -589,7 +574,6 @@ ElementHandle:
- enabled
- disabled
- editable
timeout: float
flags:
snapshot: true
pause: true
@@ -599,7 +583,6 @@ ElementHandle:
parameters:
selector: string
strict: boolean?
timeout: float
state:
type: enum?
literals:
-1
View File
@@ -120,7 +120,6 @@ LocalUtils:
headers: json?
exposeNetwork: string?
slowMo: float?
timeout: float
socksProxyRedirectPortForTest: int?
returns:
pipe: JsonPipe
-1
View File
@@ -76,7 +76,6 @@ LaunchOptions:
handleSIGINT: boolean?
handleSIGTERM: boolean?
handleSIGHUP: boolean?
timeout: float
env:
type: array?
items: NameValue
-5
View File
@@ -113,7 +113,6 @@ Page:
goBack:
title: Go back
parameters:
timeout: float
waitUntil: LifecycleEvent?
returns:
response: Response?
@@ -125,7 +124,6 @@ Page:
goForward:
title: Go forward
parameters:
timeout: float
waitUntil: LifecycleEvent?
returns:
response: Response?
@@ -160,7 +158,6 @@ Page:
reload:
title: Reload
parameters:
timeout: float
waitUntil: LifecycleEvent?
returns:
response: Response?
@@ -173,7 +170,6 @@ Page:
title: Expect screenshot
parameters:
expected: binary?
timeout: float
isNot: boolean
locator:
type: object?
@@ -210,7 +206,6 @@ Page:
screenshot:
title: Screenshot
parameters:
timeout: float
type:
type: enum?
literals:
+1
View File
@@ -90,6 +90,7 @@ export type Metadata = {
title?: string,
internal?: boolean,
stepId?: string,
timeout?: number,
};
export type ClientSideCallMetadata = {
+2 -71
View File
@@ -54,52 +54,44 @@ scheme.AndroidDeviceWebViewRemovedEvent = tObject({
scheme.AndroidDeviceWaitParams = tObject({
androidSelector: tType('AndroidSelector'),
state: tOptional(tEnum(['gone'])),
timeout: tFloat,
});
scheme.AndroidDeviceWaitResult = tOptional(tObject({}));
scheme.AndroidDeviceFillParams = tObject({
androidSelector: tType('AndroidSelector'),
text: tString,
timeout: tFloat,
});
scheme.AndroidDeviceFillResult = tOptional(tObject({}));
scheme.AndroidDeviceTapParams = tObject({
androidSelector: tType('AndroidSelector'),
duration: tOptional(tFloat),
timeout: tFloat,
});
scheme.AndroidDeviceTapResult = tOptional(tObject({}));
scheme.AndroidDeviceDragParams = tObject({
androidSelector: tType('AndroidSelector'),
dest: tType('Point'),
speed: tOptional(tFloat),
timeout: tFloat,
});
scheme.AndroidDeviceDragResult = tOptional(tObject({}));
scheme.AndroidDeviceFlingParams = tObject({
androidSelector: tType('AndroidSelector'),
direction: tEnum(['up', 'down', 'left', 'right']),
speed: tOptional(tFloat),
timeout: tFloat,
});
scheme.AndroidDeviceFlingResult = tOptional(tObject({}));
scheme.AndroidDeviceLongTapParams = tObject({
androidSelector: tType('AndroidSelector'),
timeout: tFloat,
});
scheme.AndroidDeviceLongTapResult = tOptional(tObject({}));
scheme.AndroidDevicePinchCloseParams = tObject({
androidSelector: tType('AndroidSelector'),
percent: tFloat,
speed: tOptional(tFloat),
timeout: tFloat,
});
scheme.AndroidDevicePinchCloseResult = tOptional(tObject({}));
scheme.AndroidDevicePinchOpenParams = tObject({
androidSelector: tType('AndroidSelector'),
percent: tFloat,
speed: tOptional(tFloat),
timeout: tFloat,
});
scheme.AndroidDevicePinchOpenResult = tOptional(tObject({}));
scheme.AndroidDeviceScrollParams = tObject({
@@ -107,7 +99,6 @@ scheme.AndroidDeviceScrollParams = tObject({
direction: tEnum(['up', 'down', 'left', 'right']),
percent: tFloat,
speed: tOptional(tFloat),
timeout: tFloat,
});
scheme.AndroidDeviceScrollResult = tOptional(tObject({}));
scheme.AndroidDeviceSwipeParams = tObject({
@@ -115,7 +106,6 @@ scheme.AndroidDeviceSwipeParams = tObject({
direction: tEnum(['up', 'down', 'left', 'right']),
percent: tFloat,
speed: tOptional(tFloat),
timeout: tFloat,
});
scheme.AndroidDeviceSwipeResult = tOptional(tObject({}));
scheme.AndroidDeviceInfoParams = tObject({
@@ -317,7 +307,6 @@ scheme.APIRequestContextFetchParams = tObject({
jsonData: tOptional(tString),
formData: tOptional(tArray(tType('NameValue'))),
multipartData: tOptional(tArray(tType('FormField'))),
timeout: tFloat,
failOnStatusCode: tOptional(tBoolean),
ignoreHTTPSErrors: tOptional(tBoolean),
maxRedirects: tOptional(tInt),
@@ -988,7 +977,6 @@ scheme.BrowserTypeLaunchParams = tObject({
handleSIGINT: tOptional(tBoolean),
handleSIGTERM: tOptional(tBoolean),
handleSIGHUP: tOptional(tBoolean),
timeout: tFloat,
env: tOptional(tArray(tType('NameValue'))),
headless: tOptional(tBoolean),
proxy: tOptional(tObject({
@@ -1017,7 +1005,6 @@ scheme.BrowserTypeLaunchPersistentContextParams = tObject({
handleSIGINT: tOptional(tBoolean),
handleSIGTERM: tOptional(tBoolean),
handleSIGHUP: tOptional(tBoolean),
timeout: tFloat,
env: tOptional(tArray(tType('NameValue'))),
headless: tOptional(tBoolean),
proxy: tOptional(tObject({
@@ -1105,7 +1092,6 @@ scheme.BrowserTypeConnectOverCDPParams = tObject({
endpointURL: tOptional(tString),
headers: tOptional(tArray(tType('NameValue'))),
slowMo: tOptional(tFloat),
timeout: tFloat,
isLocal: tOptional(tBoolean),
noDefaults: tOptional(tBoolean),
artifactsDir: tOptional(tString),
@@ -1117,7 +1103,6 @@ scheme.BrowserTypeConnectOverCDPResult = tObject({
});
scheme.BrowserTypeConnectToWorkerParams = tObject({
endpoint: tString,
timeout: tFloat,
});
scheme.BrowserTypeConnectToWorkerResult = tObject({
worker: tChannel(['Worker']),
@@ -1131,6 +1116,7 @@ scheme.Metadata = tObject({
title: tOptional(tString),
internal: tOptional(tBoolean),
stepId: tOptional(tString),
timeout: tOptional(tFloat),
});
scheme.ClientSideCallMetadata = tObject({
id: tInt,
@@ -1154,7 +1140,6 @@ scheme.ElectronLaunchParams = tObject({
chromiumSandbox: tOptional(tBoolean),
cwd: tOptional(tString),
env: tOptional(tArray(tType('NameValue'))),
timeout: tFloat,
acceptDownloads: tOptional(tEnum(['accept', 'deny', 'internal-browser-default'])),
bypassCSP: tOptional(tBoolean),
colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference', 'no-override'])),
@@ -1294,7 +1279,6 @@ scheme.FrameAriaSnapshotParams = tObject({
selector: tOptional(tString),
depth: tOptional(tInt),
boxes: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameAriaSnapshotResult = tObject({
snapshot: tString,
@@ -1302,7 +1286,6 @@ scheme.FrameAriaSnapshotResult = tObject({
scheme.FrameBlurParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameBlurResult = tOptional(tObject({}));
scheme.FrameCheckParams = tObject({
@@ -1311,7 +1294,6 @@ scheme.FrameCheckParams = tObject({
force: tOptional(tBoolean),
scroll: tOptional(tEnum(['auto', 'none'])),
position: tOptional(tType('Point')),
timeout: tFloat,
trial: tOptional(tBoolean),
});
scheme.FrameCheckResult = tOptional(tObject({}));
@@ -1326,7 +1308,6 @@ scheme.FrameClickParams = tObject({
delay: tOptional(tFloat),
button: tOptional(tEnum(['left', 'right', 'middle'])),
clickCount: tOptional(tInt),
timeout: tFloat,
trial: tOptional(tBoolean),
steps: tOptional(tInt),
});
@@ -1340,7 +1321,6 @@ scheme.FrameDragAndDropParams = tObject({
target: tString,
force: tOptional(tBoolean),
scroll: tOptional(tEnum(['auto', 'none'])),
timeout: tFloat,
trial: tOptional(tBoolean),
sourcePosition: tOptional(tType('Point')),
targetPosition: tOptional(tType('Point')),
@@ -1363,7 +1343,6 @@ scheme.FrameDropParams = tObject({
mimeType: tString,
value: tString,
}))),
timeout: tFloat,
});
scheme.FrameDropResult = tOptional(tObject({}));
scheme.FrameDblclickParams = tObject({
@@ -1375,7 +1354,6 @@ scheme.FrameDblclickParams = tObject({
position: tOptional(tType('Point')),
delay: tOptional(tFloat),
button: tOptional(tEnum(['left', 'right', 'middle'])),
timeout: tFloat,
trial: tOptional(tBoolean),
steps: tOptional(tInt),
});
@@ -1385,7 +1363,6 @@ scheme.FrameDispatchEventParams = tObject({
strict: tOptional(tBoolean),
type: tString,
eventInit: tType('SerializedArgument'),
timeout: tFloat,
});
scheme.FrameDispatchEventResult = tOptional(tObject({}));
scheme.FrameEvaluateExpressionParams = tObject({
@@ -1409,13 +1386,11 @@ scheme.FrameFillParams = tObject({
strict: tOptional(tBoolean),
value: tString,
force: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameFillResult = tOptional(tObject({}));
scheme.FrameFocusParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameFocusResult = tOptional(tObject({}));
scheme.FrameFrameElementParams = tOptional(tObject({}));
@@ -1441,14 +1416,12 @@ scheme.FrameGetAttributeParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
name: tString,
timeout: tFloat,
});
scheme.FrameGetAttributeResult = tObject({
value: tOptional(tString),
});
scheme.FrameGotoParams = tObject({
url: tString,
timeout: tFloat,
waitUntil: tOptional(tType('LifecycleEvent')),
referer: tOptional(tString),
});
@@ -1462,14 +1435,12 @@ scheme.FrameHoverParams = tObject({
scroll: tOptional(tEnum(['auto', 'none'])),
modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'ControlOrMeta', 'Meta', 'Shift']))),
position: tOptional(tType('Point')),
timeout: tFloat,
trial: tOptional(tBoolean),
});
scheme.FrameHoverResult = tOptional(tObject({}));
scheme.FrameInnerHTMLParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameInnerHTMLResult = tObject({
value: tString,
@@ -1477,7 +1448,6 @@ scheme.FrameInnerHTMLResult = tObject({
scheme.FrameInnerTextParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameInnerTextResult = tObject({
value: tString,
@@ -1485,7 +1455,6 @@ scheme.FrameInnerTextResult = tObject({
scheme.FrameInputValueParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameInputValueResult = tObject({
value: tString,
@@ -1493,7 +1462,6 @@ scheme.FrameInputValueResult = tObject({
scheme.FrameIsCheckedParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameIsCheckedResult = tObject({
value: tBoolean,
@@ -1501,7 +1469,6 @@ scheme.FrameIsCheckedResult = tObject({
scheme.FrameIsDisabledParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameIsDisabledResult = tObject({
value: tBoolean,
@@ -1509,7 +1476,6 @@ scheme.FrameIsDisabledResult = tObject({
scheme.FrameIsEnabledParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameIsEnabledResult = tObject({
value: tBoolean,
@@ -1531,7 +1497,6 @@ scheme.FrameIsVisibleResult = tObject({
scheme.FrameIsEditableParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameIsEditableResult = tObject({
value: tBoolean,
@@ -1542,7 +1507,6 @@ scheme.FramePressParams = tObject({
key: tString,
delay: tOptional(tFloat),
noWaitAfter: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FramePressResult = tOptional(tObject({}));
scheme.FrameQuerySelectorParams = tObject({
@@ -1575,14 +1539,12 @@ scheme.FrameSelectOptionParams = tObject({
index: tOptional(tInt),
}))),
force: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameSelectOptionResult = tObject({
values: tArray(tString),
});
scheme.FrameSetContentParams = tObject({
html: tString,
timeout: tFloat,
waitUntil: tOptional(tType('LifecycleEvent')),
});
scheme.FrameSetContentResult = tOptional(tObject({}));
@@ -1598,7 +1560,6 @@ scheme.FrameSetInputFilesParams = tObject({
directoryStream: tOptional(tChannel(['WritableStream'])),
localPaths: tOptional(tArray(tString)),
streams: tOptional(tArray(tChannel(['WritableStream']))),
timeout: tFloat,
});
scheme.FrameSetInputFilesResult = tOptional(tObject({}));
scheme.FrameTapParams = tObject({
@@ -1608,14 +1569,12 @@ scheme.FrameTapParams = tObject({
scroll: tOptional(tEnum(['auto', 'none'])),
modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'ControlOrMeta', 'Meta', 'Shift']))),
position: tOptional(tType('Point')),
timeout: tFloat,
trial: tOptional(tBoolean),
});
scheme.FrameTapResult = tOptional(tObject({}));
scheme.FrameTextContentParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
});
scheme.FrameTextContentResult = tObject({
value: tOptional(tString),
@@ -1629,7 +1588,6 @@ scheme.FrameTypeParams = tObject({
strict: tOptional(tBoolean),
text: tString,
delay: tOptional(tFloat),
timeout: tFloat,
});
scheme.FrameTypeResult = tOptional(tObject({}));
scheme.FrameUncheckParams = tObject({
@@ -1638,7 +1596,6 @@ scheme.FrameUncheckParams = tObject({
force: tOptional(tBoolean),
scroll: tOptional(tEnum(['auto', 'none'])),
position: tOptional(tType('Point')),
timeout: tFloat,
trial: tOptional(tBoolean),
});
scheme.FrameUncheckResult = tOptional(tObject({}));
@@ -1650,7 +1607,6 @@ scheme.FrameWaitForFunctionParams = tObject({
expression: tString,
isFunction: tOptional(tBoolean),
arg: tType('SerializedArgument'),
timeout: tFloat,
pollingInterval: tOptional(tFloat),
selector: tOptional(tString),
strict: tOptional(tBoolean),
@@ -1661,7 +1617,6 @@ scheme.FrameWaitForFunctionResult = tObject({
scheme.FrameWaitForSelectorParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
state: tOptional(tEnum(['attached', 'detached', 'visible', 'hidden'])),
omitReturnValue: tOptional(tBoolean),
});
@@ -1678,7 +1633,6 @@ scheme.FrameExpectParams = tObject({
expectedValue: tOptional(tType('SerializedArgument')),
useInnerText: tOptional(tBoolean),
isNot: tBoolean,
timeout: tFloat,
});
scheme.FrameExpectResult = tOptional(tObject({}));
scheme.FrameExpectErrorDetails = tObject({
@@ -1773,7 +1727,6 @@ scheme.ElementHandleCheckParams = tObject({
force: tOptional(tBoolean),
scroll: tOptional(tEnum(['auto', 'none'])),
position: tOptional(tType('Point')),
timeout: tFloat,
trial: tOptional(tBoolean),
});
scheme.ElementHandleCheckResult = tOptional(tObject({}));
@@ -1786,7 +1739,6 @@ scheme.ElementHandleClickParams = tObject({
delay: tOptional(tFloat),
button: tOptional(tEnum(['left', 'right', 'middle'])),
clickCount: tOptional(tInt),
timeout: tFloat,
trial: tOptional(tBoolean),
steps: tOptional(tInt),
});
@@ -1802,7 +1754,6 @@ scheme.ElementHandleDblclickParams = tObject({
position: tOptional(tType('Point')),
delay: tOptional(tFloat),
button: tOptional(tEnum(['left', 'right', 'middle'])),
timeout: tFloat,
trial: tOptional(tBoolean),
steps: tOptional(tInt),
});
@@ -1815,7 +1766,6 @@ scheme.ElementHandleDispatchEventResult = tOptional(tObject({}));
scheme.ElementHandleFillParams = tObject({
value: tString,
force: tOptional(tBoolean),
timeout: tFloat,
});
scheme.ElementHandleFillResult = tOptional(tObject({}));
scheme.ElementHandleFocusParams = tOptional(tObject({}));
@@ -1831,7 +1781,6 @@ scheme.ElementHandleHoverParams = tObject({
scroll: tOptional(tEnum(['auto', 'none'])),
modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'ControlOrMeta', 'Meta', 'Shift']))),
position: tOptional(tType('Point')),
timeout: tFloat,
trial: tOptional(tBoolean),
});
scheme.ElementHandleHoverResult = tOptional(tObject({}));
@@ -1878,7 +1827,6 @@ scheme.ElementHandleOwnerFrameResult = tObject({
scheme.ElementHandlePressParams = tObject({
key: tString,
delay: tOptional(tFloat),
timeout: tFloat,
noWaitAfter: tOptional(tBoolean),
});
scheme.ElementHandlePressResult = tOptional(tObject({}));
@@ -1896,7 +1844,6 @@ scheme.ElementHandleQuerySelectorAllResult = tObject({
elements: tArray(tChannel(['ElementHandle'])),
});
scheme.ElementHandleScreenshotParams = tObject({
timeout: tFloat,
type: tOptional(tEnum(['png', 'jpeg', 'webp'])),
quality: tOptional(tInt),
omitBackground: tOptional(tBoolean),
@@ -1913,9 +1860,7 @@ scheme.ElementHandleScreenshotParams = tObject({
scheme.ElementHandleScreenshotResult = tObject({
binary: tBinary,
});
scheme.ElementHandleScrollIntoViewIfNeededParams = tObject({
timeout: tFloat,
});
scheme.ElementHandleScrollIntoViewIfNeededParams = tOptional(tObject({}));
scheme.ElementHandleScrollIntoViewIfNeededResult = tOptional(tObject({}));
scheme.ElementHandleSelectOptionParams = tObject({
elements: tOptional(tArray(tChannel(['ElementHandle']))),
@@ -1926,14 +1871,12 @@ scheme.ElementHandleSelectOptionParams = tObject({
index: tOptional(tInt),
}))),
force: tOptional(tBoolean),
timeout: tFloat,
});
scheme.ElementHandleSelectOptionResult = tObject({
values: tArray(tString),
});
scheme.ElementHandleSelectTextParams = tObject({
force: tOptional(tBoolean),
timeout: tFloat,
});
scheme.ElementHandleSelectTextResult = tOptional(tObject({}));
scheme.ElementHandleSetInputFilesParams = tObject({
@@ -1946,7 +1889,6 @@ scheme.ElementHandleSetInputFilesParams = tObject({
directoryStream: tOptional(tChannel(['WritableStream'])),
localPaths: tOptional(tArray(tString)),
streams: tOptional(tArray(tChannel(['WritableStream']))),
timeout: tFloat,
});
scheme.ElementHandleSetInputFilesResult = tOptional(tObject({}));
scheme.ElementHandleTapParams = tObject({
@@ -1954,7 +1896,6 @@ scheme.ElementHandleTapParams = tObject({
scroll: tOptional(tEnum(['auto', 'none'])),
modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'ControlOrMeta', 'Meta', 'Shift']))),
position: tOptional(tType('Point')),
timeout: tFloat,
trial: tOptional(tBoolean),
});
scheme.ElementHandleTapResult = tOptional(tObject({}));
@@ -1965,26 +1906,22 @@ scheme.ElementHandleTextContentResult = tObject({
scheme.ElementHandleTypeParams = tObject({
text: tString,
delay: tOptional(tFloat),
timeout: tFloat,
});
scheme.ElementHandleTypeResult = tOptional(tObject({}));
scheme.ElementHandleUncheckParams = tObject({
force: tOptional(tBoolean),
scroll: tOptional(tEnum(['auto', 'none'])),
position: tOptional(tType('Point')),
timeout: tFloat,
trial: tOptional(tBoolean),
});
scheme.ElementHandleUncheckResult = tOptional(tObject({}));
scheme.ElementHandleWaitForElementStateParams = tObject({
state: tEnum(['visible', 'hidden', 'stable', 'enabled', 'disabled', 'editable']),
timeout: tFloat,
});
scheme.ElementHandleWaitForElementStateResult = tOptional(tObject({}));
scheme.ElementHandleWaitForSelectorParams = tObject({
selector: tString,
strict: tOptional(tBoolean),
timeout: tFloat,
state: tOptional(tEnum(['attached', 'detached', 'visible', 'hidden'])),
});
scheme.ElementHandleWaitForSelectorResult = tObject({
@@ -2057,7 +1994,6 @@ scheme.LocalUtilsConnectParams = tObject({
headers: tOptional(tAny),
exposeNetwork: tOptional(tString),
slowMo: tOptional(tFloat),
timeout: tFloat,
socksProxyRedirectPortForTest: tOptional(tInt),
});
scheme.LocalUtilsConnectResult = tObject({
@@ -2385,14 +2321,12 @@ scheme.PageExposeBindingResult = tObject({
disposable: tChannel(['Disposable']),
});
scheme.PageGoBackParams = tObject({
timeout: tFloat,
waitUntil: tOptional(tType('LifecycleEvent')),
});
scheme.PageGoBackResult = tObject({
response: tOptional(tChannel(['Response'])),
});
scheme.PageGoForwardParams = tObject({
timeout: tFloat,
waitUntil: tOptional(tType('LifecycleEvent')),
});
scheme.PageGoForwardResult = tObject({
@@ -2417,7 +2351,6 @@ scheme.PageUnregisterLocatorHandlerParams = tObject({
});
scheme.PageUnregisterLocatorHandlerResult = tOptional(tObject({}));
scheme.PageReloadParams = tObject({
timeout: tFloat,
waitUntil: tOptional(tType('LifecycleEvent')),
});
scheme.PageReloadResult = tObject({
@@ -2425,7 +2358,6 @@ scheme.PageReloadResult = tObject({
});
scheme.PageExpectScreenshotParams = tObject({
expected: tOptional(tBinary),
timeout: tFloat,
isNot: tBoolean,
locator: tOptional(tObject({
frame: tChannel(['Frame']),
@@ -2461,7 +2393,6 @@ scheme.PageExpectScreenshotErrorDetails = tObject({
log: tOptional(tArray(tString)),
});
scheme.PageScreenshotParams = tObject({
timeout: tFloat,
type: tOptional(tEnum(['png', 'jpeg', 'webp'])),
quality: tOptional(tInt),
fullPage: tOptional(tBoolean),
+4 -2
View File
@@ -133,7 +133,9 @@ import type { Progress } from './progress';
` : '') + `
import type { Binary, Channel, ${structNames.join(', ')} } from '@protocol/structs';
export type { Binary, Channel, ${structNames.join(', ')} } from '@protocol/structs';
`];
` + (target === 'Dispatcher' ? '' : `
export type TimeoutOptions = { signal: AbortSignal | undefined, timeout: number };
`)];
}
const validator_ts = [
@@ -360,7 +362,7 @@ function generateChannels(target) {
for (const derived of derivedClasses.get(channelName) || [])
addScheme(`${derived}${titleCase(methodName)}ErrorDetails`, `tType('${errorDetailsName}')`);
}
channels_ts.push(` ${methodName}(params: ${paramsName}, ${isDispatcher ? `progress: Progress` : `signal: AbortSignal | undefined`}): Promise<${resultName}>;`);
channels_ts.push(` ${methodName}(params: ${paramsName}, ${isDispatcher ? `progress: Progress` : `options: TimeoutOptions`}): Promise<${resultName}>;`);
}
channels_ts.push(`}`);