feat(page): introduce page.setDefaultTimeout (#3854)

Method `page.setDefaultTimeout` overrides default 30 seconds timeout
for all `page.waitFor*` methods, including navigation and waiting
for selectors.

Fix #3319.
This commit is contained in:
Andrey Lushnikov 2019-01-28 17:16:12 -08:00 committed by GitHub
parent f2c968fdb8
commit a064a6341b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 195 additions and 40 deletions

View File

@ -131,6 +131,7 @@
* [page.setContent(html[, options])](#pagesetcontenthtml-options)
* [page.setCookie(...cookies)](#pagesetcookiecookies)
* [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout)
* [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout)
* [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
* [page.setGeolocation(options)](#pagesetgeolocationoptions)
* [page.setJavaScriptEnabled(enabled)](#pagesetjavascriptenabledenabled)
@ -1396,7 +1397,7 @@ Shortcut for [page.mainFrame().focus(selector)](#framefocusselector).
#### page.goBack([options])
- `options` <[Object]> Navigation parameters which might have the following properties:
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) method.
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- `waitUntil` <[string]|[Array]<[string]>> When to consider navigation succeeded, defaults to `load`. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:
- `load` - consider navigation to be finished when the `load` event is fired.
- `domcontentloaded` - consider navigation to be finished when the `DOMContentLoaded` event is fired.
@ -1409,7 +1410,7 @@ Navigate to the previous page in history.
#### page.goForward([options])
- `options` <[Object]> Navigation parameters which might have the following properties:
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) method.
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- `waitUntil` <[string]|[Array]<[string]>> When to consider navigation succeeded, defaults to `load`. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:
- `load` - consider navigation to be finished when the `load` event is fired.
- `domcontentloaded` - consider navigation to be finished when the `DOMContentLoaded` event is fired.
@ -1423,7 +1424,7 @@ Navigate to the next page in history.
#### page.goto(url[, options])
- `url` <[string]> URL to navigate page to. The url should include scheme, e.g. `https://`.
- `options` <[Object]> Navigation parameters which might have the following properties:
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) method.
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- `waitUntil` <[string]|[Array]<[string]>> When to consider navigation succeeded, defaults to `load`. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:
- `load` - consider navigation to be finished when the `load` event is fired.
- `domcontentloaded` - consider navigation to be finished when the `DOMContentLoaded` event is fired.
@ -1581,7 +1582,7 @@ Shortcut for [page.mainFrame().executionContext().queryObjects(prototypeHandle)]
#### page.reload([options])
- `options` <[Object]> Navigation parameters which might have the following properties:
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) method.
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- `waitUntil` <[string]|[Array]<[string]>> When to consider navigation succeeded, defaults to `load`. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:
- `load` - consider navigation to be finished when the `load` event is fired.
- `domcontentloaded` - consider navigation to be finished when the `DOMContentLoaded` event is fired.
@ -1639,7 +1640,7 @@ Toggles ignoring cache for each request based on the enabled state. By default,
#### page.setContent(html[, options])
- `html` <[string]> HTML markup to assign to the page.
- `options` <[Object]> Parameters which might have the following properties:
- `timeout` <[number]> Maximum time in milliseconds for resources to load, defaults to 30 seconds, pass `0` to disable timeout.
- `timeout` <[number]> Maximum time in milliseconds for resources to load, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- `waitUntil` <[string]|[Array]<[string]>> When to consider setting markup succeeded, defaults to `load`. Given an array of event strings, setting content is considered to be successful after all events have been fired. Events can be either:
- `load` - consider setting content to be finished when the `load` event is fired.
- `domcontentloaded` - consider setting content to be finished when the `DOMContentLoaded` event is fired.
@ -1667,13 +1668,36 @@ await page.setCookie(cookieObject1, cookieObject2);
#### page.setDefaultNavigationTimeout(timeout)
- `timeout` <[number]> Maximum navigation time in milliseconds
This setting will change the default maximum navigation time of 30 seconds for the following methods:
- [page.goto(url[, options])](#pagegotourl-options)
This setting will change the default maximum navigation time for the following methods and related shortcuts:
- [page.goBack([options])](#pagegobackoptions)
- [page.goForward([options])](#pagegoforwardoptions)
- [page.goto(url[, options])](#pagegotourl-options)
- [page.reload([options])](#pagereloadoptions)
- [page.setContent(html[, options])](#pagesetcontenthtml-options)
- [page.waitForNavigation([options])](#pagewaitfornavigationoptions)
> **NOTE** [`page.setDefaultNavigationTimeout`](#pagesetdefaultnavigationtimeouttimeout) takes priority over [`page.setDefaultTimeout`](#pagesetdefaulttimeouttimeout)
#### page.setDefaultTimeout(timeout)
- `timeout` <[number]> Maximum time in milliseconds
This setting will change the default maximum time for the following methods and related shortcuts:
- [page.goBack([options])](#pagegobackoptions)
- [page.goForward([options])](#pagegoforwardoptions)
- [page.goto(url[, options])](#pagegotourl-options)
- [page.reload([options])](#pagereloadoptions)
- [page.setContent(html[, options])](#pagesetcontenthtml-options)
- [page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])](#pagewaitforselectororfunctionortimeout-options-args)
- [page.waitForFunction(pageFunction[, options[, ...args]])](#pagewaitforfunctionpagefunction-options-args)
- [page.waitForNavigation([options])](#pagewaitfornavigationoptions)
- [page.waitForRequest(urlOrPredicate[, options])](#pagewaitforrequesturlorpredicate-options)
- [page.waitForResponse(urlOrPredicate[, options])](#pagewaitforresponseurlorpredicate-options)
- [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options)
- [page.waitForXPath(xpath[, options])](#pagewaitforxpathxpath-options)
> **NOTE** [`page.setDefaultNavigationTimeout`](#pagesetdefaultnavigationtimeouttimeout) takes priority over [`page.setDefaultTimeout`](#pagesetdefaulttimeouttimeout)
#### page.setExtraHTTPHeaders(headers)
- `headers` <[Object]> An object containing additional HTTP headers to be sent with every request. All header values must be strings.
- returns: <[Promise]>
@ -1846,7 +1870,7 @@ Shortcut for [page.mainFrame().waitFor(selectorOrFunctionOrTimeout[, options[, .
- `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
- `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
- `mutation` - to execute `pageFunction` on every DOM mutation.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[JSHandle]>> Promise which resolves when the `pageFunction` returns a truthy value. It resolves to a JSHandle of the truthy value.
@ -1874,7 +1898,7 @@ Shortcut for [page.mainFrame().waitForFunction(pageFunction[, options[, ...args]
#### page.waitForNavigation([options])
- `options` <[Object]> Navigation parameters which might have the following properties:
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) method.
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- `waitUntil` <[string]|[Array]<[string]>> When to consider navigation succeeded, defaults to `load`. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:
- `load` - consider navigation to be finished when the `load` event is fired.
- `domcontentloaded` - consider navigation to be finished when the `DOMContentLoaded` event is fired.
@ -1899,7 +1923,7 @@ Shortcut for [page.mainFrame().waitForNavigation(options)](#framewaitfornavigati
#### page.waitForRequest(urlOrPredicate[, options])
- `urlOrPredicate` <[string]|[Function]> A URL or predicate to wait for.
- `options` <[Object]> Optional waiting parameters
- `timeout` <[number]> Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout.
- `timeout` <[number]> Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
- returns: <[Promise]<[Request]>> Promise which resolves to the matched request.
```js
@ -1911,7 +1935,7 @@ return firstRequest.url();
#### page.waitForResponse(urlOrPredicate[, options])
- `urlOrPredicate` <[string]|[Function]> A URL or predicate to wait for.
- `options` <[Object]> Optional waiting parameters
- `timeout` <[number]> Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout.
- `timeout` <[number]> Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
- returns: <[Promise]<[Response]>> Promise which resolves to the matched response.
```js
@ -1925,7 +1949,7 @@ return finalResponse.ok();
- `options` <[Object]> Optional waiting parameters
- `visible` <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
- `hidden` <[boolean]> wait for element to not be found in the DOM or to be hidden, i.e. have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM. Resolves to `null` if waiting for `hidden: true` and selector is not found in DOM.
Wait for the `selector` to appear in page. If at the moment of calling
@ -1954,7 +1978,7 @@ Shortcut for [page.mainFrame().waitForSelector(selector[, options])](#framewaitf
- `options` <[Object]> Optional waiting parameters
- `visible` <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
- `hidden` <[boolean]> wait for element to not be found in the DOM or to be hidden, i.e. have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by xpath string is added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is not found in DOM.
Wait for the `xpath` to appear in page. If at the moment of calling
@ -2538,7 +2562,7 @@ If there's no element matching `selector`, the method throws an error.
#### frame.goto(url[, options])
- `url` <[string]> URL to navigate frame to. The url should include scheme, e.g. `https://`.
- `options` <[Object]> Navigation parameters which might have the following properties:
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) method.
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- `waitUntil` <[string]|[Array]<[string]>> When to consider navigation succeeded, defaults to `load`. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:
- `load` - consider navigation to be finished when the `load` event is fired.
- `domcontentloaded` - consider navigation to be finished when the `DOMContentLoaded` event is fired.
@ -2598,7 +2622,7 @@ frame.select('select#colors', 'red', 'green', 'blue'); // multiple selections
#### frame.setContent(html[, options])
- `html` <[string]> HTML markup to assign to the page.
- `options` <[Object]> Parameters which might have the following properties:
- `timeout` <[number]> Maximum time in milliseconds for resources to load, defaults to 30 seconds, pass `0` to disable timeout.
- `timeout` <[number]> Maximum time in milliseconds for resources to load, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- `waitUntil` <[string]|[Array]<[string]>> When to consider setting markup succeeded, defaults to `load`. Given an array of event strings, setting content is considered to be successful after all events have been fired. Events can be either:
- `load` - consider setting content to be finished when the `load` event is fired.
- `domcontentloaded` - consider setting content to be finished when the `DOMContentLoaded` event is fired.
@ -2672,7 +2696,7 @@ await page.waitFor(selector => !!document.querySelector(selector), {}, selector)
- `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
- `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
- `mutation` - to execute `pageFunction` on every DOM mutation.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[JSHandle]>> Promise which resolves when the `pageFunction` returns a truthy value. It resolves to a JSHandle of the truthy value.
@ -2698,7 +2722,7 @@ await page.waitForFunction(selector => !!document.querySelector(selector), {}, s
#### frame.waitForNavigation([options])
- `options` <[Object]> Navigation parameters which might have the following properties:
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) method.
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- `waitUntil` <[string]|[Array]<[string]>> When to consider navigation succeeded, defaults to `load`. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:
- `load` - consider navigation to be finished when the `load` event is fired.
- `domcontentloaded` - consider navigation to be finished when the `DOMContentLoaded` event is fired.
@ -2724,7 +2748,7 @@ const [response] = await Promise.all([
- `options` <[Object]> Optional waiting parameters
- `visible` <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
- `hidden` <[boolean]> wait for element to not be found in the DOM or to be hidden, i.e. have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM. Resolves to `null` if waiting for `hidden: true` and selector is not found in DOM.
Wait for the `selector` to appear in page. If at the moment of calling
@ -2752,7 +2776,7 @@ puppeteer.launch().then(async browser => {
- `options` <[Object]> Optional waiting parameters
- `visible` <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
- `hidden` <[boolean]> wait for element to not be found in the DOM or to be hidden, i.e. have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by xpath string is added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is not found in DOM.
Wait for the `xpath` to appear in page. If at the moment of calling

View File

@ -27,10 +27,12 @@ class DOMWorld {
/**
* @param {!Puppeteer.FrameManager} frameManager
* @param {!Puppeteer.Frame} frame
* @param {!Puppeteer.TimeoutSettings} timeoutSettings
*/
constructor(frameManager, frame) {
constructor(frameManager, frame, timeoutSettings) {
this._frameManager = frameManager;
this._frame = frame;
this._timeoutSettings = timeoutSettings;
/** @type {?Promise<!Puppeteer.ElementHandle>} */
this._documentPromise = null;
@ -190,7 +192,7 @@ class DOMWorld {
async setContent(html, options = {}) {
const {
waitUntil = ['load'],
timeout = 30000,
timeout = this._timeoutSettings.navigationTimeout(),
} = options;
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
@ -452,7 +454,7 @@ class DOMWorld {
waitForFunction(pageFunction, options = {}, ...args) {
const {
polling = 'raf',
timeout = 30000
timeout = this._timeoutSettings.timeout(),
} = options;
return new WaitTask(this, pageFunction, 'function', polling, timeout, ...args).promise;
}
@ -474,7 +476,7 @@ class DOMWorld {
const {
visible: waitForVisible = false,
hidden: waitForHidden = false,
timeout = 30000,
timeout = this._timeoutSettings.timeout(),
} = options;
const polling = waitForVisible || waitForHidden ? 'raf' : 'mutation';
const title = `${isXPath ? 'XPath' : 'selector'} "${selectorOrXPath}"${waitForHidden ? ' to be hidden' : ''}`;

View File

@ -29,13 +29,14 @@ class FrameManager extends EventEmitter {
* @param {!Protocol.Page.FrameTree} frameTree
* @param {!Puppeteer.Page} page
* @param {!Puppeteer.NetworkManager} networkManager
* @param {!Puppeteer.TimeoutSettings} timeoutSettings
*/
constructor(client, frameTree, page, networkManager) {
constructor(client, frameTree, page, networkManager, timeoutSettings) {
super();
this._client = client;
this._page = page;
this._networkManager = networkManager;
this._defaultNavigationTimeout = 30000;
this._timeoutSettings = timeoutSettings;
/** @type {!Map<string, !Frame>} */
this._frames = new Map();
/** @type {!Map<number, !ExecutionContext>} */
@ -55,13 +56,6 @@ class FrameManager extends EventEmitter {
this._handleFrameTree(frameTree);
}
/**
* @param {number} timeout
*/
setDefaultNavigationTimeout(timeout) {
this._defaultNavigationTimeout = timeout;
}
/**
* @param {!Puppeteer.Frame} frame
* @param {string} url
@ -73,7 +67,7 @@ class FrameManager extends EventEmitter {
const {
referer = this._networkManager.extraHTTPHeaders()['referer'],
waitUntil = ['load'],
timeout = this._defaultNavigationTimeout,
timeout = this._timeoutSettings.navigationTimeout(),
} = options;
const watcher = new LifecycleWatcher(this, frame, waitUntil, timeout);
@ -120,7 +114,7 @@ class FrameManager extends EventEmitter {
assertNoLegacyNavigationOptions(options);
const {
waitUntil = ['load'],
timeout = this._defaultNavigationTimeout,
timeout = this._timeoutSettings.navigationTimeout(),
} = options;
const watcher = new LifecycleWatcher(this, frame, waitUntil, timeout);
const error = await Promise.race([
@ -373,8 +367,8 @@ class Frame {
this._loaderId = '';
/** @type {!Set<string>} */
this._lifecycleEvents = new Set();
this._mainWorld = new DOMWorld(frameManager, this);
this._secondaryWorld = new DOMWorld(frameManager, this);
this._mainWorld = new DOMWorld(frameManager, this, frameManager._timeoutSettings);
this._secondaryWorld = new DOMWorld(frameManager, this, frameManager._timeoutSettings);
/** @type {!Set<!Frame>} */
this._childFrames = new Set();

View File

@ -30,6 +30,7 @@ const {Coverage} = require('./Coverage');
const {Worker} = require('./Worker');
const {createJSHandle} = require('./JSHandle');
const {Accessibility} = require('./Accessibility');
const {TimeoutSettings} = require('./TimeoutSettings');
const writeFileAsync = helper.promisify(fs.writeFile);
class Page extends EventEmitter {
@ -78,11 +79,12 @@ class Page extends EventEmitter {
this._target = target;
this._keyboard = new Keyboard(client);
this._mouse = new Mouse(client, this._keyboard);
this._timeoutSettings = new TimeoutSettings();
this._touchscreen = new Touchscreen(client, this._keyboard);
this._accessibility = new Accessibility(client);
this._networkManager = new NetworkManager(client);
/** @type {!FrameManager} */
this._frameManager = new FrameManager(client, frameTree, this, this._networkManager);
this._frameManager = new FrameManager(client, frameTree, this, this._networkManager, this._timeoutSettings);
this._networkManager.setFrameManager(this._frameManager);
this._emulationManager = new EmulationManager(client);
this._tracing = new Tracing(client);
@ -268,7 +270,14 @@ class Page extends EventEmitter {
* @param {number} timeout
*/
setDefaultNavigationTimeout(timeout) {
this._frameManager.setDefaultNavigationTimeout(timeout);
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
}
/**
* @param {number} timeout
*/
setDefaultTimeout(timeout) {
this._timeoutSettings.setDefaultTimeout(timeout);
}
/**
@ -664,7 +673,7 @@ class Page extends EventEmitter {
*/
async waitForRequest(urlOrPredicate, options = {}) {
const {
timeout = 30000
timeout = this._timeoutSettings.timeout(),
} = options;
return helper.waitForEvent(this._networkManager, Events.NetworkManager.Request, request => {
if (helper.isString(urlOrPredicate))
@ -682,7 +691,7 @@ class Page extends EventEmitter {
*/
async waitForResponse(urlOrPredicate, options = {}) {
const {
timeout = 30000
timeout = this._timeoutSettings.timeout(),
} = options;
return helper.waitForEvent(this._networkManager, Events.NetworkManager.Response, response => {
if (helper.isString(urlOrPredicate))

57
lib/TimeoutSettings.js Normal file
View File

@ -0,0 +1,57 @@
/**
* Copyright 2019 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const DEFAULT_TIMEOUT = 30000;
class TimeoutSettings {
constructor() {
this._defaultTimeout = null;
this._defaultNavigationTimeout = null;
}
/**
* @param {number} timeout
*/
setDefaultTimeout(timeout) {
this._defaultTimeout = timeout;
}
/**
* @param {number} timeout
*/
setDefaultNavigationTimeout(timeout) {
this._defaultNavigationTimeout = timeout;
}
/**
* @return {number}
*/
navigationTimeout() {
if (this._defaultNavigationTimeout !== null)
return this._defaultNavigationTimeout;
if (this._defaultTimeout !== null)
return this._defaultTimeout;
return DEFAULT_TIMEOUT;
}
timeout() {
if (this._defaultTimeout !== null)
return this._defaultTimeout;
return DEFAULT_TIMEOUT;
}
}
module.exports = {TimeoutSettings};

2
lib/externs.d.ts vendored
View File

@ -7,6 +7,7 @@ import {Mouse as RealMouse, Keyboard as RealKeyboard, Touchscreen as RealTouchsc
import {Frame as RealFrame, FrameManager as RealFrameManager} from './FrameManager.js';
import {JSHandle as RealJSHandle, ElementHandle as RealElementHandle} from './JSHandle.js';
import {DOMWorld as RealDOMWorld} from './DOMWorld.js';
import {TimeoutSettings as RealTimeoutSettings} from './TimeoutSettings.js';
import {ExecutionContext as RealExecutionContext} from './ExecutionContext.js';
import { NetworkManager as RealNetworkManager, Request as RealRequest, Response as RealResponse } from './NetworkManager.js';
import * as child_process from 'child_process';
@ -30,6 +31,7 @@ declare global {
export class ElementHandle extends RealElementHandle {}
export class JSHandle extends RealJSHandle {}
export class DOMWorld extends RealDOMWorld {}
export class TimeoutSettings extends RealTimeoutSettings {}
export class ExecutionContext extends RealExecutionContext {}
export class Page extends RealPage { }
export class Response extends RealResponse { }

View File

@ -118,6 +118,25 @@ module.exports.addTests = function({testRunner, expect}) {
expect(error.message).toContain('Navigation Timeout Exceeded: 1ms');
expect(error).toBeInstanceOf(TimeoutError);
});
it('should fail when exceeding default maximum timeout', async({page, server}) => {
// Hang for request to the empty.html
server.setRoute('/empty.html', (req, res) => { });
let error = null;
page.setDefaultTimeout(1);
await page.goto(server.PREFIX + '/empty.html').catch(e => error = e);
expect(error.message).toContain('Navigation Timeout Exceeded: 1ms');
expect(error).toBeInstanceOf(TimeoutError);
});
it('should prioritize default navigation timeout over default timeout', async({page, server}) => {
// Hang for request to the empty.html
server.setRoute('/empty.html', (req, res) => { });
let error = null;
page.setDefaultTimeout(0);
page.setDefaultNavigationTimeout(1);
await page.goto(server.PREFIX + '/empty.html').catch(e => error = e);
expect(error.message).toContain('Navigation Timeout Exceeded: 1ms');
expect(error).toBeInstanceOf(TimeoutError);
});
it('should disable timeout when its set to 0', async({page, server}) => {
let error = null;
let loaded = false;

View File

@ -17,6 +17,7 @@ const fs = require('fs');
const path = require('path');
const utils = require('./utils');
const {waitEvent} = utils;
const {TimeoutError} = utils.requireRoot('Errors');
const DeviceDescriptors = utils.requireRoot('DeviceDescriptors');
const iPhone = DeviceDescriptors['iPhone 6'];
@ -421,6 +422,17 @@ module.exports.addTests = function({testRunner, expect, headless}) {
]);
expect(request.url()).toBe(server.PREFIX + '/digits/2.png');
});
it('should respect timeout', async({page, server}) => {
let error = null;
await page.waitForRequest(() => false, {timeout: 1}).catch(e => error = e);
expect(error).toBeInstanceOf(TimeoutError);
});
it('should respect default timeout', async({page, server}) => {
let error = null;
page.setDefaultTimeout(1);
await page.waitForRequest(() => false).catch(e => error = e);
expect(error).toBeInstanceOf(TimeoutError);
});
it('should work with no timeout', async({page, server}) => {
await page.goto(server.EMPTY_PAGE);
const [request] = await Promise.all([
@ -448,6 +460,17 @@ module.exports.addTests = function({testRunner, expect, headless}) {
]);
expect(response.url()).toBe(server.PREFIX + '/digits/2.png');
});
it('should respect timeout', async({page, server}) => {
let error = null;
await page.waitForResponse(() => false, {timeout: 1}).catch(e => error = e);
expect(error).toBeInstanceOf(TimeoutError);
});
it('should respect default timeout', async({page, server}) => {
let error = null;
page.setDefaultTimeout(1);
await page.waitForResponse(() => false).catch(e => error = e);
expect(error).toBeInstanceOf(TimeoutError);
});
it('should work with predicate', async({page, server}) => {
await page.goto(server.EMPTY_PAGE);
const [response] = await Promise.all([
@ -617,6 +640,23 @@ module.exports.addTests = function({testRunner, expect, headless}) {
const result = await page.content();
expect(result).toBe(`${doctype}${expectedOutput}`);
});
it('should respect timeout', async({page, server}) => {
const imgPath = '/img.png';
// stall for image
server.setRoute(imgPath, (req, res) => {});
let error = null;
await page.setContent(`<img src="${server.PREFIX + imgPath}"></img>`, {timeout: 1}).catch(e => error = e);
expect(error).toBeInstanceOf(TimeoutError);
});
it('should respect default navigation timeout', async({page, server}) => {
page.setDefaultNavigationTimeout(1);
const imgPath = '/img.png';
// stall for image
server.setRoute(imgPath, (req, res) => {});
let error = null;
await page.setContent(`<img src="${server.PREFIX + imgPath}"></img>`).catch(e => error = e);
expect(error).toBeInstanceOf(TimeoutError);
});
it('should await resources to load', async({page, server}) => {
const imgPath = '/img.png';
let imgResponse = null;

View File

@ -170,6 +170,14 @@ module.exports.addTests = function({testRunner, expect, product}) {
expect(error.message).toContain('waiting for function failed: timeout');
expect(error).toBeInstanceOf(TimeoutError);
});
it('should respect default timeout', async({page}) => {
page.setDefaultTimeout(1);
let error = null;
await page.waitForFunction('false').catch(e => error = e);
expect(error).toBeTruthy();
expect(error.message).toContain('waiting for function failed: timeout');
expect(error).toBeInstanceOf(TimeoutError);
});
it('should disable timeout when its set to 0', async({page}) => {
const watchdog = page.waitForFunction(() => {
window.__counter = (window.__counter || 0) + 1;