mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat: support timeouts per CDP command (#11595)
This commit is contained in:
parent
acf1518deb
commit
c660d4001d
@ -80,6 +80,7 @@ sidebar_label: API
|
|||||||
| [BrowserLaunchArgumentOptions](./puppeteer.browserlaunchargumentoptions.md) | Launcher options that only apply to Chrome. |
|
| [BrowserLaunchArgumentOptions](./puppeteer.browserlaunchargumentoptions.md) | Launcher options that only apply to Chrome. |
|
||||||
| [CDPSessionEvents](./puppeteer.cdpsessionevents.md) | |
|
| [CDPSessionEvents](./puppeteer.cdpsessionevents.md) | |
|
||||||
| [ClickOptions](./puppeteer.clickoptions.md) | |
|
| [ClickOptions](./puppeteer.clickoptions.md) | |
|
||||||
|
| [CommandOptions](./puppeteer.commandoptions.md) | |
|
||||||
| [CommonEventEmitter](./puppeteer.commoneventemitter.md) | |
|
| [CommonEventEmitter](./puppeteer.commoneventemitter.md) | |
|
||||||
| [Configuration](./puppeteer.configuration.md) | <p>Defines options to configure Puppeteer's behavior during installation and runtime.</p><p>See individual properties for more information.</p> |
|
| [Configuration](./puppeteer.configuration.md) | <p>Defines options to configure Puppeteer's behavior during installation and runtime.</p><p>See individual properties for more information.</p> |
|
||||||
| [ConnectionTransport](./puppeteer.connectiontransport.md) | |
|
| [ConnectionTransport](./puppeteer.connectiontransport.md) | |
|
||||||
|
@ -40,8 +40,8 @@ await client.send('Animation.setPlaybackRate', {
|
|||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
| Method | Modifiers | Description |
|
| Method | Modifiers | Description |
|
||||||
| --------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [connection()](./puppeteer.cdpsession.connection.md) | | |
|
| [connection()](./puppeteer.cdpsession.connection.md) | | |
|
||||||
| [detach()](./puppeteer.cdpsession.detach.md) | | Detaches the cdpSession from the target. Once detached, the cdpSession object won't emit any events and can't be used to send messages. |
|
| [detach()](./puppeteer.cdpsession.detach.md) | | Detaches the cdpSession from the target. Once detached, the cdpSession object won't emit any events and can't be used to send messages. |
|
||||||
| [id()](./puppeteer.cdpsession.id.md) | | Returns the session's id. |
|
| [id()](./puppeteer.cdpsession.id.md) | | Returns the session's id. |
|
||||||
| [send(method, paramArgs)](./puppeteer.cdpsession.send.md) | | |
|
| [send(method, params, options)](./puppeteer.cdpsession.send.md) | | |
|
||||||
|
@ -10,7 +10,8 @@ sidebar_label: CDPSession.send
|
|||||||
class CDPSession {
|
class CDPSession {
|
||||||
abstract send<T extends keyof ProtocolMapping.Commands>(
|
abstract send<T extends keyof ProtocolMapping.Commands>(
|
||||||
method: T,
|
method: T,
|
||||||
...paramArgs: ProtocolMapping.Commands[T]['paramsType']
|
params?: ProtocolMapping.Commands[T]['paramsType'][0],
|
||||||
|
options?: CommandOptions
|
||||||
): Promise<ProtocolMapping.Commands[T]['returnType']>;
|
): Promise<ProtocolMapping.Commands[T]['returnType']>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -18,9 +19,10 @@ class CDPSession {
|
|||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | --------------------------------------------- | ----------- |
|
| --------- | -------------------------------------------------- | ------------ |
|
||||||
| method | T | |
|
| method | T | |
|
||||||
| paramArgs | ProtocolMapping.Commands\[T\]\['paramsType'\] | |
|
| params | ProtocolMapping.Commands\[T\]\['paramsType'\]\[0\] | _(Optional)_ |
|
||||||
|
| options | [CommandOptions](./puppeteer.commandoptions.md) | _(Optional)_ |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
|
17
docs/api/puppeteer.commandoptions.md
Normal file
17
docs/api/puppeteer.commandoptions.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
sidebar_label: CommandOptions
|
||||||
|
---
|
||||||
|
|
||||||
|
# CommandOptions interface
|
||||||
|
|
||||||
|
#### Signature:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export interface CommandOptions
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
| Property | Modifiers | Type | Description | Default |
|
||||||
|
| -------- | --------- | ------ | ----------- | ------- |
|
||||||
|
| timeout | | number | | |
|
@ -31,6 +31,6 @@ export declare class Connection extends EventEmitter<CDPSessionEvents>
|
|||||||
| [createSession(targetInfo)](./puppeteer.connection.createsession.md) | | |
|
| [createSession(targetInfo)](./puppeteer.connection.createsession.md) | | |
|
||||||
| [dispose()](./puppeteer.connection.dispose.md) | | |
|
| [dispose()](./puppeteer.connection.dispose.md) | | |
|
||||||
| [fromSession(session)](./puppeteer.connection.fromsession.md) | <code>static</code> | |
|
| [fromSession(session)](./puppeteer.connection.fromsession.md) | <code>static</code> | |
|
||||||
| [send(method, paramArgs)](./puppeteer.connection.send.md) | | |
|
| [send(method, params, options)](./puppeteer.connection.send.md) | | |
|
||||||
| [session(sessionId)](./puppeteer.connection.session.md) | | |
|
| [session(sessionId)](./puppeteer.connection.session.md) | | |
|
||||||
| [url()](./puppeteer.connection.url.md) | | |
|
| [url()](./puppeteer.connection.url.md) | | |
|
||||||
|
@ -10,7 +10,8 @@ sidebar_label: Connection.send
|
|||||||
class Connection {
|
class Connection {
|
||||||
send<T extends keyof ProtocolMapping.Commands>(
|
send<T extends keyof ProtocolMapping.Commands>(
|
||||||
method: T,
|
method: T,
|
||||||
...paramArgs: ProtocolMapping.Commands[T]['paramsType']
|
params?: ProtocolMapping.Commands[T]['paramsType'][0],
|
||||||
|
options?: CommandOptions
|
||||||
): Promise<ProtocolMapping.Commands[T]['returnType']>;
|
): Promise<ProtocolMapping.Commands[T]['returnType']>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -18,9 +19,10 @@ class Connection {
|
|||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | --------------------------------------------- | ----------- |
|
| --------- | -------------------------------------------------- | ------------ |
|
||||||
| method | T | |
|
| method | T | |
|
||||||
| paramArgs | ProtocolMapping.Commands\[T\]\['paramsType'\] | |
|
| params | ProtocolMapping.Commands\[T\]\['paramsType'\]\[0\] | _(Optional)_ |
|
||||||
|
| options | [CommandOptions](./puppeteer.commandoptions.md) | _(Optional)_ |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
|
@ -48,6 +48,13 @@ export interface CDPSessionEvents
|
|||||||
[CDPSessionEvent.SessionDetached]: CDPSession;
|
[CDPSessionEvent.SessionDetached]: CDPSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface CommandOptions {
|
||||||
|
timeout: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `CDPSession` instances are used to talk raw Chrome Devtools Protocol.
|
* The `CDPSession` instances are used to talk raw Chrome Devtools Protocol.
|
||||||
*
|
*
|
||||||
@ -97,7 +104,8 @@ export abstract class CDPSession extends EventEmitter<CDPSessionEvents> {
|
|||||||
|
|
||||||
abstract send<T extends keyof ProtocolMapping.Commands>(
|
abstract send<T extends keyof ProtocolMapping.Commands>(
|
||||||
method: T,
|
method: T,
|
||||||
...paramArgs: ProtocolMapping.Commands[T]['paramsType']
|
params?: ProtocolMapping.Commands[T]['paramsType'][0],
|
||||||
|
options?: CommandOptions
|
||||||
): Promise<ProtocolMapping.Commands[T]['returnType']>;
|
): Promise<ProtocolMapping.Commands[T]['returnType']>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
type CDPEvents,
|
type CDPEvents,
|
||||||
CDPSession,
|
CDPSession,
|
||||||
CDPSessionEvent,
|
CDPSessionEvent,
|
||||||
|
type CommandOptions,
|
||||||
} from '../api/CDPSession.js';
|
} from '../api/CDPSession.js';
|
||||||
import {CallbackRegistry} from '../common/CallbackRegistry.js';
|
import {CallbackRegistry} from '../common/CallbackRegistry.js';
|
||||||
import {TargetCloseError} from '../common/Errors.js';
|
import {TargetCloseError} from '../common/Errors.js';
|
||||||
@ -91,7 +92,8 @@ export class CdpCDPSession extends CDPSession {
|
|||||||
|
|
||||||
override send<T extends keyof ProtocolMapping.Commands>(
|
override send<T extends keyof ProtocolMapping.Commands>(
|
||||||
method: T,
|
method: T,
|
||||||
...paramArgs: ProtocolMapping.Commands[T]['paramsType']
|
params?: ProtocolMapping.Commands[T]['paramsType'][0],
|
||||||
|
options?: CommandOptions
|
||||||
): Promise<ProtocolMapping.Commands[T]['returnType']> {
|
): Promise<ProtocolMapping.Commands[T]['returnType']> {
|
||||||
if (!this.#connection) {
|
if (!this.#connection) {
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
@ -100,13 +102,12 @@ export class CdpCDPSession extends CDPSession {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// See the comment in Connection#send explaining why we do this.
|
|
||||||
const params = paramArgs.length ? paramArgs[0] : undefined;
|
|
||||||
return this.#connection._rawSend(
|
return this.#connection._rawSend(
|
||||||
this.#callbacks,
|
this.#callbacks,
|
||||||
method,
|
method,
|
||||||
params,
|
params,
|
||||||
this.#sessionId
|
this.#sessionId,
|
||||||
|
options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import type {Protocol} from 'devtools-protocol';
|
import type {Protocol} from 'devtools-protocol';
|
||||||
import type {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
|
import type {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
|
||||||
|
|
||||||
|
import type {CommandOptions} from '../api/CDPSession.js';
|
||||||
import {
|
import {
|
||||||
CDPSessionEvent,
|
CDPSessionEvent,
|
||||||
type CDPSession,
|
type CDPSession,
|
||||||
@ -104,7 +105,8 @@ export class Connection extends EventEmitter<CDPSessionEvents> {
|
|||||||
|
|
||||||
send<T extends keyof ProtocolMapping.Commands>(
|
send<T extends keyof ProtocolMapping.Commands>(
|
||||||
method: T,
|
method: T,
|
||||||
...paramArgs: ProtocolMapping.Commands[T]['paramsType']
|
params?: ProtocolMapping.Commands[T]['paramsType'][0],
|
||||||
|
options?: CommandOptions
|
||||||
): Promise<ProtocolMapping.Commands[T]['returnType']> {
|
): Promise<ProtocolMapping.Commands[T]['returnType']> {
|
||||||
// There is only ever 1 param arg passed, but the Protocol defines it as an
|
// There is only ever 1 param arg passed, but the Protocol defines it as an
|
||||||
// array of 0 or 1 items See this comment:
|
// array of 0 or 1 items See this comment:
|
||||||
@ -112,8 +114,7 @@ export class Connection extends EventEmitter<CDPSessionEvents> {
|
|||||||
// which explains why the protocol defines the params this way for better
|
// which explains why the protocol defines the params this way for better
|
||||||
// type-inference.
|
// type-inference.
|
||||||
// So now we check if there are any params or not and deal with them accordingly.
|
// So now we check if there are any params or not and deal with them accordingly.
|
||||||
const params = paramArgs.length ? paramArgs[0] : undefined;
|
return this._rawSend(this.#callbacks, method, params, undefined, options);
|
||||||
return this._rawSend(this.#callbacks, method, params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,9 +124,10 @@ export class Connection extends EventEmitter<CDPSessionEvents> {
|
|||||||
callbacks: CallbackRegistry,
|
callbacks: CallbackRegistry,
|
||||||
method: T,
|
method: T,
|
||||||
params: ProtocolMapping.Commands[T]['paramsType'][0],
|
params: ProtocolMapping.Commands[T]['paramsType'][0],
|
||||||
sessionId?: string
|
sessionId?: string,
|
||||||
|
options?: CommandOptions
|
||||||
): Promise<ProtocolMapping.Commands[T]['returnType']> {
|
): Promise<ProtocolMapping.Commands[T]['returnType']> {
|
||||||
return callbacks.create(method, this.#timeout, id => {
|
return callbacks.create(method, options?.timeout ?? this.#timeout, id => {
|
||||||
const stringifiedMessage = JSON.stringify({
|
const stringifiedMessage = JSON.stringify({
|
||||||
method,
|
method,
|
||||||
params,
|
params,
|
||||||
|
@ -1445,6 +1445,12 @@
|
|||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[CDPSession.spec] Target.createCDPSession should respect custom timeout",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["cdp", "firefox"],
|
||||||
|
"expectations": ["SKIP"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events",
|
"testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
@ -127,6 +127,26 @@ describe('Target.createCDPSession', function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should respect custom timeout', async () => {
|
||||||
|
const {page} = await getTestState();
|
||||||
|
|
||||||
|
const client = await page.createCDPSession();
|
||||||
|
await expect(
|
||||||
|
client.send(
|
||||||
|
'Runtime.evaluate',
|
||||||
|
{
|
||||||
|
expression: 'new Promise(resolve => {})',
|
||||||
|
awaitPromise: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timeout: 50,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).rejects.toThrowError(
|
||||||
|
`Runtime.evaluate timed out. Increase the 'protocolTimeout' setting in launch/connect calls for a higher timeout if needed.`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('should expose the underlying connection', async () => {
|
it('should expose the underlying connection', async () => {
|
||||||
const {page} = await getTestState();
|
const {page} = await getTestState();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user