From 175362c04892f064eb734d49f9db1950f65b0c9d Mon Sep 17 00:00:00 2001
From: Nikolay Vitkov <34244704+Lightning00Blade@users.noreply.github.com>
Date: Fri, 10 Mar 2023 16:59:02 +0100
Subject: [PATCH] chore: add BiDi for `goto` navigation (#9795)
---
docs/api/puppeteer.httprequest.md | 6 +-
package-lock.json | 13 +-
packages/puppeteer-core/package.json | 2 +-
.../puppeteer-core/src/common/HTTPRequest.ts | 10 +-
.../puppeteer-core/src/common/HTTPResponse.ts | 10 +-
packages/puppeteer-core/src/common/Page.ts | 2 +-
.../src/common/bidi/Connection.ts | 15 +-
.../puppeteer-core/src/common/bidi/Context.ts | 93 ++++++-
.../puppeteer-core/src/common/bidi/Page.ts | 38 ++-
test/TestExpectations.json | 228 ++++++++++++++++++
test/src/navigation.spec.ts | 43 ++--
11 files changed, 409 insertions(+), 51 deletions(-)
diff --git a/docs/api/puppeteer.httprequest.md b/docs/api/puppeteer.httprequest.md
index f6f001d6fa6..6db6e461fcf 100644
--- a/docs/api/puppeteer.httprequest.md
+++ b/docs/api/puppeteer.httprequest.md
@@ -34,9 +34,9 @@ The constructor for this class is marked as internal. Third-party code should no
## Properties
-| Property | Modifiers | Type | Description |
-| ------------------------------------------- | --------------------- | ---------- | ----------------------------------------------------------------- |
-| [client](./puppeteer.httprequest.client.md) | readonly
| CDPSession | Warning! Using this client can break Puppeteer. Use with caution. |
+| Property | Modifiers | Type | Description |
+| ------------------------------------------- | --------------------- | --------------------------------------- | ----------------------------------------------------------------- |
+| [client](./puppeteer.httprequest.client.md) | readonly
| [CDPSession](./puppeteer.cdpsession.md) | Warning! Using this client can break Puppeteer. Use with caution. |
## Methods
diff --git a/package-lock.json b/package-lock.json
index fb22f32ab76..1a9d481755a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2625,8 +2625,9 @@
"license": "ISC"
},
"node_modules/chromium-bidi": {
- "version": "0.4.4",
- "license": "Apache-2.0",
+ "version": "0.4.5",
+ "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.5.tgz",
+ "integrity": "sha512-rkav9YzRfAshSTG3wNXF7P7yNiI29QAo1xBXElPoCoSQR5n20q3cOyVhDv6S7+GlF/CJ/emUxlQiR0xOPurkGg==",
"dependencies": {
"mitt": "3.0.0"
},
@@ -9228,7 +9229,7 @@
"version": "19.7.4",
"license": "Apache-2.0",
"dependencies": {
- "chromium-bidi": "0.4.4",
+ "chromium-bidi": "0.4.5",
"cross-fetch": "3.1.5",
"debug": "4.3.4",
"devtools-protocol": "0.0.1094867",
@@ -11025,7 +11026,9 @@
"version": "1.1.4"
},
"chromium-bidi": {
- "version": "0.4.4",
+ "version": "0.4.5",
+ "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.5.tgz",
+ "integrity": "sha512-rkav9YzRfAshSTG3wNXF7P7yNiI29QAo1xBXElPoCoSQR5n20q3cOyVhDv6S7+GlF/CJ/emUxlQiR0xOPurkGg==",
"requires": {
"mitt": "3.0.0"
}
@@ -13982,7 +13985,7 @@
"puppeteer-core": {
"version": "file:packages/puppeteer-core",
"requires": {
- "chromium-bidi": "0.4.4",
+ "chromium-bidi": "0.4.5",
"cross-fetch": "3.1.5",
"debug": "4.3.4",
"devtools-protocol": "0.0.1094867",
diff --git a/packages/puppeteer-core/package.json b/packages/puppeteer-core/package.json
index d4cdd1c329f..7c6e5d3afd7 100644
--- a/packages/puppeteer-core/package.json
+++ b/packages/puppeteer-core/package.json
@@ -131,7 +131,7 @@
"author": "The Chromium Authors",
"license": "Apache-2.0",
"dependencies": {
- "chromium-bidi": "0.4.4",
+ "chromium-bidi": "0.4.5",
"cross-fetch": "3.1.5",
"debug": "4.3.4",
"devtools-protocol": "0.0.1094867",
diff --git a/packages/puppeteer-core/src/common/HTTPRequest.ts b/packages/puppeteer-core/src/common/HTTPRequest.ts
index a4b802ae366..de5eb4a2e9a 100644
--- a/packages/puppeteer-core/src/common/HTTPRequest.ts
+++ b/packages/puppeteer-core/src/common/HTTPRequest.ts
@@ -14,12 +14,11 @@
* limitations under the License.
*/
import {Protocol} from 'devtools-protocol';
-import {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
import {assert} from '../util/assert.js';
+import {CDPSession} from './Connection.js';
import {ProtocolError} from './Errors.js';
-import {EventEmitter} from './EventEmitter.js';
import {Frame} from './Frame.js';
import {HTTPResponse} from './HTTPResponse.js';
import {debugError, isString} from './util.js';
@@ -74,13 +73,6 @@ export type ResourceType = Lowercase;
*/
export const DEFAULT_INTERCEPT_RESOLUTION_PRIORITY = 0;
-interface CDPSession extends EventEmitter {
- send(
- method: T,
- ...paramArgs: ProtocolMapping.Commands[T]['paramsType']
- ): Promise;
-}
-
/**
* Represents an HTTP request sent by a page.
* @remarks
diff --git a/packages/puppeteer-core/src/common/HTTPResponse.ts b/packages/puppeteer-core/src/common/HTTPResponse.ts
index f6a42878089..028abfc9890 100644
--- a/packages/puppeteer-core/src/common/HTTPResponse.ts
+++ b/packages/puppeteer-core/src/common/HTTPResponse.ts
@@ -14,10 +14,9 @@
* limitations under the License.
*/
import {Protocol} from 'devtools-protocol';
-import {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
+import {CDPSession} from './Connection.js';
import {ProtocolError} from './Errors.js';
-import {EventEmitter} from './EventEmitter.js';
import {Frame} from './Frame.js';
import {HTTPRequest} from './HTTPRequest.js';
import {SecurityDetails} from './SecurityDetails.js';
@@ -30,13 +29,6 @@ export interface RemoteAddress {
port?: number;
}
-interface CDPSession extends EventEmitter {
- send(
- method: T,
- ...paramArgs: ProtocolMapping.Commands[T]['paramsType']
- ): Promise;
-}
-
/**
* The HTTPResponse class represents responses which are received by the
* {@link Page} class.
diff --git a/packages/puppeteer-core/src/common/Page.ts b/packages/puppeteer-core/src/common/Page.ts
index 337a3e84e5b..f4ea6706621 100644
--- a/packages/puppeteer-core/src/common/Page.ts
+++ b/packages/puppeteer-core/src/common/Page.ts
@@ -822,7 +822,7 @@ export class CDPPage extends Page {
}
const textTokens = [];
for (const arg of args) {
- const remoteObject = arg.remoteObject() as Protocol.Runtime.RemoteObject;
+ const remoteObject = arg.remoteObject();
if (remoteObject.objectId) {
textTokens.push(arg.toString());
} else {
diff --git a/packages/puppeteer-core/src/common/bidi/Connection.ts b/packages/puppeteer-core/src/common/bidi/Connection.ts
index fa8ce9f08af..f87e9718e58 100644
--- a/packages/puppeteer-core/src/common/bidi/Connection.ts
+++ b/packages/puppeteer-core/src/common/bidi/Connection.ts
@@ -52,6 +52,10 @@ interface Commands {
params: Bidi.BrowsingContext.CloseParameters;
returnType: Bidi.BrowsingContext.CloseResult;
};
+ 'browsingContext.navigate': {
+ params: Bidi.BrowsingContext.NavigateParameters;
+ returnType: Bidi.BrowsingContext.NavigateResult;
+ };
'session.new': {
params: {capabilities?: Record}; // TODO: Update Types in chromium bidi
@@ -148,17 +152,20 @@ export class Connection extends EventEmitter {
if (callback.method === 'browsingContext.create') {
this.#contexts.set(
object.result.context,
- new Context(this, object.result.context)
+ new Context(this, object.result)
);
}
callback.resolve(object);
}
}
} else {
- if ('source' in object.params && !!object.params.source.context) {
- const context = this.#contexts.get(object.params.source.context);
- context?.emit(object.method, object.params);
+ let context: Context | undefined;
+ if ('context' in object.params) {
+ context = this.#contexts.get(object.params.context);
+ } else if ('source' in object.params && !!object.params.source.context) {
+ context = this.#contexts.get(object.params.source.context);
}
+ context?.emit(object.method, object.params);
this.emit(object.method, object.params);
}
diff --git a/packages/puppeteer-core/src/common/bidi/Context.ts b/packages/puppeteer-core/src/common/bidi/Context.ts
index 73d596a9e84..fb29886aee4 100644
--- a/packages/puppeteer-core/src/common/bidi/Context.ts
+++ b/packages/puppeteer-core/src/common/bidi/Context.ts
@@ -16,8 +16,13 @@
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
+import {WaitForOptions} from '../../api/Page.js';
+import {assert} from '../../util/assert.js';
import {stringifyFunction} from '../../util/Function.js';
+import {ProtocolError, TimeoutError} from '../Errors.js';
import {EventEmitter} from '../EventEmitter.js';
+import {PuppeteerLifeCycleEvent} from '../LifecycleWatcher.js';
+import {TimeoutSettings} from '../TimeoutSettings.js';
import {EvaluateFunc, HandleFor} from '../types.js';
import {isString} from '../util.js';
@@ -26,17 +31,31 @@ import {ElementHandle} from './ElementHandle.js';
import {JSHandle} from './JSHandle.js';
import {BidiSerializer} from './Serializer.js';
+/**
+ * @internal
+ */
+const puppeteerToReadinessState = new Map<
+ PuppeteerLifeCycleEvent,
+ Bidi.BrowsingContext.ReadinessState
+>([
+ ['load', 'complete'],
+ ['domcontentloaded', 'interactive'],
+]);
+
/**
* @internal
*/
export class Context extends EventEmitter {
#connection: Connection;
+ #url: string;
_contextId: string;
+ _timeoutSettings = new TimeoutSettings();
- constructor(connection: Connection, contextId: string) {
+ constructor(connection: Connection, result: Bidi.BrowsingContext.Info) {
super();
this.#connection = connection;
- this._contextId = contextId;
+ this._contextId = result.context;
+ this.#url = result.url;
}
get connection(): Connection {
@@ -124,6 +143,76 @@ export class Context extends EventEmitter {
? BidiSerializer.deserialize(result.result)
: getBidiHandle(this, result.result);
}
+
+ async goto(
+ url: string,
+ options: WaitForOptions & {
+ referer?: string | undefined;
+ referrerPolicy?: string | undefined;
+ } = {}
+ ): Promise {
+ const {waitUntil = 'load'} = options;
+
+ try {
+ const response = await Promise.race([
+ this.connection.send('browsingContext.navigate', {
+ url: url,
+ context: this.id,
+ wait: getWaitUntil(waitUntil),
+ }),
+ new Promise((_, reject) => {
+ const timeout =
+ options.timeout ?? this._timeoutSettings.navigationTimeout();
+ if (!timeout) {
+ return;
+ }
+ const error = new TimeoutError(
+ 'Navigation timeout of ' + timeout + ' ms exceeded'
+ );
+ return setTimeout(() => {
+ return reject(error);
+ }, timeout);
+ }),
+ ]);
+ this.#url = (response as Bidi.BrowsingContext.NavigateResult).result.url;
+ return null;
+ } catch (error) {
+ if (error instanceof ProtocolError) {
+ error.message += ` at ${url}`;
+ }
+ throw error;
+ }
+
+ function getWaitUntil(
+ event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]
+ ): Bidi.BrowsingContext.ReadinessState {
+ if (Array.isArray(event) && event.length > 1) {
+ throw new Error('BiDi support only single `waitUntil` argument');
+ }
+ const waitUntilSingle = Array.isArray(event)
+ ? (event.find(lifecycle => {
+ return lifecycle === 'domcontentloaded' || lifecycle === 'load';
+ }) as PuppeteerLifeCycleEvent)
+ : event;
+
+ if (
+ waitUntilSingle === 'networkidle0' ||
+ waitUntilSingle === 'networkidle2'
+ ) {
+ throw new Error(`BiDi does not support 'waitUntil' ${waitUntilSingle}`);
+ }
+
+ assert(waitUntilSingle, `Invalid waitUntil option ${waitUntilSingle}`);
+
+ return puppeteerToReadinessState.get(
+ waitUntilSingle
+ ) as Bidi.BrowsingContext.ReadinessState;
+ }
+ }
+
+ url(): string {
+ return this.#url;
+ }
}
/**
diff --git a/packages/puppeteer-core/src/common/bidi/Page.ts b/packages/puppeteer-core/src/common/bidi/Page.ts
index 1d48c01ade9..f4015171e30 100644
--- a/packages/puppeteer-core/src/common/bidi/Page.ts
+++ b/packages/puppeteer-core/src/common/bidi/Page.ts
@@ -16,8 +16,13 @@
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
-import {Page as PageBase, PageEmittedEvents} from '../../api/Page.js';
+import {
+ Page as PageBase,
+ PageEmittedEvents,
+ WaitForOptions,
+} from '../../api/Page.js';
import {ConsoleMessage, ConsoleMessageLocation} from '../ConsoleMessage.js';
+import {HTTPResponse} from '../HTTPResponse.js';
import {EvaluateFunc, HandleFor} from '../types.js';
import {Context, getBidiHandle} from './Context.js';
@@ -30,8 +35,11 @@ export class Page extends PageBase {
#context: Context;
#subscribedEvents = [
'log.entryAdded',
+ 'browsingContext.load',
] as Bidi.Session.SubscribeParameters['events'];
+
#boundOnLogEntryAdded = this.#onLogEntryAdded.bind(this);
+ #boundOnLoaded = this.#onLoad.bind(this);
constructor(context: Context) {
super();
@@ -43,6 +51,7 @@ export class Page extends PageBase {
});
this.#context.on('log.entryAdded', this.#boundOnLogEntryAdded);
+ this.#context.on('browsingContext.load', this.#boundOnLoaded);
}
#onLogEntryAdded(event: Bidi.Log.LogEntry): void {
@@ -82,6 +91,10 @@ export class Page extends PageBase {
}
}
+ #onLoad(_event: Bidi.BrowsingContext.NavigationInfo): void {
+ this.emit(PageEmittedEvents.Load);
+ }
+
override async close(): Promise {
await this.#context.connection.send('session.unsubscribe', {
events: this.#subscribedEvents,
@@ -93,6 +106,7 @@ export class Page extends PageBase {
});
this.#context.off('log.entryAdded', this.#boundOnLogEntryAdded);
+ this.#context.off('browsingContext.load', this.#boundOnLogEntryAdded);
}
override async evaluateHandle<
@@ -114,6 +128,28 @@ export class Page extends PageBase {
): Promise>> {
return this.#context.evaluate(pageFunction, ...args);
}
+
+ override async goto(
+ url: string,
+ options?: WaitForOptions & {
+ referer?: string | undefined;
+ referrerPolicy?: string | undefined;
+ }
+ ): Promise {
+ return this.#context.goto(url, options);
+ }
+
+ override url(): string {
+ return this.#context.url();
+ }
+
+ override setDefaultNavigationTimeout(timeout: number): void {
+ this.#context._timeoutSettings.setDefaultNavigationTimeout(timeout);
+ }
+
+ override setDefaultTimeout(timeout: number): void {
+ this.#context._timeoutSettings.setDefaultTimeout(timeout);
+ }
}
function isConsoleLogEntry(
diff --git a/test/TestExpectations.json b/test/TestExpectations.json
index e0d1975fbb6..4bbbcd8382a 100644
--- a/test/TestExpectations.json
+++ b/test/TestExpectations.json
@@ -1817,6 +1817,12 @@
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
+ {
+ "testIdPattern": "[jshandle.spec] JSHandle Page.evaluateHandle should accept object handle as an argument",
+ "platforms": ["darwin"],
+ "parameters": ["firefox", "webDriverBiDi"],
+ "expectations": ["PASS", "FAIL"]
+ },
{
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors",
"platforms": ["darwin", "linux", "win32"],
@@ -1840,5 +1846,227 @@
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec]",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["PASS"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should work with redirects",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["chrome", "webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should return response when page changes its URL after load",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to empty page with domcontentloaded",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should work when page calls history API in beforeunload",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to empty page with networkidle0",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to empty page with networkidle2",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should work when navigating to valid url",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should work when navigating to data url",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should work when navigating to 404",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should not throw an error for a 404 response with an empty body",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should not throw an error for a 500 response with an empty body",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should return last response in redirect chain",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should wait for network idle to succeed navigation",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to dataURL and fire dataURL requests",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to URL with hash and fire requests without hash",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should work with self requesting page",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should send referer",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with both domcontentloaded and load",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with clicking on anchor links",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.pushState()",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.replaceState()",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with DOM history.back()/history.forward()",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work when subframe issues window.stop()",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL", "TIMEOUT"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goBack should work",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goBack should work with HistoryAPI",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Frame.goto should navigate subframes",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Frame.goto should reject when frame detaches",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Frame.goto should return matching responses",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should work",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should fail when frame detaches",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.reload should work",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad url",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["firefox", "webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL after redirects",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["firefox", "webDriverBiDi"],
+ "expectations": ["FAIL"]
+ },
+ {
+ "testIdPattern": "[navigation.spec] navigation \"after all\" hook in \"navigation\"",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["firefox", "headless", "webDriverBiDi"],
+ "expectations": ["FAIL"]
}
]
diff --git a/test/src/navigation.spec.ts b/test/src/navigation.spec.ts
index 38fb6cc8607..6a79934d2b4 100644
--- a/test/src/navigation.spec.ts
+++ b/test/src/navigation.spec.ts
@@ -25,11 +25,12 @@ import {
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} from './mocha-utils.js';
-import utils from './utils.js';
+import {attachFrame, isFavicon, waitEvent} from './utils.js';
describe('navigation', function () {
setupTestBrowserHooks();
setupTestPageAndContextHooks();
+
describe('Page.goto', function () {
it('should work', async () => {
const {page, server} = getTestState();
@@ -361,10 +362,14 @@ describe('navigation', function () {
server.waitForRequest('/fetch-request-a.js'),
server.waitForRequest('/fetch-request-b.js'),
server.waitForRequest('/fetch-request-c.js'),
- ]);
- const secondFetchResourceRequested = server.waitForRequest(
- '/fetch-request-d.js'
- );
+ ]).catch(() => {
+ // Ignore Error that arise from test server during hooks
+ });
+ const secondFetchResourceRequested = server
+ .waitForRequest('/fetch-request-d.js')
+ .catch(() => {
+ // Ignore Error that arise from test server during hooks
+ });
// Navigate to a page which loads immediately and then does a bunch of
// requests via javascript's fetch method.
@@ -466,7 +471,7 @@ describe('navigation', function () {
const requests: HTTPRequest[] = [];
page.on('request', request => {
- return !utils.isFavicon(request) && requests.push(request);
+ return !isFavicon(request) && requests.push(request);
});
const dataURL = 'data:text/html,yo
';
const response = (await page.goto(dataURL))!;
@@ -479,7 +484,7 @@ describe('navigation', function () {
const requests: HTTPRequest[] = [];
page.on('request', request => {
- return !utils.isFavicon(request) && requests.push(request);
+ return !isFavicon(request) && requests.push(request);
});
const response = (await page.goto(server.EMPTY_PAGE + '#hash'))!;
expect(response.status()).toBe(200);
@@ -509,13 +514,17 @@ describe('navigation', function () {
it('should send referer', async () => {
const {page, server} = getTestState();
- const [request1, request2] = await Promise.all([
+ const requests = Promise.all([
server.waitForRequest('/grid.html'),
server.waitForRequest('/digits/1.png'),
page.goto(server.PREFIX + '/grid.html', {
referer: 'http://google.com/',
}),
- ]);
+ ]).catch(() => {
+ return [];
+ });
+
+ const [request1, request2] = await requests;
expect(request1.headers['referer']).toBe('http://google.com/');
// Make sure subresources do not inherit referer.
expect(request2.headers['referer']).toBe(server.PREFIX + '/grid.html');
@@ -530,7 +539,9 @@ describe('navigation', function () {
page.goto(server.PREFIX + '/grid.html', {
referrerPolicy: 'no-referer',
}),
- ]);
+ ]).catch(() => {
+ return [];
+ });
expect(request1.headers['referer']).toBeUndefined();
expect(request2.headers['referer']).toBe(server.PREFIX + '/grid.html');
});
@@ -571,7 +582,7 @@ describe('navigation', function () {
return (bothFired = true);
});
- await server.waitForRequest('/one-style.css');
+ await server.waitForRequest('/one-style.css').catch(() => {});
await domContentLoadedPromise;
expect(bothFired).toBe(false);
response.end();
@@ -659,7 +670,7 @@ describe('navigation', function () {
const navigationPromise = page.goto(
server.PREFIX + '/frames/one-frame.html'
);
- const frame = await utils.waitEvent(page, 'frameattached');
+ const frame = await waitEvent(page, 'frameattached');
await new Promise(fulfill => {
page.on('framenavigated', f => {
if (f === frame) {
@@ -737,7 +748,7 @@ describe('navigation', function () {
.catch(error_ => {
return error_;
});
- await server.waitForRequest('/empty.html');
+ await server.waitForRequest('/empty.html').catch(() => {});
await page.$eval('iframe', frame => {
return frame.remove();
@@ -753,9 +764,9 @@ describe('navigation', function () {
await page.goto(server.EMPTY_PAGE);
// Attach three frames.
const frames = await Promise.all([
- utils.attachFrame(page, 'frame1', server.EMPTY_PAGE),
- utils.attachFrame(page, 'frame2', server.EMPTY_PAGE),
- utils.attachFrame(page, 'frame3', server.EMPTY_PAGE),
+ attachFrame(page, 'frame1', server.EMPTY_PAGE),
+ attachFrame(page, 'frame2', server.EMPTY_PAGE),
+ attachFrame(page, 'frame3', server.EMPTY_PAGE),
]);
// Navigate all frames to the same URL.
const serverResponses: ServerResponse[] = [];