From 13cc266b37fade3cdaf552850fcfb1fe548a6524 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Mon, 1 Nov 2021 17:12:19 -0700 Subject: [PATCH] feat: add "commit" to possible waitUntil options (#9892) --- docs/src/api/params.md | 3 +- packages/playwright-core/src/client/frame.ts | 7 +- packages/playwright-core/src/client/types.ts | 4 +- .../playwright-core/src/protocol/channels.ts | 27 ++++---- .../playwright-core/src/protocol/protocol.yml | 66 +++++-------------- .../playwright-core/src/protocol/validator.ts | 11 ++-- packages/playwright-core/src/server/frames.ts | 6 +- packages/playwright-core/src/server/types.ts | 4 +- packages/playwright-core/types/types.d.ts | 33 ++++++---- tests/page/page-goto.spec.ts | 16 ++++- tests/page/page-set-content.spec.ts | 6 ++ tests/page/page-wait-for-load-state.spec.ts | 2 +- tests/page/page-wait-for-navigation.spec.ts | 15 +++++ tests/page/page-wait-for-url.spec.ts | 19 ++++++ utils/generate_channels.js | 4 ++ 15 files changed, 135 insertions(+), 88 deletions(-) diff --git a/docs/src/api/params.md b/docs/src/api/params.md index 101cf84975..2db72555af 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -1,10 +1,11 @@ ## navigation-wait-until -- `waitUntil` <[WaitUntilState]<"load"|"domcontentloaded"|"networkidle">> +- `waitUntil` <[WaitUntilState]<"load"|"domcontentloaded"|"networkidle"|"commit">> When to consider operation succeeded, defaults to `load`. Events can be either: * `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * `'load'` - consider operation to be finished when the `load` event is fired. * `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. +* `'commit'` - consider operation to be finished when network response is received and the document started loading. ## navigation-timeout - `timeout` <[float]> diff --git a/packages/playwright-core/src/client/frame.ts b/packages/playwright-core/src/client/frame.ts index f85827a917..95c6620aec 100644 --- a/packages/playwright-core/src/client/frame.ts +++ b/packages/playwright-core/src/client/frame.ts @@ -27,7 +27,7 @@ import { Page } from './page'; import { EventEmitter } from 'events'; import { Waiter } from './waiter'; import { Events } from './events'; -import { LifecycleEvent, URLMatch, SelectOption, SelectOptionOptions, FilePayload, WaitForFunctionOptions, kLifecycleEvents, StrictOptions } from './types'; +import { LifecycleEvent, URLMatch, SelectOption, SelectOptionOptions, FilePayload, WaitForFunctionOptions, StrictOptions, kLifecycleEvents } from './types'; import { urlMatches } from './clientHelper'; import * as api from '../../types/types'; import * as structs from '../../types/structs'; @@ -157,7 +157,8 @@ export class Frame extends ChannelOwner { if (urlMatches(this._page?.context()._options.baseURL, this.url(), url)) - return await this.waitForLoadState(options?.waitUntil, options); + return await this.waitForLoadState(options.waitUntil, options); + await this.waitForNavigation({ url, ...options }); } @@ -476,6 +477,6 @@ export function verifyLoadState(name: string, waitUntil: LifecycleEvent): Lifecy if (waitUntil as unknown === 'networkidle0') waitUntil = 'networkidle'; if (!kLifecycleEvents.has(waitUntil)) - throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle)`); + throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle|commit)`); return waitUntil; } diff --git a/packages/playwright-core/src/client/types.ts b/packages/playwright-core/src/client/types.ts index 71b3fb5c45..0753a76c4a 100644 --- a/packages/playwright-core/src/client/types.ts +++ b/packages/playwright-core/src/client/types.ts @@ -44,8 +44,8 @@ export type SetStorageState = { origins?: channels.OriginStorage[] }; -export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle'; -export const kLifecycleEvents: Set = new Set(['load', 'domcontentloaded', 'networkidle']); +export type LifecycleEvent = channels.LifecycleEvent; +export const kLifecycleEvents: Set = new Set(['load', 'domcontentloaded', 'networkidle', 'commit']); export type BrowserContextOptions = Omit & { viewport?: Size | null, diff --git a/packages/playwright-core/src/protocol/channels.ts b/packages/playwright-core/src/protocol/channels.ts index 353d5af358..684fe8b3da 100644 --- a/packages/playwright-core/src/protocol/channels.ts +++ b/packages/playwright-core/src/protocol/channels.ts @@ -243,6 +243,7 @@ export type FetchResponse = { headers: NameValue[], }; +export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle' | 'commit'; // ----------- Root ----------- export type RootInitializer = {}; export interface RootChannel extends Channel { @@ -1311,33 +1312,33 @@ export type PageExposeBindingOptions = { export type PageExposeBindingResult = void; export type PageGoBackParams = { timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, }; export type PageGoBackOptions = { timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, }; export type PageGoBackResult = { response?: ResponseChannel, }; export type PageGoForwardParams = { timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, }; export type PageGoForwardOptions = { timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, }; export type PageGoForwardResult = { response?: ResponseChannel, }; export type PageReloadParams = { timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, }; export type PageReloadOptions = { timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, }; export type PageReloadResult = { response?: ResponseChannel, @@ -1604,7 +1605,7 @@ export type FrameInitializer = { url: string, name: string, parentFrame?: FrameChannel, - loadStates: ('load' | 'domcontentloaded' | 'networkidle')[], + loadStates: LifecycleEvent[], }; export interface FrameChannel extends Channel { on(event: 'loadstate', callback: (params: FrameLoadstateEvent) => void): this; @@ -1653,8 +1654,8 @@ export interface FrameChannel extends Channel { expect(params: FrameExpectParams, metadata?: Metadata): Promise; } export type FrameLoadstateEvent = { - add?: 'load' | 'domcontentloaded' | 'networkidle', - remove?: 'load' | 'domcontentloaded' | 'networkidle', + add?: LifecycleEvent, + remove?: LifecycleEvent, }; export type FrameNavigatedEvent = { url: string, @@ -1886,12 +1887,12 @@ export type FrameGetAttributeResult = { export type FrameGotoParams = { url: string, timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, referer?: string, }; export type FrameGotoOptions = { timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, referer?: string, }; export type FrameGotoResult = { @@ -2084,11 +2085,11 @@ export type FrameSelectOptionResult = { export type FrameSetContentParams = { html: string, timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, }; export type FrameSetContentOptions = { timeout?: number, - waitUntil?: 'load' | 'domcontentloaded' | 'networkidle', + waitUntil?: LifecycleEvent, }; export type FrameSetContentResult = void; export type FrameSetInputFilesParams = { diff --git a/packages/playwright-core/src/protocol/protocol.yml b/packages/playwright-core/src/protocol/protocol.yml index 1f40e01b97..2270390f03 100644 --- a/packages/playwright-core/src/protocol/protocol.yml +++ b/packages/playwright-core/src/protocol/protocol.yml @@ -301,6 +301,16 @@ FetchResponse: type: array items: NameValue + +LifecycleEvent: + type: enum + literals: + - load + - domcontentloaded + - networkidle + - commit + + LaunchOptions: type: mixin properties: @@ -956,12 +966,7 @@ Page: goBack: parameters: timeout: number? - waitUntil: - type: enum? - literals: - - load - - domcontentloaded - - networkidle + waitUntil: LifecycleEvent? returns: response: Response? tracing: @@ -970,12 +975,7 @@ Page: goForward: parameters: timeout: number? - waitUntil: - type: enum? - literals: - - load - - domcontentloaded - - networkidle + waitUntil: LifecycleEvent? returns: response: Response? tracing: @@ -984,12 +984,7 @@ Page: reload: parameters: timeout: number? - waitUntil: - type: enum? - literals: - - load - - domcontentloaded - - networkidle + waitUntil: LifecycleEvent? returns: response: Response? tracing: @@ -1280,12 +1275,7 @@ Frame: parentFrame: Frame? loadStates: type: array - items: - type: enum - literals: - - load - - domcontentloaded - - networkidle + items: LifecycleEvent commands: @@ -1490,12 +1480,7 @@ Frame: parameters: url: string timeout: number? - waitUntil: - type: enum? - literals: - - load - - domcontentloaded - - networkidle + waitUntil: LifecycleEvent? referer: string? returns: response: Response? @@ -1668,12 +1653,7 @@ Frame: parameters: html: string timeout: number? - waitUntil: - type: enum? - literals: - - load - - domcontentloaded - - networkidle + waitUntil: LifecycleEvent? tracing: snapshot: true @@ -1819,18 +1799,8 @@ Frame: loadstate: parameters: - add: - type: enum? - literals: - - load - - domcontentloaded - - networkidle - remove: - type: enum? - literals: - - load - - domcontentloaded - - networkidle + add: LifecycleEvent? + remove: LifecycleEvent? navigated: parameters: diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index af4114e5a1..4c834b4207 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -191,6 +191,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { statusText: tString, headers: tArray(tType('NameValue')), }); + scheme.LifecycleEvent = tEnum(['load', 'domcontentloaded', 'networkidle', 'commit']); scheme.RootInitializeParams = tObject({ sdkLanguage: tString, }); @@ -538,15 +539,15 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { }); scheme.PageGoBackParams = tObject({ timeout: tOptional(tNumber), - waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), + waitUntil: tOptional(tType('LifecycleEvent')), }); scheme.PageGoForwardParams = tObject({ timeout: tOptional(tNumber), - waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), + waitUntil: tOptional(tType('LifecycleEvent')), }); scheme.PageReloadParams = tObject({ timeout: tOptional(tNumber), - waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), + waitUntil: tOptional(tType('LifecycleEvent')), }); scheme.PageScreenshotParams = tObject({ timeout: tOptional(tNumber), @@ -753,7 +754,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { scheme.FrameGotoParams = tObject({ url: tString, timeout: tOptional(tNumber), - waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), + waitUntil: tOptional(tType('LifecycleEvent')), referer: tOptional(tString), }); scheme.FrameHoverParams = tObject({ @@ -839,7 +840,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { scheme.FrameSetContentParams = tObject({ html: tString, timeout: tOptional(tNumber), - waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), + waitUntil: tOptional(tType('LifecycleEvent')), }); scheme.FrameSetInputFilesParams = tObject({ selector: tString, diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts index bae8a17b6d..9c3e507a2f 100644 --- a/packages/playwright-core/src/server/frames.ts +++ b/packages/playwright-core/src/server/frames.ts @@ -452,6 +452,9 @@ export class Frame extends SdkObject { if (this._parentFrame) this._parentFrame._childFrames.add(this); + + this._firedLifecycleEvents.add('commit'); + this._subtreeLifecycleEvents.add('commit'); } _onLifecycleEvent(event: types.LifecycleEvent) { @@ -471,6 +474,7 @@ export class Frame extends SdkObject { this._stopNetworkIdleTimer(); if (this._inflightRequests.size === 0) this._startNetworkIdleTimer(); + this._onLifecycleEvent('commit'); } setPendingDocument(documentInfo: DocumentInfo | undefined) { @@ -1492,6 +1496,6 @@ function verifyLifecycle(name: string, waitUntil: types.LifecycleEvent): types.L if (waitUntil as unknown === 'networkidle0') waitUntil = 'networkidle'; if (!types.kLifecycleEvents.has(waitUntil)) - throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle)`); + throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle|commit)`); return waitUntil; } diff --git a/packages/playwright-core/src/server/types.ts b/packages/playwright-core/src/server/types.ts index 3f90028135..1b42a8a807 100644 --- a/packages/playwright-core/src/server/types.ts +++ b/packages/playwright-core/src/server/types.ts @@ -28,8 +28,8 @@ export type WaitForElementOptions = TimeoutOptions & StrictOptions & { state?: ' export type WaitForFunctionOptions = TimeoutOptions & { pollingInterval?: number }; -export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle'; -export const kLifecycleEvents: Set = new Set(['load', 'domcontentloaded', 'networkidle']); +export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle' | 'commit'; +export const kLifecycleEvents: Set = new Set(['load', 'domcontentloaded', 'networkidle', 'commit']); export type NavigateOptions = TimeoutOptions & { waitUntil?: LifecycleEvent, diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index afa103e247..d1d803db25 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -2146,8 +2146,9 @@ export interface Page { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -2173,8 +2174,9 @@ export interface Page { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -2224,8 +2226,9 @@ export interface Page { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -2750,8 +2753,9 @@ export interface Page { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -3000,8 +3004,9 @@ export interface Page { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -3648,8 +3653,9 @@ export interface Page { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -3770,8 +3776,9 @@ export interface Page { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -4925,8 +4932,9 @@ export interface Frame { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -5427,8 +5435,9 @@ export interface Frame { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -5769,8 +5778,9 @@ export interface Frame { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise; /** @@ -5810,8 +5820,9 @@ export interface Frame { * - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. * - `'load'` - consider operation to be finished when the `load` event is fired. * - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms. + * - `'commit'` - consider operation to be finished when network response is received and the document started loading. */ - waitUntil?: "load"|"domcontentloaded"|"networkidle"; + waitUntil?: "load"|"domcontentloaded"|"networkidle"|"commit"; }): Promise;} /** diff --git a/tests/page/page-goto.spec.ts b/tests/page/page-goto.spec.ts index bf29f61dc9..4d71d7e305 100644 --- a/tests/page/page-goto.spec.ts +++ b/tests/page/page-goto.spec.ts @@ -287,7 +287,7 @@ it('should throw if networkidle2 is passed as an option', async ({ page, server let error = null; // @ts-expect-error networkidle2 is not allowed await page.goto(server.EMPTY_PAGE, { waitUntil: 'networkidle2' }).catch(err => error = err); - expect(error.message).toContain(`waitUntil: expected one of (load|domcontentloaded|networkidle)`); + expect(error.message).toContain(`waitUntil: expected one of (load|domcontentloaded|networkidle|commit)`); }); it('should fail when main resources failed to load', async ({ page, browserName, isWindows, mode }) => { @@ -628,3 +628,17 @@ it('should properly wait for load', async ({ page, server, browserName }) => { 'load' ]); }); + +it('should return when navigation is committed if commit is specified', async ({ page, server }) => { + server.setRoute('/empty.html', (req, res) => { + res.writeHead(200, { + 'content-type': 'text/html', + 'content-length': '8192' + }); + // Write enought bytes of the body to trigge response received event. + res.write('' + 'A'.repeat(4100)); + res.uncork(); + }); + const response = await page.goto(server.EMPTY_PAGE, { waitUntil: 'commit' }); + expect(response.status()).toBe(200); +}); diff --git a/tests/page/page-set-content.spec.ts b/tests/page/page-set-content.spec.ts index 10ca5aa281..a323d16367 100644 --- a/tests/page/page-set-content.spec.ts +++ b/tests/page/page-set-content.spec.ts @@ -31,6 +31,12 @@ it('should work with domcontentloaded', async ({ page, server }) => { expect(result).toBe(expectedOutput); }); +it('should work with commit', async ({ page }) => { + await page.setContent('<div>hello</div>', { waitUntil: 'commit' }); + const result = await page.content(); + expect(result).toBe(expectedOutput); +}); + it('should work with doctype', async ({ page, server }) => { const doctype = '<!DOCTYPE html>'; await page.setContent(`${doctype}<div>hello</div>`); diff --git a/tests/page/page-wait-for-load-state.spec.ts b/tests/page/page-wait-for-load-state.spec.ts index 4d631ae349..9853ab2d05 100644 --- a/tests/page/page-wait-for-load-state.spec.ts +++ b/tests/page/page-wait-for-load-state.spec.ts @@ -48,7 +48,7 @@ it('should throw for bad state', async ({ page, server }) => { await page.goto(server.PREFIX + '/one-style.html'); // @ts-expect-error 'bad' is not a valid load state const error = await page.waitForLoadState('bad').catch(e => e); - expect(error.message).toContain(`state: expected one of (load|domcontentloaded|networkidle)`); + expect(error.message).toContain(`state: expected one of (load|domcontentloaded|networkidle|commit)`); }); it('should resolve immediately if load state matches', async ({ page, server }) => { diff --git a/tests/page/page-wait-for-navigation.spec.ts b/tests/page/page-wait-for-navigation.spec.ts index e09e15400e..91a5c1679a 100644 --- a/tests/page/page-wait-for-navigation.spec.ts +++ b/tests/page/page-wait-for-navigation.spec.ts @@ -60,6 +60,21 @@ it('should work with both domcontentloaded and load', async ({ page, server }) = await navigationPromise; }); +it('should work with commit', async ({ page, server }) => { + server.setRoute('/empty.html', (req, res) => { + res.writeHead(200, { + 'content-type': 'text/html', + 'content-length': '8192' + }); + // Write enought bytes of the body to trigge response received event. + res.write('<title>' + 'A'.repeat(4100)); + res.uncork(); + }); + + page.goto(server.EMPTY_PAGE).catch(e => {}); + await page.waitForNavigation({ waitUntil: 'commit' }); +}); + it('should work with clicking on anchor links', async ({ page, server }) => { await page.goto(server.EMPTY_PAGE); await page.setContent(`<a href='#foobar'>foobar</a>`); diff --git a/tests/page/page-wait-for-url.spec.ts b/tests/page/page-wait-for-url.spec.ts index c944f348d2..ccfec39f96 100644 --- a/tests/page/page-wait-for-url.spec.ts +++ b/tests/page/page-wait-for-url.spec.ts @@ -49,6 +49,25 @@ it('should work with both domcontentloaded and load', async ({ page, server }) = await navigationPromise; }); +it('should work with commit', async ({ page, server }) => { + server.setRoute('/empty.html', (req, res) => { + res.writeHead(200, { + 'content-type': 'text/html', + 'content-length': '8192' + }); + // Write enought bytes of the body to trigge response received event. + res.write('<title>' + 'A'.repeat(4100)); + res.uncork(); + }); + + page.goto(server.EMPTY_PAGE).catch(e => {}); + await page.waitForURL('**/empty.html', { waitUntil: 'commit' }); +}); + +it('should work with commit and about:blank', async ({ page, server }) => { + await page.waitForURL('about:blank', { waitUntil: 'commit' }); +}); + it('should work with clicking on anchor links', async ({ page, server }) => { await page.goto(server.EMPTY_PAGE); await page.setContent(`<a href='#foobar'>foobar</a>`); diff --git a/utils/generate_channels.js b/utils/generate_channels.js index 2f28d50319..fe6e0ae0d4 100755 --- a/utils/generate_channels.js +++ b/utils/generate_channels.js @@ -271,6 +271,10 @@ for (const [name, item] of Object.entries(protocol)) { channels_ts.push(`export type ${name} = ${inner.ts};`); channels_ts.push(``); addScheme(name, inner.scheme); + } else if (item.type === 'enum') { + const ts = item.literals.map(literal => `'${literal}'`).join(' | '); + channels_ts.push(`export type ${name} = ${ts};`) + addScheme(name, `tEnum([${item.literals.map(literal => `'${literal}'`).join(', ')}])`); } }