From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../webdriver/test/xpcshell/test_Capabilities.js | 700 +++++++++++++++++++++ 1 file changed, 700 insertions(+) create mode 100644 remote/shared/webdriver/test/xpcshell/test_Capabilities.js (limited to 'remote/shared/webdriver/test/xpcshell/test_Capabilities.js') diff --git a/remote/shared/webdriver/test/xpcshell/test_Capabilities.js b/remote/shared/webdriver/test/xpcshell/test_Capabilities.js new file mode 100644 index 0000000000..19401dd463 --- /dev/null +++ b/remote/shared/webdriver/test/xpcshell/test_Capabilities.js @@ -0,0 +1,700 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +"use strict"; + +const { AppInfo } = ChromeUtils.importESModule( + "chrome://remote/content/shared/AppInfo.sys.mjs" +); +const { error } = ChromeUtils.importESModule( + "chrome://remote/content/shared/webdriver/Errors.sys.mjs" +); +const { + Capabilities, + mergeCapabilities, + PageLoadStrategy, + processCapabilities, + Proxy, + Timeouts, + UnhandledPromptBehavior, + validateCapabilities, +} = ChromeUtils.importESModule( + "chrome://remote/content/shared/webdriver/Capabilities.sys.mjs" +); + +add_task(function test_Timeouts_ctor() { + let ts = new Timeouts(); + equal(ts.implicit, 0); + equal(ts.pageLoad, 300000); + equal(ts.script, 30000); +}); + +add_task(function test_Timeouts_toString() { + equal(new Timeouts().toString(), "[object Timeouts]"); +}); + +add_task(function test_Timeouts_toJSON() { + let ts = new Timeouts(); + deepEqual(ts.toJSON(), { implicit: 0, pageLoad: 300000, script: 30000 }); +}); + +add_task(function test_Timeouts_fromJSON() { + let json = { + implicit: 0, + pageLoad: 2.0, + script: Number.MAX_SAFE_INTEGER, + }; + let ts = Timeouts.fromJSON(json); + equal(ts.implicit, json.implicit); + equal(ts.pageLoad, json.pageLoad); + equal(ts.script, json.script); +}); + +add_task(function test_Timeouts_fromJSON_unrecognised_field() { + let json = { + sessionId: "foobar", + }; + try { + Timeouts.fromJSON(json); + } catch (e) { + equal(e.name, error.InvalidArgumentError.name); + equal(e.message, "Unrecognised timeout: sessionId"); + } +}); + +add_task(function test_Timeouts_fromJSON_invalid_types() { + for (let value of [null, [], {}, false, "10", 2.5]) { + Assert.throws( + () => Timeouts.fromJSON({ implicit: value }), + /InvalidArgumentError/ + ); + } +}); + +add_task(function test_Timeouts_fromJSON_bounds() { + for (let value of [-1, Number.MAX_SAFE_INTEGER + 1]) { + Assert.throws( + () => Timeouts.fromJSON({ script: value }), + /InvalidArgumentError/ + ); + } +}); + +add_task(function test_PageLoadStrategy() { + equal(PageLoadStrategy.None, "none"); + equal(PageLoadStrategy.Eager, "eager"); + equal(PageLoadStrategy.Normal, "normal"); +}); + +add_task(function test_Proxy_ctor() { + let p = new Proxy(); + let props = [ + "proxyType", + "httpProxy", + "sslProxy", + "socksProxy", + "socksVersion", + "proxyAutoconfigUrl", + ]; + for (let prop of props) { + ok(prop in p, `${prop} in ${JSON.stringify(props)}`); + equal(p[prop], null); + } +}); + +add_task(function test_Proxy_init() { + let p = new Proxy(); + + // no changed made, and 5 (system) is default + equal(p.init(), false); + equal(Services.prefs.getIntPref("network.proxy.type"), 5); + + // pac + p.proxyType = "pac"; + p.proxyAutoconfigUrl = "http://localhost:1234"; + ok(p.init()); + + equal(Services.prefs.getIntPref("network.proxy.type"), 2); + equal( + Services.prefs.getStringPref("network.proxy.autoconfig_url"), + "http://localhost:1234" + ); + + // direct + p = new Proxy(); + p.proxyType = "direct"; + ok(p.init()); + equal(Services.prefs.getIntPref("network.proxy.type"), 0); + + // autodetect + p = new Proxy(); + p.proxyType = "autodetect"; + ok(p.init()); + equal(Services.prefs.getIntPref("network.proxy.type"), 4); + + // system + p = new Proxy(); + p.proxyType = "system"; + ok(p.init()); + equal(Services.prefs.getIntPref("network.proxy.type"), 5); + + // manual + for (let proxy of ["http", "ssl", "socks"]) { + p = new Proxy(); + p.proxyType = "manual"; + p.noProxy = ["foo", "bar"]; + p[`${proxy}Proxy`] = "foo"; + p[`${proxy}ProxyPort`] = 42; + if (proxy === "socks") { + p[`${proxy}Version`] = 4; + } + + ok(p.init()); + equal(Services.prefs.getIntPref("network.proxy.type"), 1); + equal( + Services.prefs.getStringPref("network.proxy.no_proxies_on"), + "foo, bar" + ); + equal(Services.prefs.getStringPref(`network.proxy.${proxy}`), "foo"); + equal(Services.prefs.getIntPref(`network.proxy.${proxy}_port`), 42); + if (proxy === "socks") { + equal(Services.prefs.getIntPref(`network.proxy.${proxy}_version`), 4); + } + } + + // empty no proxy should reset default exclustions + p = new Proxy(); + p.proxyType = "manual"; + p.noProxy = []; + ok(p.init()); + equal(Services.prefs.getStringPref("network.proxy.no_proxies_on"), ""); +}); + +add_task(function test_Proxy_toString() { + equal(new Proxy().toString(), "[object Proxy]"); +}); + +add_task(function test_Proxy_toJSON() { + let p = new Proxy(); + deepEqual(p.toJSON(), {}); + + // autoconfig url + p = new Proxy(); + p.proxyType = "pac"; + p.proxyAutoconfigUrl = "foo"; + deepEqual(p.toJSON(), { proxyType: "pac", proxyAutoconfigUrl: "foo" }); + + // manual proxy + p = new Proxy(); + p.proxyType = "manual"; + deepEqual(p.toJSON(), { proxyType: "manual" }); + + for (let proxy of ["httpProxy", "sslProxy", "socksProxy"]) { + let expected = { proxyType: "manual" }; + + p = new Proxy(); + p.proxyType = "manual"; + + if (proxy == "socksProxy") { + p.socksVersion = 5; + expected.socksVersion = 5; + } + + // without port + p[proxy] = "foo"; + expected[proxy] = "foo"; + deepEqual(p.toJSON(), expected); + + // with port + p[proxy] = "foo"; + p[`${proxy}Port`] = 0; + expected[proxy] = "foo:0"; + deepEqual(p.toJSON(), expected); + + p[`${proxy}Port`] = 42; + expected[proxy] = "foo:42"; + deepEqual(p.toJSON(), expected); + + // add brackets for IPv6 address as proxy hostname + p[proxy] = "2001:db8::1"; + p[`${proxy}Port`] = 42; + expected[proxy] = "foo:42"; + expected[proxy] = "[2001:db8::1]:42"; + deepEqual(p.toJSON(), expected); + } + + // noProxy: add brackets for IPv6 address + p = new Proxy(); + p.proxyType = "manual"; + p.noProxy = ["2001:db8::1"]; + let expected = { proxyType: "manual", noProxy: "[2001:db8::1]" }; + deepEqual(p.toJSON(), expected); +}); + +add_task(function test_Proxy_fromJSON() { + let p = new Proxy(); + deepEqual(p, Proxy.fromJSON(undefined)); + deepEqual(p, Proxy.fromJSON(null)); + + for (let typ of [true, 42, "foo", []]) { + Assert.throws(() => Proxy.fromJSON(typ), /InvalidArgumentError/); + } + + // must contain a valid proxyType + Assert.throws(() => Proxy.fromJSON({}), /InvalidArgumentError/); + Assert.throws( + () => Proxy.fromJSON({ proxyType: "foo" }), + /InvalidArgumentError/ + ); + + // autoconfig url + for (let url of [true, 42, [], {}]) { + Assert.throws( + () => Proxy.fromJSON({ proxyType: "pac", proxyAutoconfigUrl: url }), + /InvalidArgumentError/ + ); + } + + p = new Proxy(); + p.proxyType = "pac"; + p.proxyAutoconfigUrl = "foo"; + deepEqual(p, Proxy.fromJSON({ proxyType: "pac", proxyAutoconfigUrl: "foo" })); + + // manual proxy + p = new Proxy(); + p.proxyType = "manual"; + deepEqual(p, Proxy.fromJSON({ proxyType: "manual" })); + + for (let proxy of ["httpProxy", "sslProxy", "socksProxy"]) { + let manual = { proxyType: "manual" }; + + // invalid hosts + for (let host of [ + true, + 42, + [], + {}, + null, + "http://foo", + "foo:-1", + "foo:65536", + "foo/test", + "foo#42", + "foo?foo=bar", + "2001:db8::1", + ]) { + manual[proxy] = host; + Assert.throws(() => Proxy.fromJSON(manual), /InvalidArgumentError/); + } + + p = new Proxy(); + p.proxyType = "manual"; + if (proxy == "socksProxy") { + manual.socksVersion = 5; + p.socksVersion = 5; + } + + let host_map = { + "foo:1": { hostname: "foo", port: 1 }, + "foo:21": { hostname: "foo", port: 21 }, + "foo:80": { hostname: "foo", port: 80 }, + "foo:443": { hostname: "foo", port: 443 }, + "foo:65535": { hostname: "foo", port: 65535 }, + "127.0.0.1:42": { hostname: "127.0.0.1", port: 42 }, + "[2001:db8::1]:42": { hostname: "2001:db8::1", port: "42" }, + }; + + // valid proxy hosts with port + for (let host in host_map) { + manual[proxy] = host; + + p[`${proxy}`] = host_map[host].hostname; + p[`${proxy}Port`] = host_map[host].port; + + deepEqual(p, Proxy.fromJSON(manual)); + } + + // Without a port the default port of the scheme is used + for (let host of ["foo", "foo:"]) { + manual[proxy] = host; + + // For socks no default port is available + p[proxy] = `foo`; + if (proxy === "socksProxy") { + p[`${proxy}Port`] = null; + } else { + let default_ports = { httpProxy: 80, sslProxy: 443 }; + + p[`${proxy}Port`] = default_ports[proxy]; + } + + deepEqual(p, Proxy.fromJSON(manual)); + } + } + + // missing required socks version + Assert.throws( + () => Proxy.fromJSON({ proxyType: "manual", socksProxy: "foo:1234" }), + /InvalidArgumentError/ + ); + + // Bug 1703805: Since Firefox 90 ftpProxy is no longer supported + Assert.throws( + () => Proxy.fromJSON({ proxyType: "manual", ftpProxy: "foo:21" }), + /InvalidArgumentError/ + ); + + // noProxy: invalid settings + for (let noProxy of [true, 42, {}, null, "foo", [true], [42], [{}], [null]]) { + Assert.throws( + () => Proxy.fromJSON({ proxyType: "manual", noProxy }), + /InvalidArgumentError/ + ); + } + + // noProxy: valid settings + p = new Proxy(); + p.proxyType = "manual"; + for (let noProxy of [[], ["foo"], ["foo", "bar"], ["127.0.0.1"]]) { + let manual = { proxyType: "manual", noProxy }; + p.noProxy = noProxy; + deepEqual(p, Proxy.fromJSON(manual)); + } + + // noProxy: IPv6 needs brackets removed + p = new Proxy(); + p.proxyType = "manual"; + p.noProxy = ["2001:db8::1"]; + let manual = { proxyType: "manual", noProxy: ["[2001:db8::1]"] }; + deepEqual(p, Proxy.fromJSON(manual)); +}); + +add_task(function test_UnhandledPromptBehavior() { + equal(UnhandledPromptBehavior.Accept, "accept"); + equal(UnhandledPromptBehavior.AcceptAndNotify, "accept and notify"); + equal(UnhandledPromptBehavior.Dismiss, "dismiss"); + equal(UnhandledPromptBehavior.DismissAndNotify, "dismiss and notify"); + equal(UnhandledPromptBehavior.Ignore, "ignore"); +}); + +add_task(function test_Capabilities_ctor() { + let caps = new Capabilities(); + ok(caps.has("browserName")); + ok(caps.has("browserVersion")); + ok(caps.has("platformName")); + ok(["linux", "mac", "windows", "android"].includes(caps.get("platformName"))); + equal(PageLoadStrategy.Normal, caps.get("pageLoadStrategy")); + equal(false, caps.get("acceptInsecureCerts")); + ok(caps.get("timeouts") instanceof Timeouts); + ok(caps.get("proxy") instanceof Proxy); + equal(caps.get("setWindowRect"), !AppInfo.isAndroid); + equal(caps.get("strictFileInteractability"), false); + equal(caps.get("webSocketUrl"), null); + + equal(false, caps.get("moz:accessibilityChecks")); + ok(caps.has("moz:buildID")); + ok(caps.has("moz:debuggerAddress")); + ok(caps.has("moz:platformVersion")); + ok(caps.has("moz:processID")); + ok(caps.has("moz:profile")); + equal(true, caps.get("moz:webdriverClick")); + + // No longer supported capabilities + ok(!caps.has("moz:useNonSpecCompliantPointerOrigin")); +}); + +add_task(function test_Capabilities_toString() { + equal("[object Capabilities]", new Capabilities().toString()); +}); + +add_task(function test_Capabilities_toJSON() { + let caps = new Capabilities(); + let json = caps.toJSON(); + + equal(caps.get("browserName"), json.browserName); + equal(caps.get("browserVersion"), json.browserVersion); + equal(caps.get("platformName"), json.platformName); + equal(caps.get("pageLoadStrategy"), json.pageLoadStrategy); + equal(caps.get("acceptInsecureCerts"), json.acceptInsecureCerts); + deepEqual(caps.get("proxy").toJSON(), json.proxy); + deepEqual(caps.get("timeouts").toJSON(), json.timeouts); + equal(caps.get("setWindowRect"), json.setWindowRect); + equal(caps.get("strictFileInteractability"), json.strictFileInteractability); + equal(caps.get("webSocketUrl"), json.webSocketUrl); + + equal(caps.get("moz:accessibilityChecks"), json["moz:accessibilityChecks"]); + equal(caps.get("moz:buildID"), json["moz:buildID"]); + equal(caps.get("moz:debuggerAddress"), json["moz:debuggerAddress"]); + equal(caps.get("moz:platformVersion"), json["moz:platformVersion"]); + equal(caps.get("moz:processID"), json["moz:processID"]); + equal(caps.get("moz:profile"), json["moz:profile"]); + equal(caps.get("moz:webdriverClick"), json["moz:webdriverClick"]); +}); + +add_task(function test_Capabilities_fromJSON() { + const { fromJSON } = Capabilities; + + // plain + for (let typ of [{}, null, undefined]) { + ok(fromJSON(typ).has("browserName")); + } + + // matching + let caps = new Capabilities(); + + caps = fromJSON({ acceptInsecureCerts: true }); + equal(true, caps.get("acceptInsecureCerts")); + 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); + + let timeoutsConfig = { implicit: 123 }; + caps = fromJSON({ timeouts: timeoutsConfig }); + equal(123, caps.get("timeouts").implicit); + + caps = fromJSON({ strictFileInteractability: false }); + equal(false, caps.get("strictFileInteractability")); + caps = fromJSON({ strictFileInteractability: true }); + equal(true, caps.get("strictFileInteractability")); + + caps = fromJSON({ webSocketUrl: true }); + equal(true, caps.get("webSocketUrl")); + + caps = fromJSON({ "webauthn:virtualAuthenticators": true }); + equal(true, caps.get("webauthn:virtualAuthenticators")); + caps = fromJSON({ "webauthn:virtualAuthenticators": false }); + equal(false, caps.get("webauthn:virtualAuthenticators")); + Assert.throws( + () => fromJSON({ "webauthn:virtualAuthenticators": "foo" }), + /InvalidArgumentError/ + ); + + caps = fromJSON({ "webauthn:extension:uvm": true }); + equal(true, caps.get("webauthn:extension:uvm")); + caps = fromJSON({ "webauthn:extension:uvm": false }); + equal(false, caps.get("webauthn:extension:uvm")); + Assert.throws( + () => fromJSON({ "webauthn:extension:uvm": "foo" }), + /InvalidArgumentError/ + ); + + caps = fromJSON({ "webauthn:extension:prf": true }); + equal(true, caps.get("webauthn:extension:prf")); + caps = fromJSON({ "webauthn:extension:prf": false }); + equal(false, caps.get("webauthn:extension:prf")); + Assert.throws( + () => fromJSON({ "webauthn:extension:prf": "foo" }), + /InvalidArgumentError/ + ); + + caps = fromJSON({ "webauthn:extension:largeBlob": true }); + equal(true, caps.get("webauthn:extension:largeBlob")); + caps = fromJSON({ "webauthn:extension:largeBlob": false }); + equal(false, caps.get("webauthn:extension:largeBlob")); + Assert.throws( + () => fromJSON({ "webauthn:extension:largeBlob": "foo" }), + /InvalidArgumentError/ + ); + + caps = fromJSON({ "webauthn:extension:credBlob": true }); + equal(true, caps.get("webauthn:extension:credBlob")); + caps = fromJSON({ "webauthn:extension:credBlob": false }); + equal(false, caps.get("webauthn:extension:credBlob")); + Assert.throws( + () => fromJSON({ "webauthn:extension:credBlob": "foo" }), + /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 }), + /InvalidArgumentError/ + ); + Assert.throws( + () => fromJSON({ "moz:useNonSpecCompliantPointerOrigin": true }), + /InvalidArgumentError/ + ); +}); + +add_task(function test_mergeCapabilities() { + // Shadowed values. + Assert.throws( + () => + mergeCapabilities( + { acceptInsecureCerts: true }, + { acceptInsecureCerts: false } + ), + /InvalidArgumentError/ + ); + + deepEqual( + { acceptInsecureCerts: true }, + mergeCapabilities({ acceptInsecureCerts: true }, undefined) + ); + deepEqual( + { acceptInsecureCerts: true, browserName: "Firefox" }, + mergeCapabilities({ acceptInsecureCerts: true }, { browserName: "Firefox" }) + ); +}); + +add_task(function test_validateCapabilities_invalid() { + const invalidCapabilities = [ + true, + 42, + "foo", + [], + { acceptInsecureCerts: "foo" }, + { browserName: true }, + { browserVersion: true }, + { platformName: true }, + { pageLoadStrategy: "foo" }, + { proxy: false }, + { strictFileInteractability: "foo" }, + { timeouts: false }, + { unhandledPromptBehavior: false }, + { webSocketUrl: false }, + { webSocketUrl: "foo" }, + { "moz:firefoxOptions": "foo" }, + { "moz:accessibilityChecks": "foo" }, + { "moz:webdriverClick": "foo" }, + { "moz:webdriverClick": 1 }, + { "moz:useNonSpecCompliantPointerOrigin": false }, + { "moz:debuggerAddress": "foo" }, + { "moz:someRandomString": {} }, + ]; + for (const capabilities of invalidCapabilities) { + Assert.throws( + () => validateCapabilities(capabilities), + /InvalidArgumentError/ + ); + } +}); + +add_task(function test_validateCapabilities_valid() { + // Ignore null value. + deepEqual({}, validateCapabilities({ test: null })); + + const validCapabilities = [ + { acceptInsecureCerts: true }, + { browserName: "firefox" }, + { browserVersion: "12" }, + { platformName: "linux" }, + { pageLoadStrategy: "eager" }, + { proxy: { proxyType: "manual", httpProxy: "test.com" } }, + { strictFileInteractability: true }, + { timeouts: { pageLoad: 500 } }, + { unhandledPromptBehavior: "accept" }, + { webSocketUrl: true }, + { "moz:firefoxOptions": {} }, + { "moz:accessibilityChecks": true }, + { "moz:webdriverClick": true }, + { "moz:debuggerAddress": true }, + { "test:extension": "foo" }, + ]; + for (const validCapability of validCapabilities) { + deepEqual(validCapability, validateCapabilities(validCapability)); + } +}); + +add_task(function test_processCapabilities() { + for (const invalidValue of [ + { capabilities: null }, + { capabilities: undefined }, + { capabilities: "foo" }, + { capabilities: true }, + { capabilities: [] }, + { capabilities: { alwaysMatch: null } }, + { capabilities: { alwaysMatch: "foo" } }, + { capabilities: { alwaysMatch: true } }, + { capabilities: { alwaysMatch: [] } }, + { capabilities: { firstMatch: null } }, + { capabilities: { firstMatch: "foo" } }, + { capabilities: { firstMatch: true } }, + { capabilities: { firstMatch: {} } }, + { capabilities: { firstMatch: [] } }, + ]) { + Assert.throws( + () => processCapabilities(invalidValue), + /InvalidArgumentError/ + ); + } + + deepEqual( + { acceptInsecureCerts: true }, + processCapabilities({ + capabilities: { alwaysMatch: { acceptInsecureCerts: true } }, + }) + ); + deepEqual( + { browserName: "Firefox" }, + processCapabilities({ + capabilities: { firstMatch: [{ browserName: "Firefox" }] }, + }) + ); + deepEqual( + { acceptInsecureCerts: true, browserName: "Firefox" }, + processCapabilities({ + capabilities: { + alwaysMatch: { acceptInsecureCerts: true }, + firstMatch: [{ browserName: "Firefox" }], + }, + }) + ); +}); + +// use Proxy.toJSON to test marshal +add_task(function test_marshal() { + let proxy = new Proxy(); + + // drop empty fields + deepEqual({}, proxy.toJSON()); + proxy.proxyType = "manual"; + deepEqual({ proxyType: "manual" }, proxy.toJSON()); + proxy.proxyType = null; + deepEqual({}, proxy.toJSON()); + proxy.proxyType = undefined; + deepEqual({}, proxy.toJSON()); + + // iterate over object literals + proxy.proxyType = { foo: "bar" }; + deepEqual({ proxyType: { foo: "bar" } }, proxy.toJSON()); + + // iterate over complex object that implement toJSON + proxy.proxyType = new Proxy(); + deepEqual({}, proxy.toJSON()); + proxy.proxyType.proxyType = "manual"; + deepEqual({ proxyType: { proxyType: "manual" } }, proxy.toJSON()); + + // drop objects with no entries + proxy.proxyType = { foo: {} }; + deepEqual({}, proxy.toJSON()); + proxy.proxyType = { foo: new Proxy() }; + deepEqual({}, proxy.toJSON()); +}); -- cgit v1.2.3