diff --git a/docs/api.md b/docs/api.md index 64b7e695f0f7f..5cf2863dbfe1e 100644 --- a/docs/api.md +++ b/docs/api.md @@ -325,7 +325,7 @@ const [page] = await Promise.all([ console.log(await page.evaluate('location.href')); ``` -> **NOTE** Use [Page.waitForLoadState](#pagewaitforloadstateoptions) to wait until the page gets to a particular state (you should not need it in most cases). +> **NOTE** Use [`page.waitForLoadState([state[, options]])`](#pagewaitforloadstatestate-options) to wait until the page gets to a particular state (you should not need it in most cases). #### browserContext.addCookies(cookies) - `cookies` <[Array]<[Object]>> @@ -692,7 +692,7 @@ page.removeListener('request', logRequest); - [page.waitFor(selectorOrFunctionOrTimeout[, options[, arg]])](#pagewaitforselectororfunctionortimeout-options-arg) - [page.waitForEvent(event[, optionsOrPredicate])](#pagewaitforeventevent-optionsorpredicate) - [page.waitForFunction(pageFunction, arg[, options])](#pagewaitforfunctionpagefunction-arg-options) -- [page.waitForLoadState([options])](#pagewaitforloadstateoptions) +- [page.waitForLoadState([state[, options]])](#pagewaitforloadstatestate-options) - [page.waitForNavigation([options])](#pagewaitfornavigationoptions) - [page.waitForRequest(urlOrPredicate[, options])](#pagewaitforrequesturlorpredicate-options) - [page.waitForResponse(urlOrPredicate[, options])](#pagewaitforresponseurlorpredicate-options) @@ -780,7 +780,8 @@ const [popup] = await Promise.all([ ]); console.log(await popup.evaluate('location.href')); ``` -> **NOTE** Use [Page.waitForLoadState](#pagewaitforloadstateoptions) to wait until the page gets to a particular state (you should not need it in most cases). + +> **NOTE** Use [`page.waitForLoadState([state[, options]])`](#pagewaitforloadstatestate-options) to wait until the page gets to a particular state (you should not need it in most cases). #### event: 'request' - <[Request]> @@ -1705,25 +1706,33 @@ await page.waitForFunction(selector => !!document.querySelector(selector), selec Shortcut for [page.mainFrame().waitForFunction(pageFunction, arg, options]])](#framewaitforfunctionpagefunction-arg-options). -#### page.waitForLoadState([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 [browserContext.setDefaultNavigationTimeout(timeout)](#browsercontextsetdefaultnavigationtimeouttimeout), [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout), [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods. - - `waitUntil` <"load"|"domcontentloaded"|"networkidle0"|"networkidle2"> When to consider navigation succeeded, defaults to `load`. 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. - - `'networkidle0'` - consider navigation to be finished when there are no more than 0 network connections for at least `500` ms. - - `'networkidle2'` - consider navigation to be finished when there are no more than 2 network connections for at least `500` ms. -- returns: <[Promise]> Promise which resolves when the load state has been achieved. +#### page.waitForLoadState([state[, options]]) +- `state` <"load"|"domcontentloaded"|"networkidle0"|"networkidle2"> Load state to wait for, defaults to `load`. If the state has been already reached while loading current document, the method resolves immediately. + - `'load'` - wait for the `load` event to be fired. + - `'domcontentloaded'` - wait for the `DOMContentLoaded` event to be fired. + - `'networkidle0'` - wait until there are no more than 0 network connections for at least `500` ms. + - `'networkidle2'` - wait until there are no more than 2 network connections for at least `500` ms. +- `options` <[Object]> + - `timeout` <[number]> Maximum waiting time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultNavigationTimeout(timeout)](#browsercontextsetdefaultnavigationtimeouttimeout), [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout), [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods. +- returns: <[Promise]> Promise which resolves when the required load state has been reached. -This resolves when the page reaches a required load state, `load` by default. The navigation can be in progress when it is called. -If navigation is already at a required state, resolves immediately. +This resolves when the page reaches a required load state, `load` by default. The navigation must have been committed when this method is called. If current document has already reached the required state, resolves immediately. ```js await page.click('button'); // Click triggers navigation. -await page.waitForLoadState(); // The promise resolves after navigation has finished. +await page.waitForLoadState(); // The promise resolves after 'load' event. +``` + +```js +const [popup] = await Promise.all([ + page.waitForEvent('popup'), + page.click('button'), // Click triggers a popup. +]) +await popup.waitForLoadState('domcontentloaded'); // The promise resolves after 'domcontentloaded' event. +console.log(await popup.title()); // Popup is ready to use. ``` -Shortcut for [page.mainFrame().waitForLoadState([options])](#framewaitforloadstateoptions). +Shortcut for [page.mainFrame().waitForLoadState([options])](#framewaitforloadstatestate-options). #### page.waitForNavigation([options]) - `options` <[Object]> Navigation parameters which might have the following properties: @@ -1881,7 +1890,7 @@ An example of getting text from an iframe element: - [frame.url()](#frameurl) - [frame.waitFor(selectorOrFunctionOrTimeout[, options[, arg]])](#framewaitforselectororfunctionortimeout-options-arg) - [frame.waitForFunction(pageFunction, arg[, options])](#framewaitforfunctionpagefunction-arg-options) -- [frame.waitForLoadState([options])](#framewaitforloadstateoptions) +- [frame.waitForLoadState([state[, options]])](#framewaitforloadstatestate-options) - [frame.waitForNavigation([options])](#framewaitfornavigationoptions) - [frame.waitForSelector(selector[, options])](#framewaitforselectorselector-options) @@ -2369,22 +2378,21 @@ const selector = '.foo'; await frame.waitForFunction(selector => !!document.querySelector(selector), selector); ``` -#### frame.waitForLoadState([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 [browserContext.setDefaultNavigationTimeout(timeout)](#browsercontextsetdefaultnavigationtimeouttimeout), [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout), [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods. - - `waitUntil` <"load"|"domcontentloaded"|"networkidle0"|"networkidle2"> When to consider navigation succeeded, defaults to `load`. 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. - - `'networkidle0'` - consider navigation to be finished when there are no more than 0 network connections for at least `500` ms. - - `'networkidle2'` - consider navigation to be finished when there are no more than 2 network connections for at least `500` ms. -- returns: <[Promise]> Promise which resolves when the load state has been achieved. +#### frame.waitForLoadState([state[, options]]) +- `state` <"load"|"domcontentloaded"|"networkidle0"|"networkidle2"> Load state to wait for, defaults to `load`. If the state has been already reached while loading current document, the method resolves immediately. + - `'load'` - wait for the `load` event to be fired. + - `'domcontentloaded'` - wait for the `DOMContentLoaded` event to be fired. + - `'networkidle0'` - wait until there are no more than 0 network connections for at least `500` ms. + - `'networkidle2'` - wait until there are no more than 2 network connections for at least `500` ms. +- `options` <[Object]> + - `timeout` <[number]> Maximum waiting time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultNavigationTimeout(timeout)](#browsercontextsetdefaultnavigationtimeouttimeout), [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout), [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods. +- returns: <[Promise]> Promise which resolves when the required load state has been reached. -This resolves when the page reaches a required load state, `load` by default. The navigation can be in progress when it is called. -If navigation is already at a required state, resolves immediately. +This resolves when the frame reaches a required load state, `load` by default. The navigation must have been committed when this method is called. If current document has already reached the required state, resolves immediately. ```js await frame.click('button'); // Click triggers navigation. -await frame.waitForLoadState(); // The promise resolves after navigation has finished. +await frame.waitForLoadState(); // The promise resolves after 'load' event. ``` #### frame.waitForNavigation([options]) diff --git a/src/frames.ts b/src/frames.ts index e018b8ed66995..fb99cfb730c3a 100644 --- a/src/frames.ts +++ b/src/frames.ts @@ -370,7 +370,7 @@ export class Frame { await sameDocumentPromise; } const request = (navigateResult && navigateResult.newDocumentId) ? frameTask.request(navigateResult.newDocumentId) : null; - await frameTask.waitForLifecycle(options.waitUntil); + await frameTask.waitForLifecycle(options.waitUntil === undefined ? 'load' : options.waitUntil); frameTask.done(); return request ? request._finalRequest().response() : null; } @@ -383,14 +383,14 @@ export class Frame { frameTask.waitForSameDocumentNavigation(options.url), ]); const request = documentId ? frameTask.request(documentId) : null; - await frameTask.waitForLifecycle(options.waitUntil); + await frameTask.waitForLifecycle(options.waitUntil === undefined ? 'load' : options.waitUntil); frameTask.done(); return request ? request._finalRequest().response() : null; } - async waitForLoadState(options: types.NavigateOptions = {}): Promise { + async waitForLoadState(state: types.LifecycleEvent = 'load', options: types.TimeoutOptions = {}): Promise { const frameTask = new FrameTask(this, options); - await frameTask.waitForLifecycle(options.waitUntil); + await frameTask.waitForLifecycle(state); frameTask.done(); } @@ -507,7 +507,7 @@ export class Frame { this._page._frameManager._consoleMessageTags.set(tag, () => { // Clear lifecycle right after document.open() - see 'tag' below. this._page._frameManager.clearFrameLifecycle(this); - this.waitForLoadState(options).then(resolve).catch(reject); + this.waitForLoadState(options ? options.waitUntil : 'load', options).then(resolve).catch(reject); }); }); const contentPromise = context.evaluateInternal(({ html, tag }) => { @@ -1078,7 +1078,7 @@ export class FrameTask { })); } - waitForLifecycle(waitUntil: types.LifecycleEvent = 'load'): Promise { + waitForLifecycle(waitUntil: types.LifecycleEvent): Promise { if (!types.kLifecycleEvents.has(waitUntil)) throw new Error(`Unsupported waitUntil option ${String(waitUntil)}`); return this.raceAgainstFailures(new Promise((resolve, reject) => { diff --git a/src/page.ts b/src/page.ts index 27d15db182e6b..c6dd32f7f05ca 100644 --- a/src/page.ts +++ b/src/page.ts @@ -295,8 +295,8 @@ export class Page extends platform.EventEmitter { return waitPromise; } - async waitForLoadState(options?: types.NavigateOptions): Promise { - return this.mainFrame().waitForLoadState(options); + async waitForLoadState(state?: types.LifecycleEvent, options?: types.TimeoutOptions): Promise { + return this.mainFrame().waitForLoadState(state, options); } async waitForNavigation(options?: types.WaitForNavigationOptions): Promise { diff --git a/test/browsercontext.spec.js b/test/browsercontext.spec.js index 7e9ae9d7163ab..01afa4870c0fc 100644 --- a/test/browsercontext.spec.js +++ b/test/browsercontext.spec.js @@ -497,7 +497,7 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, FF context.waitForEvent('page'), page.evaluate(url => window.open(url), server.EMPTY_PAGE) ]); - await otherPage.waitForLoadState({ waitUntil: 'domcontentloaded' }); + await otherPage.waitForLoadState('domcontentloaded'); expect(otherPage.url()).toBe(server.EMPTY_PAGE); await context.close(); }); @@ -508,7 +508,7 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, FF context.waitForEvent('page'), page.evaluate(url => window.open(url), 'about:blank') ]); - await otherPage.waitForLoadState({ waitUntil: 'domcontentloaded' }); + await otherPage.waitForLoadState('domcontentloaded'); expect(otherPage.url()).toBe('about:blank'); await context.close(); }); @@ -519,7 +519,7 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, FF context.waitForEvent('page'), page.evaluate(() => window.open()) ]); - await otherPage.waitForLoadState({ waitUntil: 'domcontentloaded' }); + await otherPage.waitForLoadState('domcontentloaded'); expect(otherPage.url()).toBe('about:blank'); await context.close(); }); @@ -577,7 +577,7 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, FF // Issue a redirect. serverResponse.writeHead(302, { location: '/injectedstyle.css' }); serverResponse.end(); - await newPage.waitForLoadState({ waitUntil: 'domcontentloaded' }); + await newPage.waitForLoadState('domcontentloaded'); expect(newPage.url()).toBe(server.PREFIX + '/one-style.html'); // Cleanup. await context.close(); diff --git a/test/elementhandle.spec.js b/test/elementhandle.spec.js index 5bb2fa2cbbd4c..ae83bf9ff8ed9 100644 --- a/test/elementhandle.spec.js +++ b/test/elementhandle.spec.js @@ -218,7 +218,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT}) return div; }); expect(await divHandle.ownerFrame()).toBe(page.mainFrame()); - await popup.waitForLoadState({ waitUntil: 'domcontentloaded' }); + await popup.waitForLoadState('domcontentloaded'); await page.evaluate(() => { const div = document.querySelector('div'); window.__popup.document.body.appendChild(div); diff --git a/test/emulation.spec.js b/test/emulation.spec.js index cac81946496be..bb16c2fe07249 100644 --- a/test/emulation.spec.js +++ b/test/emulation.spec.js @@ -351,7 +351,7 @@ module.exports.describe = function({testRunner, expect, playwright, headless, FF page.waitForEvent('popup'), page.evaluate(url => window._popup = window.open(url), server.PREFIX + '/formatted-number.html'), ]); - await popup.waitForLoadState({ waitUntil: 'domcontentloaded' }); + await popup.waitForLoadState('domcontentloaded'); const result = await popup.evaluate(() => window.result); expect(result).toBe('1 000 000,5'); await context.close(); @@ -364,7 +364,7 @@ module.exports.describe = function({testRunner, expect, playwright, headless, FF page.waitForEvent('popup'), page.evaluate(url => window._popup = window.open(url), server.PREFIX + '/formatted-number.html'), ]); - await popup.waitForLoadState({ waitUntil: 'domcontentloaded' }); + await popup.waitForLoadState('domcontentloaded'); const result = await popup.evaluate(() => window.initialNavigatorLanguage); expect(result).toBe('fr-CH'); await context.close(); diff --git a/test/navigation.spec.js b/test/navigation.spec.js index 804518216a467..0c7cc92396a71 100644 --- a/test/navigation.spec.js +++ b/test/navigation.spec.js @@ -819,7 +819,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF it('should respect timeout', async({page, server}) => { server.setRoute('/one-style.css', (req, res) => response = res); await page.goto(server.PREFIX + '/one-style.html', {waitUntil: 'domcontentloaded'}); - const error = await page.waitForLoadState({ timeout: 1 }).catch(e => e); + const error = await page.waitForLoadState('load', { timeout: 1 }).catch(e => e); expect(error.message).toBe('Navigation timeout of 1 ms exceeded'); }); it('should resolve immediately if loaded', async({page, server}) => { @@ -830,7 +830,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF await page.goto(server.EMPTY_PAGE); server.setRoute('/one-style.css', (req, res) => response = res); await page.goto(server.PREFIX + '/one-style.html', {waitUntil: 'domcontentloaded'}); - await page.waitForLoadState({ waitUntil: 'domcontentloaded' }); + await page.waitForLoadState('domcontentloaded'); }); it('should work with pages that have loaded before being connected to', async({page, context, server}) => { await page.goto(server.EMPTY_PAGE); @@ -851,7 +851,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF return popup.document.readyState; }), ]); - await popup.waitForLoadState({ waitUntil: 'load' }); + await popup.waitForLoadState(); expect(readyState).toBe(FFOX ? 'uninitialized' : 'complete'); expect(await popup.evaluate(() => document.readyState)).toBe(FFOX ? 'uninitialized' : 'complete'); }); @@ -860,7 +860,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF page.waitForEvent('popup'), page.evaluate(() => window.open('about:blank') && 1), ]); - await popup.waitForLoadState({ waitUntil: 'load' }); + await popup.waitForLoadState(); expect(await popup.evaluate(() => document.readyState)).toBe('complete'); }); it('should wait for load state of about:blank popup with noopener ', async({browser, page}) => { @@ -868,7 +868,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF page.waitForEvent('popup'), page.evaluate(() => window.open('about:blank', null, 'noopener') && 1), ]); - await popup.waitForLoadState({ waitUntil: 'load' }); + await popup.waitForLoadState(); expect(await popup.evaluate(() => document.readyState)).toBe('complete'); }); it('should wait for load state of popup with network url ', async({browser, page, server}) => { @@ -877,7 +877,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF page.waitForEvent('popup'), page.evaluate(url => window.open(url) && 1, server.EMPTY_PAGE), ]); - await popup.waitForLoadState({ waitUntil: 'load' }); + await popup.waitForLoadState(); expect(await popup.evaluate(() => document.readyState)).toBe('complete'); }); it('should wait for load state of popup with network url and noopener ', async({browser, page, server}) => { @@ -886,7 +886,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF page.waitForEvent('popup'), page.evaluate(url => window.open(url, null, 'noopener') && 1, server.EMPTY_PAGE), ]); - await popup.waitForLoadState({ waitUntil: 'load' }); + await popup.waitForLoadState(); expect(await popup.evaluate(() => document.readyState)).toBe('complete'); }); it('should work with clicking target=_blank', async({browser, page, server}) => { @@ -896,7 +896,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF page.waitForEvent('popup'), page.click('a'), ]); - await popup.waitForLoadState({ waitUntil: 'load' }); + await popup.waitForLoadState(); expect(await popup.evaluate(() => document.readyState)).toBe('complete'); }); it('should wait for load state of newPage', async({browser, context, page, server}) => { @@ -904,7 +904,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF context.waitForEvent('page'), context.newPage(), ]); - await newPage.waitForLoadState({ waitUntil: 'load' }); + await newPage.waitForLoadState(); expect(await newPage.evaluate(() => document.readyState)).toBe('complete'); }); it('should resolve after popup load', async({browser, server}) => { @@ -920,7 +920,7 @@ module.exports.describe = function({testRunner, expect, playwright, MAC, WIN, FF page.evaluate(url => window.popup = window.open(url), server.PREFIX + '/one-style.html'), ]); let resolved = false; - const loadSatePromise = popup.waitForLoadState({waitUntil: 'load'}).then(() => resolved = true); + const loadSatePromise = popup.waitForLoadState().then(() => resolved = true); // Round trips! for (let i = 0; i < 5; i++) await page.evaluate('window'); diff --git a/test/popup.spec.js b/test/popup.spec.js index 75dd5edce870a..854165d9955ff 100644 --- a/test/popup.spec.js +++ b/test/popup.spec.js @@ -32,7 +32,7 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE context.waitForEvent('page'), page.click('a'), ]); - await popup.waitForLoadState({waitUntil: 'domcontentloaded'}) + await popup.waitForLoadState('domcontentloaded'); const userAgent = await popup.evaluate(() => window.initialUserAgent); const request = await requestPromise; await context.close(); @@ -110,7 +110,7 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE page.waitForEvent('popup'), page.evaluate(url => window._popup = window.open(url), server.PREFIX + '/title.html'), ]); - await popup.waitForLoadState({waitUntil: 'domcontentloaded'}); + await popup.waitForLoadState('domcontentloaded'); expect(await popup.title()).toBe('Woof-Woof'); await context.close(); });