summaryrefslogtreecommitdiffstats
path: root/browser/components/preferences/tests/browser_connection_dnsoverhttps.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/preferences/tests/browser_connection_dnsoverhttps.js')
-rw-r--r--browser/components/preferences/tests/browser_connection_dnsoverhttps.js808
1 files changed, 808 insertions, 0 deletions
diff --git a/browser/components/preferences/tests/browser_connection_dnsoverhttps.js b/browser/components/preferences/tests/browser_connection_dnsoverhttps.js
new file mode 100644
index 0000000000..71d7814fd8
--- /dev/null
+++ b/browser/components/preferences/tests/browser_connection_dnsoverhttps.js
@@ -0,0 +1,808 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(4);
+
+const {
+ EnterprisePolicyTesting,
+ PoliciesPrefTracker,
+} = ChromeUtils.importESModule(
+ "resource://testing-common/EnterprisePolicyTesting.sys.mjs"
+);
+
+ChromeUtils.defineModuleGetter(
+ this,
+ "DoHController",
+ "resource:///modules/DoHController.jsm"
+);
+ChromeUtils.defineModuleGetter(
+ this,
+ "DoHConfigController",
+ "resource:///modules/DoHConfig.jsm"
+);
+ChromeUtils.defineModuleGetter(
+ this,
+ "DoHTestUtils",
+ "resource://testing-common/DoHTestUtils.jsm"
+);
+
+const SUBDIALOG_URL =
+ "chrome://browser/content/preferences/dialogs/connection.xhtml";
+const TRR_MODE_PREF = "network.trr.mode";
+const TRR_URI_PREF = "network.trr.uri";
+const TRR_CUSTOM_URI_PREF = "network.trr.custom_uri";
+const ROLLOUT_ENABLED_PREF = "doh-rollout.enabled";
+const ROLLOUT_SELF_ENABLED_PREF = "doh-rollout.self-enabled";
+const HEURISTICS_DISABLED_PREF = "doh-rollout.disable-heuristics";
+const FIRST_RESOLVER_VALUE = DoHTestUtils.providers[0].uri;
+const SECOND_RESOLVER_VALUE = DoHTestUtils.providers[1].uri;
+const DEFAULT_RESOLVER_VALUE = FIRST_RESOLVER_VALUE;
+
+const modeCheckboxSelector = "#networkDnsOverHttps";
+const uriTextboxSelector = "#networkCustomDnsOverHttpsInput";
+const resolverMenulistSelector = "#networkDnsOverHttpsResolverChoices";
+const defaultPrefValues = Object.freeze({
+ [TRR_MODE_PREF]: 0,
+ [TRR_CUSTOM_URI_PREF]: "",
+});
+
+// See bug 1741554. This test should not actually try to create a connection to
+// the real DoH endpoint. But a background request could do that while the test
+// is in progress, before we've actually disabled TRR, and would cause a crash
+// due to connecting to a non-local IP.
+// To prevent that we override the IP to a local address.
+Cc["@mozilla.org/network/native-dns-override;1"]
+ .getService(Ci.nsINativeDNSResolverOverride)
+ .addIPOverride("mozilla.cloudflare-dns.com", "127.0.0.1");
+
+async function resetPrefs() {
+ await DoHTestUtils.resetRemoteSettingsConfig();
+ await DoHController._uninit();
+ Services.prefs.clearUserPref(TRR_MODE_PREF);
+ Services.prefs.clearUserPref(TRR_URI_PREF);
+ Services.prefs.clearUserPref(TRR_CUSTOM_URI_PREF);
+ Services.prefs.getChildList("doh-rollout.").forEach(pref => {
+ Services.prefs.clearUserPref(pref);
+ });
+ // Clear out any telemetry events generated by DoHController so that we don't
+ // confuse tests running after this one that are looking at those.
+ Services.telemetry.clearEvents();
+ await DoHController.init();
+}
+Services.prefs.setStringPref("network.trr.confirmationNS", "skip");
+let preferencesOpen = new Promise(res => open_preferences(res));
+
+registerCleanupFunction(async () => {
+ await resetPrefs();
+ gBrowser.removeCurrentTab();
+ Services.prefs.clearUserPref("network.trr.confirmationNS");
+});
+
+async function openConnectionsSubDialog() {
+ /*
+ The connection dialog has type="child", So it has to be opened as a sub dialog
+ of the main pref tab. Prefs only get updated after the subdialog is confirmed & closed
+ */
+ let dialog = await openAndLoadSubDialog(SUBDIALOG_URL);
+ ok(dialog, "connection window opened");
+ return dialog;
+}
+
+function waitForPrefObserver(name) {
+ return new Promise(resolve => {
+ const observer = {
+ observe(aSubject, aTopic, aData) {
+ if (aData == name) {
+ Services.prefs.removeObserver(name, observer);
+ resolve();
+ }
+ },
+ };
+ Services.prefs.addObserver(name, observer);
+ });
+}
+
+async function testWithProperties(props, startTime) {
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: testing with " +
+ JSON.stringify(props)
+ );
+
+ // There are two different signals that the DoHController is ready, depending
+ // on the config being tested. If we're setting the TRR mode pref, we should
+ // expect the disable-heuristics pref to be set as the signal. Else, we can
+ // expect the self-enabled pref as the signal.
+ let rolloutReadyPromise;
+ if (props.hasOwnProperty(TRR_MODE_PREF)) {
+ if (
+ [2, 3, 5].includes(props[TRR_MODE_PREF]) &&
+ props.hasOwnProperty(ROLLOUT_ENABLED_PREF)
+ ) {
+ // Only initialize the promise if we're going to enable the rollout -
+ // otherwise we will never await it, which could cause a leak if it doesn't
+ // end up resolving.
+ rolloutReadyPromise = waitForPrefObserver(HEURISTICS_DISABLED_PREF);
+ }
+ Services.prefs.setIntPref(TRR_MODE_PREF, props[TRR_MODE_PREF]);
+ }
+ if (props.hasOwnProperty(ROLLOUT_ENABLED_PREF)) {
+ if (!rolloutReadyPromise) {
+ rolloutReadyPromise = waitForPrefObserver(ROLLOUT_SELF_ENABLED_PREF);
+ }
+ Services.prefs.setBoolPref(
+ ROLLOUT_ENABLED_PREF,
+ props[ROLLOUT_ENABLED_PREF]
+ );
+ await rolloutReadyPromise;
+ }
+ if (props.hasOwnProperty(TRR_CUSTOM_URI_PREF)) {
+ Services.prefs.setStringPref(
+ TRR_CUSTOM_URI_PREF,
+ props[TRR_CUSTOM_URI_PREF]
+ );
+ }
+ if (props.hasOwnProperty(TRR_URI_PREF)) {
+ Services.prefs.setStringPref(TRR_URI_PREF, props[TRR_URI_PREF]);
+ }
+
+ let dialog = await openConnectionsSubDialog();
+ await dialog.uiReady;
+ info(
+ Date.now() - startTime + ": testWithProperties: connections dialog now open"
+ );
+ let doc = dialog.document;
+ let win = doc.ownerGlobal;
+ let dialogElement = doc.getElementById("ConnectionsDialog");
+ let dialogClosingPromise = BrowserTestUtils.waitForEvent(
+ dialogElement,
+ "dialogclosing"
+ );
+ let modeCheckbox = doc.querySelector(modeCheckboxSelector);
+ let uriTextbox = doc.querySelector(uriTextboxSelector);
+ let resolverMenulist = doc.querySelector(resolverMenulistSelector);
+ let uriPrefChangedPromise;
+ let modePrefChangedPromise;
+ let disableHeuristicsPrefChangedPromise;
+
+ if (props.hasOwnProperty("expectedModeChecked")) {
+ await TestUtils.waitForCondition(
+ () => modeCheckbox.checked === props.expectedModeChecked
+ );
+ is(
+ modeCheckbox.checked,
+ props.expectedModeChecked,
+ "mode checkbox has expected checked state"
+ );
+ }
+ if (props.hasOwnProperty("expectedUriValue")) {
+ await TestUtils.waitForCondition(
+ () => uriTextbox.value === props.expectedUriValue
+ );
+ is(
+ uriTextbox.value,
+ props.expectedUriValue,
+ "URI textbox has expected value"
+ );
+ }
+ if (props.hasOwnProperty("expectedResolverListValue")) {
+ await TestUtils.waitForCondition(
+ () => resolverMenulist.value === props.expectedResolverListValue
+ );
+ is(
+ resolverMenulist.value,
+ props.expectedResolverListValue,
+ "resolver menulist has expected value"
+ );
+ }
+ if (props.clickMode) {
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: clickMode, waiting for the pref observer"
+ );
+ modePrefChangedPromise = waitForPrefObserver(TRR_MODE_PREF);
+ if (props.hasOwnProperty("expectedDisabledHeuristics")) {
+ disableHeuristicsPrefChangedPromise = waitForPrefObserver(
+ HEURISTICS_DISABLED_PREF
+ );
+ }
+ info(
+ Date.now() - startTime + ": testWithProperties: clickMode, pref changed"
+ );
+ modeCheckbox.scrollIntoView();
+ EventUtils.synthesizeMouseAtCenter(modeCheckbox, {}, win);
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: clickMode, mouse click synthesized"
+ );
+ }
+ if (props.hasOwnProperty("selectResolver")) {
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: selectResolver, creating change event"
+ );
+ resolverMenulist.focus();
+ resolverMenulist.value = props.selectResolver;
+ resolverMenulist.dispatchEvent(new Event("input", { bubbles: true }));
+ resolverMenulist.dispatchEvent(new Event("change", { bubbles: true }));
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: selectResolver, item value set and events dispatched"
+ );
+ }
+
+ if (props.hasOwnProperty("inputUriKeys")) {
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: inputUriKeys, waiting for the pref observer"
+ );
+ uriPrefChangedPromise = waitForPrefObserver(TRR_CUSTOM_URI_PREF);
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: inputUriKeys, pref changed, now enter the new value"
+ );
+ uriTextbox.focus();
+ uriTextbox.value = props.inputUriKeys;
+ uriTextbox.dispatchEvent(new win.Event("input", { bubbles: true }));
+ uriTextbox.dispatchEvent(new win.Event("change", { bubbles: true }));
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: inputUriKeys, input and change events dispatched"
+ );
+ }
+
+ info(Date.now() - startTime + ": testWithProperties: calling acceptDialog");
+ dialogElement.acceptDialog();
+
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: waiting for the dialogClosingPromise"
+ );
+ let dialogClosingEvent = await dialogClosingPromise;
+ ok(dialogClosingEvent, "connection window closed");
+
+ info(
+ Date.now() -
+ startTime +
+ ": testWithProperties: waiting for any of uri and mode prefs to change"
+ );
+ await Promise.all([
+ uriPrefChangedPromise,
+ modePrefChangedPromise,
+ disableHeuristicsPrefChangedPromise,
+ ]);
+ info(Date.now() - startTime + ": testWithProperties: prefs changed");
+
+ if (props.hasOwnProperty("expectedFinalUriPref")) {
+ if (props.expectedFinalUriPref) {
+ let uriPref = Services.prefs.getStringPref(TRR_URI_PREF);
+ is(
+ uriPref,
+ props.expectedFinalUriPref,
+ "uri pref ended up with the expected value"
+ );
+ } else {
+ ok(
+ !Services.prefs.prefHasUserValue(TRR_URI_PREF),
+ "uri pref ended up with the expected value (unset)"
+ );
+ }
+ }
+
+ if (props.hasOwnProperty("expectedModePref")) {
+ let modePref = Services.prefs.getIntPref(TRR_MODE_PREF);
+ is(
+ modePref,
+ props.expectedModePref,
+ "mode pref ended up with the expected value"
+ );
+ }
+
+ if (props.hasOwnProperty("expectedDisabledHeuristics")) {
+ let disabledHeuristicsPref = Services.prefs.getBoolPref(
+ HEURISTICS_DISABLED_PREF
+ );
+ is(
+ disabledHeuristicsPref,
+ props.expectedDisabledHeuristics,
+ "disable-heuristics pref ended up with the expected value"
+ );
+ }
+
+ if (props.hasOwnProperty("expectedFinalCusomUriPref")) {
+ let customUriPref = Services.prefs.getStringPref(TRR_CUSTOM_URI_PREF);
+ is(
+ customUriPref,
+ props.expectedFinalCustomUriPref,
+ "custom_uri pref ended up with the expected value"
+ );
+ }
+
+ info(Date.now() - startTime + ": testWithProperties: fin");
+}
+
+add_task(async function default_values() {
+ let customUriPref = Services.prefs.getStringPref(TRR_CUSTOM_URI_PREF);
+ let uriPrefHasUserValue = Services.prefs.prefHasUserValue(TRR_URI_PREF);
+ let modePref = Services.prefs.getIntPref(TRR_MODE_PREF);
+ is(
+ modePref,
+ defaultPrefValues[TRR_MODE_PREF],
+ `Actual value of ${TRR_MODE_PREF} matches expected default value`
+ );
+ ok(
+ !uriPrefHasUserValue,
+ `Actual value of ${TRR_URI_PREF} matches expected default value (unset)`
+ );
+ is(
+ customUriPref,
+ defaultPrefValues[TRR_CUSTOM_URI_PREF],
+ `Actual value of ${TRR_CUSTOM_URI_PREF} matches expected default value`
+ );
+});
+
+let testVariations = [
+ // verify state with defaults
+ { name: "default", expectedModePref: 5, expectedUriValue: "" },
+
+ // verify each of the modes maps to the correct checked state
+ { name: "mode 0", [TRR_MODE_PREF]: 0, expectedModeChecked: false },
+ {
+ name: "mode 1",
+ [TRR_MODE_PREF]: 1,
+ expectedModeChecked: false,
+ },
+ {
+ name: "mode 2",
+ [TRR_MODE_PREF]: 2,
+ expectedModeChecked: true,
+ expectedFinalUriPref: DEFAULT_RESOLVER_VALUE,
+ },
+ {
+ name: "mode 3",
+ [TRR_MODE_PREF]: 3,
+ expectedModeChecked: true,
+ expectedFinalUriPref: DEFAULT_RESOLVER_VALUE,
+ },
+ {
+ name: "mode 4",
+ [TRR_MODE_PREF]: 4,
+ expectedModeChecked: false,
+ },
+ { name: "mode 5", [TRR_MODE_PREF]: 5, expectedModeChecked: false },
+ // verify an out of bounds mode value maps to the correct checked state
+ {
+ name: "mode out-of-bounds",
+ [TRR_MODE_PREF]: 77,
+ expectedModeChecked: false,
+ },
+
+ // verify automatic heuristics states
+ {
+ name: "heuristics on and mode unset",
+ [TRR_MODE_PREF]: 0,
+ [ROLLOUT_ENABLED_PREF]: true,
+ expectedModeChecked: true,
+ },
+ {
+ name: "heuristics on and mode set to 2",
+ [TRR_MODE_PREF]: 2,
+ [ROLLOUT_ENABLED_PREF]: true,
+ expectedModeChecked: true,
+ },
+ {
+ name: "heuristics on but disabled, mode unset",
+ [TRR_MODE_PREF]: 5,
+ [ROLLOUT_ENABLED_PREF]: true,
+ expectedModeChecked: false,
+ },
+ {
+ name: "heuristics on but disabled, mode set to 2",
+ [TRR_MODE_PREF]: 2,
+ [ROLLOUT_ENABLED_PREF]: true,
+ expectedModeChecked: true,
+ },
+
+ // verify toggling the checkbox gives the right outcomes
+ {
+ name: "toggle mode on",
+ clickMode: true,
+ expectedModeValue: 2,
+ expectedUriValue: "",
+ expectedFinalUriPref: DEFAULT_RESOLVER_VALUE,
+ },
+ {
+ name: "toggle mode off",
+ [TRR_MODE_PREF]: 2,
+ expectedModeChecked: true,
+ clickMode: true,
+ expectedModePref: 5,
+ },
+ {
+ name: "toggle mode off when on due to heuristics",
+ [TRR_MODE_PREF]: 0,
+ [ROLLOUT_ENABLED_PREF]: true,
+ expectedModeChecked: true,
+ clickMode: true,
+ expectedModePref: 5,
+ expectedDisabledHeuristics: true,
+ },
+ // Test selecting non-default, non-custom TRR provider, NextDNS.
+ {
+ name: "Select NextDNS as TRR provider",
+ [TRR_MODE_PREF]: 2,
+ selectResolver: SECOND_RESOLVER_VALUE,
+ expectedFinalUriPref: SECOND_RESOLVER_VALUE,
+ },
+ // Test selecting non-default, non-custom TRR provider, NextDNS,
+ // with DoH not enabled. The provider selection should stick.
+ {
+ name: "Select NextDNS as TRR provider in mode 0",
+ [TRR_MODE_PREF]: 0,
+ selectResolver: SECOND_RESOLVER_VALUE,
+ expectedFinalUriPref: SECOND_RESOLVER_VALUE,
+ },
+ {
+ name: "return to default from NextDNS",
+ [TRR_MODE_PREF]: 2,
+ [TRR_URI_PREF]: SECOND_RESOLVER_VALUE,
+ expectedResolverListValue: SECOND_RESOLVER_VALUE,
+ selectResolver: DEFAULT_RESOLVER_VALUE,
+ expectedFinalUriPref: DEFAULT_RESOLVER_VALUE,
+ },
+ // test that selecting Custom, when we have a TRR_CUSTOM_URI_PREF subsequently changes TRR_URI_PREF
+ {
+ name: "select custom with existing custom_uri pref value",
+ [TRR_MODE_PREF]: 2,
+ [TRR_CUSTOM_URI_PREF]: "https://example.com",
+ expectedModeValue: true,
+ selectResolver: "custom",
+ expectedUriValue: "https://example.com",
+ expectedFinalUriPref: "https://example.com",
+ expectedFinalCustomUriPref: "https://example.com",
+ },
+ {
+ name: "select custom and enter new custom_uri pref value",
+ [TRR_URI_PREF]: "",
+ [TRR_CUSTOM_URI_PREF]: "",
+ clickMode: true,
+ selectResolver: "custom",
+ inputUriKeys: "https://example.com",
+ expectedModePref: 2,
+ expectedFinalUriPref: "https://example.com",
+ expectedFinalCustomUriPref: "https://example.com",
+ },
+
+ {
+ name: "return to default from custom",
+ [TRR_MODE_PREF]: 2,
+ [TRR_URI_PREF]: "https://example.com",
+ [TRR_CUSTOM_URI_PREF]: "https://example.com",
+ expectedUriValue: "https://example.com",
+ expectedResolverListValue: "custom",
+ selectResolver: DEFAULT_RESOLVER_VALUE,
+ expectedFinalUriPref: DEFAULT_RESOLVER_VALUE,
+ expectedFinalCustomUriPref: "https://example.com",
+ },
+ {
+ name: "clear the custom uri",
+ [TRR_MODE_PREF]: 2,
+ [TRR_URI_PREF]: "https://example.com",
+ [TRR_CUSTOM_URI_PREF]: "https://example.com",
+ expectedUriValue: "https://example.com",
+ expectedResolverListValue: "custom",
+ inputUriKeys: "",
+ expectedFinalUriPref: DEFAULT_RESOLVER_VALUE,
+ expectedFinalCustomUriPref: "",
+ },
+ {
+ name: "empty default resolver list",
+ [TRR_MODE_PREF]: 2,
+ [TRR_URI_PREF]: "https://example.com",
+ [TRR_CUSTOM_URI_PREF]: "",
+ expectedUriValue: "https://example.com",
+ expectedResolverListValue: "custom",
+ expectedFinalUriPref: "https://example.com",
+ expectedFinalCustomUriPref: "https://example.com",
+ },
+];
+
+for (let props of testVariations) {
+ add_task(async function testVariation() {
+ await preferencesOpen;
+ let startTime = Date.now();
+ info("starting test: " + props.name);
+ await testWithProperties(props, startTime);
+ await resetPrefs();
+ });
+}
+
+add_task(async function testRemoteSettingsEnable() {
+ // Enable the rollout.
+ await DoHTestUtils.loadRemoteSettingsConfig({
+ providers: "example-1, example-2",
+ rolloutEnabled: true,
+ steeringEnabled: false,
+ steeringProviders: "",
+ autoDefaultEnabled: false,
+ autoDefaultProviders: "",
+ id: "global",
+ });
+
+ let doTest = async (cancelOrAccept = "cancel") => {
+ let dialog = await openConnectionsSubDialog();
+ await dialog.uiReady;
+ let doc = dialog.document;
+ let dialogElement = doc.getElementById("ConnectionsDialog");
+ let modeCheckbox = doc.querySelector(modeCheckboxSelector);
+ ok(modeCheckbox.checked, "The mode checkbox should be checked.");
+ let dialogClosingPromise = BrowserTestUtils.waitForEvent(
+ dialogElement,
+ "dialogclosing"
+ );
+ if (cancelOrAccept == "cancel") {
+ dialogElement.cancelDialog();
+ } else {
+ dialogElement.acceptDialog();
+ }
+ await dialogClosingPromise;
+ if (cancelOrAccept == "cancel") {
+ try {
+ await TestUtils.waitForCondition(() =>
+ Services.prefs.prefHasUserValue("doh-rollout.disable-heuristics")
+ );
+ ok(false, "Heuristics were disabled when they shouldn't have been!");
+ } catch (e) {
+ ok(true, "Heuristics remained enabled.");
+ }
+ is(Services.prefs.getStringPref("network.trr.uri"), "");
+ ok(!Services.prefs.prefHasUserValue("network.trr.mode"));
+ } else {
+ // If accepting, the chosen provider is persisted to network.trr.uri
+ // and heuristics should get disabled.
+ await TestUtils.waitForCondition(() =>
+ Services.prefs.prefHasUserValue("doh-rollout.disable-heuristics")
+ );
+ ok(
+ Services.prefs.getBoolPref("doh-rollout.disable-heuristics"),
+ "Heurstics were disabled."
+ );
+ is(
+ Services.prefs.getStringPref("network.trr.uri"),
+ DEFAULT_RESOLVER_VALUE
+ );
+ is(Services.prefs.getIntPref("network.trr.mode"), 2);
+ }
+ };
+
+ for (let action of ["cancel", "accept"]) {
+ await doTest(action);
+ }
+});
+
+add_task(async function testEnterprisePolicy() {
+ async function closeDialog(dialog) {
+ let dialogClosingPromise = BrowserTestUtils.waitForEvent(
+ dialog,
+ "dialogclosing"
+ );
+
+ dialog.cancelDialog();
+ await dialogClosingPromise;
+ }
+
+ async function withPolicy(policy, fn, preFn = () => {}) {
+ await resetPrefs();
+ PoliciesPrefTracker.start();
+ await EnterprisePolicyTesting.setupPolicyEngineWithJson(policy);
+
+ await preFn();
+
+ let dialog = await openConnectionsSubDialog();
+ await dialog.uiReady;
+
+ let doc = dialog.document;
+
+ let dialogElement = doc.getElementById("ConnectionsDialog");
+ let modeCheckbox = doc.querySelector(modeCheckboxSelector);
+ let resolverMenulist = doc.querySelector(resolverMenulistSelector);
+ let uriTextbox = doc.querySelector(uriTextboxSelector);
+
+ await fn({
+ dialog,
+ dialogElement,
+ modeCheckbox,
+ resolverMenulist,
+ doc,
+ uriTextbox,
+ });
+
+ await closeDialog(dialogElement);
+ EnterprisePolicyTesting.resetRunOnceState();
+ PoliciesPrefTracker.stop();
+ }
+
+ info("Check that a locked policy does not allow any changes in the UI");
+ await withPolicy(
+ {
+ policies: {
+ DNSOverHTTPS: {
+ Enabled: true,
+ ProviderURL: "https://examplelocked.com/provider",
+ ExcludedDomains: ["examplelocked.com", "example.org"],
+ Locked: true,
+ },
+ },
+ },
+ async res => {
+ ok(res.modeCheckbox.checked, "The mode checkbox should be checked.");
+ is(res.modeCheckbox.disabled, true, "The checkbox should be locked.");
+
+ is(res.resolverMenulist.value, "custom", "Resolver list shows custom");
+ is(
+ res.resolverMenulist.disabled,
+ true,
+ "The resolver list should be locked."
+ );
+
+ is(res.uriTextbox.disabled, true, "The custom URI should be locked.");
+ }
+ );
+
+ info("Check that an unlocked policy has editable fields in the dialog");
+ await withPolicy(
+ {
+ policies: {
+ DNSOverHTTPS: {
+ Enabled: true,
+ ProviderURL: "https://example.com/provider",
+ ExcludedDomains: ["example.com", "example.org"],
+ },
+ },
+ },
+ async res => {
+ ok(res.modeCheckbox.checked, "The mode checkbox should be checked.");
+ is(
+ res.modeCheckbox.disabled,
+ false,
+ "The checkbox should not be locked."
+ );
+
+ is(res.resolverMenulist.value, "custom", "Resolver list shows custom");
+ is(
+ res.resolverMenulist.disabled,
+ false,
+ "The resolver list should not be locked."
+ );
+
+ is(
+ res.uriTextbox.value,
+ "https://example.com/provider",
+ "Expected custom resolver"
+ );
+ is(
+ res.uriTextbox.disabled,
+ false,
+ "The custom URI should not be locked."
+ );
+ }
+ );
+
+ info("Check that a locked disabled policy disables the buttons");
+ await withPolicy(
+ {
+ policies: {
+ DNSOverHTTPS: {
+ Enabled: false,
+ ProviderURL: "https://example.com/provider",
+ ExcludedDomains: ["example.com", "example.org"],
+ Locked: true,
+ },
+ },
+ },
+ async res => {
+ ok(!res.modeCheckbox.checked, "The mode checkbox should be unchecked.");
+ is(res.modeCheckbox.disabled, true, "The checkbox should be locked.");
+
+ is(res.resolverMenulist.value, "custom", "Resolver list shows custom");
+ is(
+ res.resolverMenulist.disabled,
+ true,
+ "The resolver list should be locked."
+ );
+
+ is(res.uriTextbox.disabled, true, "The custom URI should be locked.");
+ }
+ );
+
+ info("Check that an unlocked disabled policy has editable fields");
+ await withPolicy(
+ {
+ policies: {
+ DNSOverHTTPS: {
+ Enabled: false,
+ ProviderURL: "https://example.com/provider",
+ ExcludedDomains: ["example.com", "example.org"],
+ },
+ },
+ },
+ async res => {
+ ok(!res.modeCheckbox.checked, "The mode checkbox should be unchecked.");
+ is(
+ res.modeCheckbox.disabled,
+ false,
+ "The checkbox should not be locked."
+ );
+
+ is(res.resolverMenulist.value, "custom", "Resolver list shows custom");
+ is(
+ res.resolverMenulist.disabled,
+ true,
+ "The resolver list should be locked."
+ );
+
+ is(res.uriTextbox.disabled, true, "The custom URI should be locked.");
+ }
+ );
+
+ info("Check that the remote settings config doesn't override the policy");
+ await withPolicy(
+ {
+ policies: {
+ DNSOverHTTPS: {
+ Enabled: true,
+ ProviderURL: "https://example.com/provider",
+ ExcludedDomains: ["example.com", "example.org"],
+ },
+ },
+ },
+ async res => {
+ ok(res.modeCheckbox.checked, "The mode checkbox should be checked.");
+ is(
+ res.modeCheckbox.disabled,
+ false,
+ "The checkbox should not be locked."
+ );
+
+ is(res.resolverMenulist.value, "custom", "Resolver list shows custom");
+ is(
+ res.resolverMenulist.disabled,
+ false,
+ "The resolver list should not be locked."
+ );
+
+ is(
+ res.uriTextbox.value,
+ "https://example.com/provider",
+ "Expected custom resolver"
+ );
+ is(
+ res.uriTextbox.disabled,
+ false,
+ "The custom URI should not be locked."
+ );
+ },
+ async function runAfterSettingPolicy() {
+ await DoHTestUtils.loadRemoteSettingsConfig({
+ providers: "example-1, example-2",
+ rolloutEnabled: true,
+ steeringEnabled: false,
+ steeringProviders: "",
+ autoDefaultEnabled: false,
+ autoDefaultProviders: "",
+ id: "global",
+ });
+ }
+ );
+});