Bug 1884090 - [remote] Add support for "HTTP flag" in WebDriver Session. r=webdriver-reviewers,jdescottes

Differential Revision: https://phabricator.services.mozilla.com/D211815
This commit is contained in:
Henrik Skupin 2024-05-29 08:40:49 +00:00
parent 9406e9ecd1
commit 9c60f55dee
8 changed files with 263 additions and 129 deletions

View file

@ -115,6 +115,9 @@ export function GeckoDriver(server) {
// WebDriver Session
this._currentSession = null;
// Flag to indicate a WebDriver HTTP session
this._flags = new Set([lazy.WebDriverSession.SESSION_FLAG_HTTP]);
// Flag to indicate that the application is shutting down
this._isShuttingDown = false;
@ -401,14 +404,20 @@ GeckoDriver.prototype.newSession = async function (cmd) {
const { parameters: capabilities } = cmd;
try {
// If the WebDriver BiDi protocol is active always use the Remote Agent
// to handle the WebDriver session. If it's not the case then Marionette
// itself needs to handle it, and has to nullify the "webSocketUrl"
// capability.
if (lazy.RemoteAgent.webDriverBiDi) {
await lazy.RemoteAgent.webDriverBiDi.createSession(capabilities);
// If the WebDriver BiDi protocol is active always use the Remote Agent
// to handle the WebDriver session.
await lazy.RemoteAgent.webDriverBiDi.createSession(
capabilities,
this._flags
);
} else {
this._currentSession = new lazy.WebDriverSession(capabilities);
// If it's not the case then Marionette itself needs to handle it, and
// has to nullify the "webSocketUrl" capability.
this._currentSession = new lazy.WebDriverSession(
capabilities,
this._flags
);
this._currentSession.capabilities.delete("webSocketUrl");
}

View file

@ -12,7 +12,7 @@ const { error } = ChromeUtils.importESModule(
);
add_task(async function test_execute_missing_command_error() {
const session = new WebDriverSession();
const session = new WebDriverSession({}, new Set());
info("Attempt to execute an unknown protocol command");
await Assert.rejects(
@ -24,7 +24,7 @@ add_task(async function test_execute_missing_command_error() {
});
add_task(async function test_execute_missing_internal_command_error() {
const session = new WebDriverSession();
const session = new WebDriverSession({}, new Set());
info(
"Attempt to execute a protocol command which relies on an unknown internal method"

View file

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
@ -14,21 +16,45 @@ ChromeUtils.defineESModuleGetters(lazy, {
"chrome://remote/content/shared/webdriver/UserPromptHandler.sys.mjs",
});
ChromeUtils.defineLazyGetter(lazy, "debuggerAddress", () => {
return lazy.RemoteAgent.running && lazy.RemoteAgent.cdp
? lazy.remoteAgent.debuggerAddress
: null;
});
ChromeUtils.defineLazyGetter(lazy, "isHeadless", () => {
return Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless;
});
ChromeUtils.defineLazyGetter(lazy, "remoteAgent", () => {
return Cc["@mozilla.org/remote/agent;1"].createInstance(Ci.nsIRemoteAgent);
});
ChromeUtils.defineLazyGetter(lazy, "userAgent", () => {
return Cc["@mozilla.org/network/protocol;1?name=http"].getService(
Ci.nsIHttpProtocolHandler
).userAgent;
});
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"shutdownTimeout",
"toolkit.asyncshutdown.crash_timeout"
);
// List of capabilities which are only relevant for Webdriver Classic.
export const WEBDRIVER_CLASSIC_CAPABILITIES = [
"pageLoadStrategy",
"timeouts",
"strictFileInteractability",
"timeouts",
"unhandledPromptBehavior",
"webSocketUrl",
"moz:useNonSpecCompliantPointerOrigin",
"moz:webdriverClick",
// Gecko specific capabilities
"moz:debuggerAddress",
"moz:firefoxOptions",
"moz:useNonSpecCompliantPointerOrigin",
"moz:webdriverClick",
];
/** Representation of WebDriver session timeouts. */
@ -90,7 +116,7 @@ export class Timeouts {
default:
throw new lazy.error.InvalidArgumentError(
"Unrecognised timeout: " + type
`Unrecognized timeout: ${type}`
);
}
}
@ -407,51 +433,36 @@ export class Proxy {
}
}
/** WebDriver session capabilities representation. */
export class Capabilities extends Map {
/** @class */
/**
* WebDriver session capabilities representation.
*/
constructor() {
// Default values for capabilities supported by both WebDriver protocols
super([
// webdriver
["browserName", getWebDriverBrowserName()],
["browserVersion", lazy.AppInfo.version],
["platformName", getWebDriverPlatformName()],
["acceptInsecureCerts", false],
["pageLoadStrategy", PageLoadStrategy.Normal],
["proxy", new Proxy()],
["setWindowRect", !lazy.AppInfo.isAndroid],
["timeouts", new Timeouts()],
["strictFileInteractability", false],
["unhandledPromptBehavior", new lazy.UserPromptHandler()],
[
"userAgent",
Cc["@mozilla.org/network/protocol;1?name=http"].getService(
Ci.nsIHttpProtocolHandler
).userAgent,
],
["webSocketUrl", null],
["userAgent", lazy.userAgent],
// proprietary
// HTTP only capabilities
["pageLoadStrategy", PageLoadStrategy.Normal],
["timeouts", new Timeouts()],
["setWindowRect", !lazy.AppInfo.isAndroid],
["strictFileInteractability", false],
// Gecko specific capabilities
["moz:accessibilityChecks", false],
["moz:buildID", lazy.AppInfo.appBuildID],
[
"moz:debuggerAddress",
// With bug 1715481 fixed always use the Remote Agent instance
lazy.RemoteAgent.running && lazy.RemoteAgent.cdp
? lazy.remoteAgent.debuggerAddress
: null,
],
[
"moz:headless",
Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless,
],
["moz:debuggerAddress", lazy.debuggerAddress],
["moz:headless", lazy.isHeadless],
["moz:platformVersion", Services.sysinfo.getProperty("version")],
["moz:processID", lazy.AppInfo.processID],
["moz:profile", maybeProfile()],
[
"moz:shutdownTimeout",
Services.prefs.getIntPref("toolkit.asyncshutdown.crash_timeout"),
],
["moz:shutdownTimeout", lazy.shutdownTimeout],
["moz:webdriverClick", true],
["moz:windowless", false],
]);
@ -478,7 +489,7 @@ export class Capabilities extends Map {
}
/**
* JSON serialisation of capabilities object.
* JSON serialization of capabilities object.
*
* @returns {Object<string, ?>}
*/
@ -501,11 +512,13 @@ export class Capabilities extends Map {
*
* @param {Object<string, *>=} json
* WebDriver capabilities.
* @param {boolean=} isHttp
* Flag indicating that it is a WebDriver classic session. Defaults to false.
*
* @returns {Capabilities}
* Internal representation of WebDriver capabilities.
*/
static fromJSON(json) {
static fromJSON(json, isHttp = false) {
if (typeof json == "undefined" || json === null) {
json = {};
}
@ -518,6 +531,11 @@ export class Capabilities extends Map {
// TODO: Bug 1823907. We can start using here spec compliant method `validate`,
// as soon as `desiredCapabilities` and `requiredCapabilities` are not supported.
for (let [k, v] of Object.entries(json)) {
if (!isHttp && WEBDRIVER_CLASSIC_CAPABILITIES.includes(k)) {
// Ignore any WebDriver classic capability for a WebDriver BiDi session.
continue;
}
switch (k) {
case "acceptInsecureCerts":
lazy.assert.boolean(

View file

@ -32,10 +32,31 @@ ChromeUtils.defineLazyGetter(lazy, "logger", () => lazy.Log.get());
// Global singleton that holds active WebDriver sessions
const webDriverSessions = new Map();
/**
* @typedef {Set} SessionConfigurationFlags
* A set of flags defining the features of a WebDriver session. It can be
* empty or contain entries as listed below. External specifications may
* define additional flags, or create sessions without the HTTP flag.
*
* <dl>
* <dt><code>"http"</code> (string)
* <dd>Flag indicating a WebDriver classic (HTTP) session.
* </dl>
*/
/**
* Representation of WebDriver session.
*/
export class WebDriverSession {
#capabilities;
#connections;
#http;
#id;
#messageHandler;
#path;
static SESSION_FLAG_HTTP = "http";
/**
* Construct a new WebDriver session.
*
@ -52,23 +73,22 @@ export class WebDriverSession {
* are implicitly trusted on navigation for the duration of the session.
*
* <dt><code>pageLoadStrategy</code> (string)
* <dd>The page load strategy to use for the current session. Must be
* <dd>(HTTP only) The page load strategy to use for the current session. Must be
* one of "<tt>none</tt>", "<tt>eager</tt>", and "<tt>normal</tt>".
*
* <dt><code>proxy</code> (Proxy object)
* <dd>Defines the proxy configuration.
*
* <dt><code>setWindowRect</code> (boolean)
* <dd>Indicates whether the remote end supports all of the resizing
* <dd>(HTTP only) Indicates whether the remote end supports all of the resizing
* and repositioning commands.
*
* <dt><code>strictFileInteractability</code> (boolean)
* <dd>Defines the current sessions strict file interactability.
* <dd>(HTTP only) Defines the current sessions strict file interactability.
*
* <dt><code>timeouts</code> (Timeouts object)
* <dd>Describes the timeouts imposed on certian session operations.
* <dd>(HTTP only) Describes the timeouts imposed on certain session operations.
*
* TODO: update for WebDriver BiDi type
* <dt><code>unhandledPromptBehavior</code> (string)
* <dd>Describes the current sessions user prompt handler. Must be one of
* "<tt>accept</tt>", "<tt>accept and notify</tt>", "<tt>dismiss</tt>",
@ -76,13 +96,13 @@ export class WebDriverSession {
* "<tt>dismiss and notify</tt>" state.
*
* <dt><code>moz:accessibilityChecks</code> (boolean)
* <dd>Run a11y checks when clicking elements.
* <dd>(HTTP only) Run a11y checks when clicking elements.
*
* <dt><code>moz:debuggerAddress</code> (boolean)
* <dd>Indicate that the Chrome DevTools Protocol (CDP) has to be enabled.
*
* <dt><code>moz:webdriverClick</code> (boolean)
* <dd>Use a WebDriver conforming <i>WebDriver::ElementClick</i>.
* <dd>(HTTP only) Use a WebDriver conforming <i>WebDriver::ElementClick</i>.
* </dl>
*
* <h4>WebAuthn</h4>
@ -140,7 +160,7 @@ export class WebDriverSession {
* <code>proxyType</code> is "<tt>manual</tt>".
*
* <dt><code>noProxy</code> (string)
* <dd>Lists the adress for which the proxy should be bypassed when
* <dd>Lists the address for which the proxy should be bypassed when
* the <code>proxyType</code> is "<tt>manual</tt>". Must be a JSON
* List containing any number of any of domains, IPv4 addresses, or IPv6
* addresses.
@ -168,9 +188,10 @@ export class WebDriverSession {
* </code></pre>
*
* @param {Object<string, *>=} capabilities
* JSON Object containing any of the recognised capabilities listed
* JSON Object containing any of the recognized capabilities listed
* above.
*
* @param {SessionConfigurationFlags} flags
* Session configuration flags.
* @param {WebDriverBiDiConnection=} connection
* An optional existing WebDriver BiDi connection to associate with the
* new session.
@ -178,19 +199,20 @@ export class WebDriverSession {
* @throws {SessionNotCreatedError}
* If, for whatever reason, a session could not be created.
*/
constructor(capabilities, connection) {
constructor(capabilities, flags, connection) {
// WebSocket connections that use this session. This also accounts for
// possible disconnects due to network outages, which require clients
// to reconnect.
this._connections = new Set();
this.#connections = new Set();
this.id = lazy.generateUUID();
this.#id = lazy.generateUUID();
this.#http = flags.has(WebDriverSession.SESSION_FLAG_HTTP);
// Define the HTTP path to query this session via WebDriver BiDi
this.path = `/session/${this.id}`;
this.#path = `/session/${this.#id}`;
try {
this.capabilities = lazy.Capabilities.fromJSON(capabilities, this.path);
this.#capabilities = lazy.Capabilities.fromJSON(capabilities, this.#http);
} catch (e) {
throw new lazy.error.SessionNotCreatedError(e);
}
@ -201,7 +223,7 @@ export class WebDriverSession {
);
}
if (this.capabilities.get("acceptInsecureCerts")) {
if (this.acceptInsecureCerts) {
lazy.logger.warn(
"TLS certificate errors will be ignored for this session"
);
@ -219,7 +241,7 @@ export class WebDriverSession {
// immediately register the newly created session for it.
if (connection) {
connection.registerSession(this);
this._connections.add(connection);
this.#connections.add(connection);
}
// Maps a Navigable (browsing context or content browser for top-level
@ -228,11 +250,11 @@ export class WebDriverSession {
lazy.registerProcessDataActor();
webDriverSessions.set(this.id, this);
webDriverSessions.set(this.#id, this);
}
destroy() {
webDriverSessions.delete(this.id);
webDriverSessions.delete(this.#id);
lazy.unregisterProcessDataActor();
@ -241,20 +263,20 @@ export class WebDriverSession {
lazy.allowAllCerts.disable();
// Close all open connections which unregister themselves.
this._connections.forEach(connection => connection.close());
if (this._connections.size > 0) {
this.#connections.forEach(connection => connection.close());
if (this.#connections.size > 0) {
lazy.logger.warn(
`Failed to close ${this._connections.size} WebSocket connections`
`Failed to close ${this.#connections.size} WebSocket connections`
);
}
// Destroy the dedicated MessageHandler instance if we created one.
if (this._messageHandler) {
this._messageHandler.off(
if (this.#messageHandler) {
this.#messageHandler.off(
"message-handler-protocol-event",
this._onMessageHandlerProtocolEvent
);
this._messageHandler.destroy();
this.#messageHandler.destroy();
}
}
@ -282,46 +304,66 @@ export class WebDriverSession {
}
get a11yChecks() {
return this.capabilities.get("moz:accessibilityChecks");
return this.#capabilities.get("moz:accessibilityChecks");
}
get acceptInsecureCerts() {
return this.#capabilities.get("acceptInsecureCerts");
}
get capabilities() {
return this.#capabilities;
}
get http() {
return this.#http;
}
get id() {
return this.#id;
}
get messageHandler() {
if (!this._messageHandler) {
this._messageHandler =
lazy.RootMessageHandlerRegistry.getOrCreateMessageHandler(this.id);
if (!this.#messageHandler) {
this.#messageHandler =
lazy.RootMessageHandlerRegistry.getOrCreateMessageHandler(this.#id);
this._onMessageHandlerProtocolEvent =
this._onMessageHandlerProtocolEvent.bind(this);
this._messageHandler.on(
this.#messageHandler.on(
"message-handler-protocol-event",
this._onMessageHandlerProtocolEvent
);
}
return this._messageHandler;
return this.#messageHandler;
}
get pageLoadStrategy() {
return this.capabilities.get("pageLoadStrategy");
return this.#capabilities.get("pageLoadStrategy");
}
get path() {
return this.#path;
}
get proxy() {
return this.capabilities.get("proxy");
return this.#capabilities.get("proxy");
}
get strictFileInteractability() {
return this.capabilities.get("strictFileInteractability");
return this.#capabilities.get("strictFileInteractability");
}
get timeouts() {
return this.capabilities.get("timeouts");
return this.#capabilities.get("timeouts");
}
set timeouts(timeouts) {
this.capabilities.set("timeouts", timeouts);
this.#capabilities.set("timeouts", timeouts);
}
get userPromptHandler() {
return this.capabilities.get("unhandledPromptBehavior");
return this.#capabilities.get("unhandledPromptBehavior");
}
/**
@ -330,15 +372,15 @@ export class WebDriverSession {
* @param {WebDriverBiDiConnection} connection
*/
removeConnection(connection) {
if (this._connections.has(connection)) {
this._connections.delete(connection);
if (this.#connections.has(connection)) {
this.#connections.delete(connection);
} else {
lazy.logger.warn("Trying to remove a connection that doesn't exist.");
}
}
toString() {
return `[object ${this.constructor.name} ${this.id}]`;
return `[object ${this.constructor.name} ${this.#id}]`;
}
// nsIHttpRequestHandler
@ -362,12 +404,12 @@ export class WebDriverSession {
response._connection
);
conn.registerSession(this);
this._connections.add(conn);
this.#connections.add(conn);
}
_onMessageHandlerProtocolEvent(eventName, messageHandlerEvent) {
const { name, data } = messageHandlerEvent;
this._connections.forEach(connection => connection.sendEvent(name, data));
this.#connections.forEach(connection => connection.sendEvent(name, data));
}
// XPCOM

View file

@ -50,7 +50,7 @@ add_task(function test_Timeouts_fromJSON() {
equal(ts.script, json.script);
});
add_task(function test_Timeouts_fromJSON_unrecognised_field() {
add_task(function test_Timeouts_fromJSON_unrecognized_field() {
let json = {
sessionId: "foobar",
};
@ -58,7 +58,7 @@ add_task(function test_Timeouts_fromJSON_unrecognised_field() {
Timeouts.fromJSON(json);
} catch (e) {
equal(e.name, error.InvalidArgumentError.name);
equal(e.message, "Unrecognised timeout: sessionId");
equal(e.message, "Unrecognized timeout: sessionId");
}
});
@ -439,27 +439,53 @@ add_task(function test_Capabilities_fromJSON() {
caps = fromJSON({ acceptInsecureCerts: false });
equal(false, caps.get("acceptInsecureCerts"));
for (let strategy of Object.values(PageLoadStrategy)) {
caps = fromJSON({ pageLoadStrategy: strategy });
equal(strategy, caps.get("pageLoadStrategy"));
}
let proxyConfig = { proxyType: "manual" };
caps = fromJSON({ proxy: proxyConfig });
equal("manual", caps.get("proxy").proxyType);
// HTTP only capabilities
for (let strategy of Object.values(PageLoadStrategy)) {
caps = fromJSON({ pageLoadStrategy: strategy }, true);
equal(strategy, caps.get("pageLoadStrategy"));
caps = fromJSON({ pageLoadStrategy: strategy });
equal("normal", caps.get("pageLoadStrategy"));
}
let timeoutsConfig = { implicit: 123 };
caps = fromJSON({ timeouts: timeoutsConfig });
equal(0, caps.get("timeouts").implicit);
caps = fromJSON({ timeouts: timeoutsConfig }, true);
equal(123, caps.get("timeouts").implicit);
caps = fromJSON({ strictFileInteractability: false });
caps = fromJSON({ strictFileInteractability: false }, true);
equal(false, caps.get("strictFileInteractability"));
caps = fromJSON({ strictFileInteractability: true });
caps = fromJSON({ strictFileInteractability: true }, true);
equal(true, caps.get("strictFileInteractability"));
caps = fromJSON({ webSocketUrl: true });
caps = fromJSON({ webSocketUrl: true }, true);
equal(true, caps.get("webSocketUrl"));
// Mozilla specific capabilities
caps = fromJSON({ "moz:accessibilityChecks": true });
equal(true, caps.get("moz:accessibilityChecks"));
caps = fromJSON({ "moz:accessibilityChecks": false });
equal(false, caps.get("moz:accessibilityChecks"));
caps = fromJSON({ "moz:webdriverClick": true }, true);
equal(true, caps.get("moz:webdriverClick"));
caps = fromJSON({ "moz:webdriverClick": false }, true);
equal(false, caps.get("moz:webdriverClick"));
// capability is always populated with null if remote agent is not listening
caps = fromJSON({});
equal(null, caps.get("moz:debuggerAddress"));
caps = fromJSON({ "moz:debuggerAddress": "foo" });
equal(null, caps.get("moz:debuggerAddress"));
caps = fromJSON({ "moz:debuggerAddress": true });
equal(null, caps.get("moz:debuggerAddress"));
// Extension capabilities
caps = fromJSON({ "webauthn:virtualAuthenticators": true });
equal(true, caps.get("webauthn:virtualAuthenticators"));
caps = fromJSON({ "webauthn:virtualAuthenticators": false });
@ -505,31 +531,13 @@ add_task(function test_Capabilities_fromJSON() {
/InvalidArgumentError/
);
caps = fromJSON({ "moz:accessibilityChecks": true });
equal(true, caps.get("moz:accessibilityChecks"));
caps = fromJSON({ "moz:accessibilityChecks": false });
equal(false, caps.get("moz:accessibilityChecks"));
// capability is always populated with null if remote agent is not listening
caps = fromJSON({});
equal(null, caps.get("moz:debuggerAddress"));
caps = fromJSON({ "moz:debuggerAddress": "foo" });
equal(null, caps.get("moz:debuggerAddress"));
caps = fromJSON({ "moz:debuggerAddress": true });
equal(null, caps.get("moz:debuggerAddress"));
caps = fromJSON({ "moz:webdriverClick": true });
equal(true, caps.get("moz:webdriverClick"));
caps = fromJSON({ "moz:webdriverClick": false });
equal(false, caps.get("moz:webdriverClick"));
// No longer supported capabilities
Assert.throws(
() => fromJSON({ "moz:useNonSpecCompliantPointerOrigin": false }),
() => fromJSON({ "moz:useNonSpecCompliantPointerOrigin": false }, true),
/InvalidArgumentError/
);
Assert.throws(
() => fromJSON({ "moz:useNonSpecCompliantPointerOrigin": true }),
() => fromJSON({ "moz:useNonSpecCompliantPointerOrigin": true }, true),
/InvalidArgumentError/
);
});

View file

@ -4,7 +4,7 @@
"use strict";
const { Capabilities, Timeouts } = ChromeUtils.importESModule(
const { Timeouts } = ChromeUtils.importESModule(
"chrome://remote/content/shared/webdriver/Capabilities.sys.mjs"
);
const { getWebDriverSessionById, WebDriverSession } =
@ -12,26 +12,79 @@ const { getWebDriverSessionById, WebDriverSession } =
"chrome://remote/content/shared/webdriver/Session.sys.mjs"
);
add_task(function test_WebDriverSession_ctor() {
const session = new WebDriverSession();
function createSession(options = {}) {
const { capabilities = {}, connection, isHttp = false } = options;
const flags = new Set();
if (isHttp) {
flags.add("http");
}
return new WebDriverSession(capabilities, flags, connection);
}
add_task(function test_WebDriverSession_ctor() {
Assert.throws(() => new WebDriverSession({}), /TypeError/);
// Session id and path
let session = createSession();
equal(typeof session.id, "string");
ok(session.capabilities instanceof Capabilities);
equal(session.path, `/session/${session.id}`);
// Sets HTTP flag
session = createSession({ isHttp: true });
equal(session.http, true);
session = createSession({ isHttp: false });
equal(session.http, false);
// Sets capabilities based on session configuration flag.
const capabilities = {
acceptInsecureCerts: true,
unhandledPromptBehavior: "ignore",
// HTTP only
pageLoadStrategy: "eager",
strictFileInteractability: true,
timeouts: { script: 1000 },
};
// HTTP session
session = createSession({ isHttp: true, capabilities });
equal(session.acceptInsecureCerts, true);
equal(session.pageLoadStrategy, "eager");
equal(session.strictFileInteractability, true);
equal(session.timeouts.script, 1000);
equal(session.userPromptHandler.toJSON(), "ignore");
// BiDi session (uses default values for HTTP only capabilities)
session = createSession({ isHttp: false, capabilities });
equal(session.acceptInsecureCerts, true);
equal(session.pageLoadStrategy, "normal");
equal(session.strictFileInteractability, false);
equal(session.timeouts.script, 30000);
equal(session.userPromptHandler.toJSON(), "dismiss and notify");
});
add_task(function test_WebDriverSession_destroy() {
const session = new WebDriverSession();
const session = createSession();
session.destroy();
// Calling twice doesn't raise error.
session.destroy();
});
add_task(function test_WebDriverSession_getters() {
const session = new WebDriverSession();
const session = createSession();
equal(
session.a11yChecks,
session.capabilities.get("moz:accessibilityChecks")
);
equal(
session.acceptInsecureCerts,
session.capabilities.get("acceptInsecureCerts")
);
equal(session.pageLoadStrategy, session.capabilities.get("pageLoadStrategy"));
equal(session.proxy, session.capabilities.get("proxy"));
equal(
@ -46,7 +99,7 @@ add_task(function test_WebDriverSession_getters() {
});
add_task(function test_WebDriverSession_setters() {
const session = new WebDriverSession();
const session = createSession();
const timeouts = new Timeouts();
timeouts.pageLoad = 45;
@ -56,8 +109,8 @@ add_task(function test_WebDriverSession_setters() {
});
add_task(function test_getWebDriverSessionById() {
const session1 = new WebDriverSession();
const session2 = new WebDriverSession();
const session1 = createSession();
const session2 = createSession();
equal(getWebDriverSessionById(session1.id), session1);
equal(getWebDriverSessionById(session2.id), session2);

View file

@ -69,7 +69,8 @@ export class WebDriverBiDi {
* @param {Object<string, *>=} capabilities
* JSON Object containing any of the recognised capabilities as listed
* on the `WebDriverSession` class.
*
* @param {Set} flags
* Session configuration flags.
* @param {WebDriverBiDiConnection=} sessionlessConnection
* Optional connection that is not yet accociated with a WebDriver
* session, and has to be associated with the new WebDriver session.
@ -80,7 +81,7 @@ export class WebDriverBiDi {
* @throws {SessionNotCreatedError}
* If, for whatever reason, a session could not be created.
*/
async createSession(capabilities, sessionlessConnection) {
async createSession(capabilities, flags, sessionlessConnection) {
if (this.session) {
throw new lazy.error.SessionNotCreatedError(
"Maximum number of active sessions"
@ -89,6 +90,7 @@ export class WebDriverBiDi {
const session = new lazy.WebDriverSession(
capabilities,
flags,
sessionlessConnection
);

View file

@ -180,13 +180,15 @@ export class WebDriverBiDiConnection extends WebSocketConnection {
if (module === "session" && command === "new") {
const processedCapabilities = lazy.processCapabilities(params);
const flags = new Set();
result = await lazy.RemoteAgent.webDriverBiDi.createSession(
processedCapabilities,
flags,
this
);
// Since in Capabilities class we setup default values also for capabilities which are
// not relevant for bidi, we want to remove them from the payload before returning to a client.
// The Capabilities class sets up default values also for capabilities
// which are not relevant for BiDi, we want to remove those from the payload.
result.capabilities = Array.from(result.capabilities.entries()).reduce(
(object, [key, value]) => {
if (!lazy.WEBDRIVER_CLASSIC_CAPABILITIES.includes(key)) {