commit 3cad1db09ce659efac80269e3f7d86e92659e4d5
parent dafe5b51f3cf0265b5fdf186ce632a66775f58ac
Author: Emma Zuehlcke <emz@mozilla.com>
Date: Thu, 18 Dec 2025 17:00:38 +0000
Bug 2003471 - Implement tests for the ETP advanced and customize preferences sections. r=hjones,bvandersloot
Differential Revision: https://phabricator.services.mozilla.com/D276696
Diffstat:
4 files changed, 761 insertions(+), 4 deletions(-)
diff --git a/browser/components/preferences/tests/browser.toml b/browser/components/preferences/tests/browser.toml
@@ -107,6 +107,10 @@ skip-if = [
["browser_ensure_prefs_bindings_initted.js"]
+["browser_etp_advanced.js"]
+
+["browser_etp_customize.js"]
+
["browser_etp_exceptions_dialog.js"]
["browser_etp_status.js"]
@@ -243,12 +247,12 @@ skip-if = [
["browser_privacypane_2.js"]
skip-if = [
- "os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && opt && a11y_checks",
+ "os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && a11y_checks && opt",
]
["browser_privacypane_3.js"]
skip-if = [
- "os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && opt && a11y_checks",
+ "os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && a11y_checks && opt",
]
["browser_proxy_backup.js"]
@@ -310,7 +314,7 @@ skip-if = [
["browser_search_within_preferences_1.js"]
skip-if = [
- "os == 'win' && os_version == '11.26100' && arch == 'x86_64' && ccov"
+ "os == 'win' && os_version == '11.26100' && arch == 'x86_64' && ccov",
]
["browser_search_within_preferences_2.js"]
diff --git a/browser/components/preferences/tests/browser_etp_advanced.js b/browser/components/preferences/tests/browser_etp_advanced.js
@@ -0,0 +1,365 @@
+/* Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests for the ETP advanced settings view.
+
+const CAT_PREF = "browser.contentblocking.category";
+const BASELINE_PREF = "privacy.trackingprotection.allow_list.baseline.enabled";
+const CONVENIENCE_PREF =
+ "privacy.trackingprotection.allow_list.convenience.enabled";
+const PERMISSIONS_DIALOG_URL =
+ "chrome://browser/content/preferences/dialogs/permissions.xhtml";
+
+function getControl(doc, id) {
+ let control = doc.getElementById(id);
+ ok(control, `Control ${id} exists`);
+ return control;
+}
+
+function synthesizeClick(el) {
+ let target = el.buttonEl ?? el.inputEl ?? el;
+ target.scrollIntoView({ block: "center" });
+ EventUtils.synthesizeMouseAtCenter(target, {}, target.ownerGlobal);
+}
+
+function getControlWrapper(doc, id) {
+ return getControl(doc, id).closest("setting-control");
+}
+
+async function clickBaselineCheckboxWithConfirm(
+ doc,
+ controlId,
+ prefName,
+ expectedValue,
+ buttonNumClick
+) {
+ let checkbox = getControl(doc, controlId);
+
+ let promptPromise = PromptTestUtils.handleNextPrompt(
+ gBrowser.selectedBrowser,
+ { modalType: Services.prompt.MODAL_TYPE_CONTENT },
+ { buttonNumClick }
+ );
+
+ let prefChangePromise = null;
+ if (buttonNumClick === 1) {
+ prefChangePromise = waitForAndAssertPrefState(
+ prefName,
+ expectedValue,
+ `${prefName} updated`
+ );
+ }
+
+ synthesizeClick(checkbox);
+
+ await promptPromise;
+
+ if (prefChangePromise) {
+ await prefChangePromise;
+ }
+
+ is(
+ checkbox.checked,
+ expectedValue,
+ `Checkbox ${controlId} should be ${expectedValue}`
+ );
+
+ return checkbox;
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.settings-redesign.enabled", true]],
+ });
+});
+
+async function openEtpPage() {
+ await openPreferencesViaOpenPreferencesAPI("etp", { leaveOpen: true });
+ let doc = gBrowser.contentDocument;
+ await BrowserTestUtils.waitForCondition(
+ () => doc.getElementById("contentBlockingCategoryRadioGroup"),
+ "Wait for the ETP advanced radio group to render"
+ );
+ return {
+ win: gBrowser.contentWindow,
+ doc,
+ tab: gBrowser.selectedTab,
+ };
+}
+
+// Verifies category radios reflect pref changes and the customize entry point navigates correctly.
+add_task(async function test_etp_category_radios_and_customize_navigation() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [CAT_PREF, "standard"],
+ [BASELINE_PREF, true],
+ [CONVENIENCE_PREF, true],
+ ],
+ });
+
+ let { win, doc, tab } = await openEtpPage();
+
+ let standardRadio = getControl(doc, "etpLevelStandard");
+ let strictRadio = getControl(doc, "etpLevelStrict");
+ let customRadio = getControl(doc, "etpLevelCustom");
+ let customizeButton = getControl(doc, "etpCustomizeButton");
+ let levelWarning = getControl(doc, "etpLevelWarning");
+
+ ok(standardRadio.checked, "Standard ETP level is initially selected");
+ ok(
+ customizeButton.parentDisabled,
+ "Customize button disabled until custom level selected"
+ );
+ ok(
+ BrowserTestUtils.isHidden(levelWarning),
+ "ETP level warning hidden while standard selected"
+ );
+
+ info("Switch to strict and wait for the pref to change");
+ let prefChange = waitForAndAssertPrefState(
+ CAT_PREF,
+ "strict",
+ "ETP category pref set to strict"
+ );
+ synthesizeClick(strictRadio);
+ await prefChange;
+ ok(strictRadio.checked, "Strict radio button selected");
+
+ let strictBaselineWrapper = getControlWrapper(
+ doc,
+ "etpAllowListBaselineEnabled"
+ );
+ ok(
+ BrowserTestUtils.isVisible(strictBaselineWrapper),
+ "Baseline checkbox for strict is visible when strict selected"
+ );
+
+ let levelWarningVisible = () => BrowserTestUtils.isVisible(levelWarning);
+ if (!levelWarningVisible()) {
+ await BrowserTestUtils.waitForMutationCondition(
+ levelWarning,
+ { attributes: true, attributeFilter: ["hidden"] },
+ levelWarningVisible
+ );
+ }
+ ok(levelWarningVisible(), "ETP level warning visible for strict level");
+
+ info("Switch to custom and ensure the pref updates");
+ prefChange = waitForAndAssertPrefState(
+ CAT_PREF,
+ "custom",
+ "ETP category pref set to custom"
+ );
+ synthesizeClick(customRadio);
+ await prefChange;
+ ok(customRadio.checked, "Custom radio button selected");
+
+ let customizeEnabled = () => !customizeButton.parentDisabled;
+ if (!customizeEnabled()) {
+ await BrowserTestUtils.waitForMutationCondition(
+ customizeButton,
+ { attributes: true, attributeFilter: ["parentdisabled"] },
+ customizeEnabled
+ );
+ }
+ ok(customizeEnabled(), "Customize button enabled when custom level selected");
+ ok(levelWarningVisible(), "ETP level warning remains visible for custom");
+
+ info("Click customize and wait for the custom pane to load");
+ let paneShown = waitForPaneChange("etpCustomize");
+ synthesizeClick(customizeButton);
+ await paneShown;
+ is(
+ win.history.state,
+ "paneEtpCustomize",
+ "Customize button navigated to the ETP custom pane"
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+// Ensures strict baseline checkbox flows prompt for confirmation and gate the convenience checkbox.
+add_task(async function test_strict_baseline_checkbox_requires_confirmation() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [CAT_PREF, "strict"],
+ [BASELINE_PREF, true],
+ [CONVENIENCE_PREF, true],
+ ],
+ });
+
+ let { doc, tab } = await openEtpPage();
+
+ let baselineCheckbox = getControl(doc, "etpAllowListBaselineEnabled");
+ let convenienceCheckbox = getControl(doc, "etpAllowListConvenienceEnabled");
+
+ ok(baselineCheckbox.checked, "Baseline checkbox starts checked");
+
+ info("Cancel the confirmation dialog and ensure checkbox stays checked");
+ await clickBaselineCheckboxWithConfirm(
+ doc,
+ "etpAllowListBaselineEnabled",
+ BASELINE_PREF,
+ true,
+ 0
+ );
+ ok(
+ baselineCheckbox.checked,
+ "Baseline checkbox remains checked after cancelling dialog"
+ );
+
+ info("Confirm the dialog to disable the baseline allow list");
+ await clickBaselineCheckboxWithConfirm(
+ doc,
+ "etpAllowListBaselineEnabled",
+ BASELINE_PREF,
+ false,
+ 1
+ );
+ ok(
+ !Services.prefs.getBoolPref(BASELINE_PREF),
+ "Baseline pref disabled after confirming dialog"
+ );
+ ok(
+ convenienceCheckbox.parentDisabled,
+ "Convenience checkbox disabled when baseline unchecked"
+ );
+
+ info("Re-enable baseline and ensure convenience becomes active again");
+ let prefChange = waitForAndAssertPrefState(
+ BASELINE_PREF,
+ true,
+ "Baseline pref restored"
+ );
+ synthesizeClick(baselineCheckbox);
+ await prefChange;
+
+ let convenienceEnabled = () => !convenienceCheckbox.parentDisabled;
+ if (!convenienceEnabled()) {
+ await BrowserTestUtils.waitForMutationCondition(
+ convenienceCheckbox,
+ { attributes: true, attributeFilter: ["parentdisabled"] },
+ convenienceEnabled
+ );
+ }
+ ok(
+ convenienceEnabled(),
+ "Convenience checkbox enabled again after baseline re-enabled"
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+// Ensures the RFP warning visibility follows the resistFingerprinting pref.
+add_task(async function test_rfp_warning_visibility() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [CAT_PREF, "strict"],
+ ["privacy.resistFingerprinting.pbmode", false],
+ ["privacy.resistFingerprinting", false],
+ ],
+ });
+
+ let { doc, tab } = await openEtpPage();
+
+ let rfpWarning = getControl(doc, "rfpWarning");
+ ok(
+ BrowserTestUtils.isHidden(rfpWarning),
+ "RFP warning hidden while pref disabled"
+ );
+
+ let mutationTarget = doc.documentElement;
+ let warningVisibleCondition = () => {
+ let el = doc.getElementById("rfpWarning");
+ return el && BrowserTestUtils.isVisible(el);
+ };
+
+ info("Enable normal RFP and wait for the warning to show");
+ let waitForVisible = BrowserTestUtils.waitForMutationCondition(
+ mutationTarget,
+ { attributes: true, childList: true, subtree: true },
+ warningVisibleCondition
+ );
+ Services.prefs.setBoolPref("privacy.resistFingerprinting", true);
+ await waitForVisible;
+ rfpWarning = getControl(doc, "rfpWarning");
+ ok(
+ BrowserTestUtils.isVisible(rfpWarning),
+ "RFP warning visible when pref enabled"
+ );
+
+ let warningHiddenCondition = () => {
+ let el = doc.getElementById("rfpWarning");
+ return el && BrowserTestUtils.isHidden(el);
+ };
+
+ info("Disable normal RFP and wait for the warning to hide");
+ let waitForHidden = BrowserTestUtils.waitForMutationCondition(
+ mutationTarget,
+ { attributes: true, childList: true, subtree: true },
+ warningHiddenCondition
+ );
+ Services.prefs.setBoolPref("privacy.resistFingerprinting", false);
+ await waitForHidden;
+ rfpWarning = getControl(doc, "rfpWarning");
+ ok(
+ BrowserTestUtils.isHidden(rfpWarning),
+ "RFP warning hidden when pref disabled again"
+ );
+
+ info("Enable PBM RFP and wait for the warning to show");
+ waitForVisible = BrowserTestUtils.waitForMutationCondition(
+ mutationTarget,
+ { attributes: true, childList: true, subtree: true },
+ warningVisibleCondition
+ );
+ Services.prefs.setBoolPref("privacy.resistFingerprinting.pbmode", true);
+ await waitForVisible;
+ rfpWarning = getControl(doc, "rfpWarning");
+ ok(
+ BrowserTestUtils.isVisible(rfpWarning),
+ "RFP warning visible when PBM pref enabled"
+ );
+
+ info("Disable PBM RFP and wait for the warning to hide");
+ waitForHidden = BrowserTestUtils.waitForMutationCondition(
+ mutationTarget,
+ { attributes: true, childList: true, subtree: true },
+ warningHiddenCondition
+ );
+ Services.prefs.setBoolPref("privacy.resistFingerprinting.pbmode", false);
+ await waitForHidden;
+ rfpWarning = getControl(doc, "rfpWarning");
+ ok(
+ BrowserTestUtils.isHidden(rfpWarning),
+ "RFP warning hidden when PBM pref disabled again"
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+// Ensures the manage exceptions button opens the permissions dialog.
+add_task(async function test_manage_exceptions_button_opens_dialog() {
+ await SpecialPowers.pushPrefEnv({
+ set: [[CAT_PREF, "standard"]],
+ });
+
+ let { doc, tab } = await openEtpPage();
+
+ let manageButton = getControl(doc, "etpManageExceptionsButton");
+ let dialogPromise = promiseLoadSubDialog(PERMISSIONS_DIALOG_URL);
+ synthesizeClick(manageButton);
+ let dialogWin = await dialogPromise;
+ await dialogWin.document.mozSubdialogReady;
+ ok(
+ dialogWin.document.getElementById("permissionsBox"),
+ "Permissions dialog rendered for manage exceptions"
+ );
+ let dialogEl = dialogWin.document.querySelector("dialog");
+ dialogEl.getButton("cancel").click();
+ await BrowserTestUtils.waitForEvent(dialogWin, "unload");
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/components/preferences/tests/browser_etp_customize.js b/browser/components/preferences/tests/browser_etp_customize.js
@@ -0,0 +1,388 @@
+/* Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const CAT_PREF = "browser.contentblocking.category";
+const BASELINE_PREF = "privacy.trackingprotection.allow_list.baseline.enabled";
+const CONVENIENCE_PREF =
+ "privacy.trackingprotection.allow_list.convenience.enabled";
+const COOKIE_BEHAVIOR_PREF = "network.cookie.cookieBehavior";
+const TP_PREF = "privacy.trackingprotection.enabled";
+const TP_PBM_PREF = "privacy.trackingprotection.pbmode.enabled";
+const CRYPTOMINING_PREF = "privacy.trackingprotection.cryptomining.enabled";
+const FINGERPRINTING_PREF = "privacy.trackingprotection.fingerprinting.enabled";
+const SUSPECT_FP_PREF = "privacy.fingerprintingProtection";
+const SUSPECT_FP_PBM_PREF = "privacy.fingerprintingProtection.pbmode";
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.settings-redesign.enabled", true]],
+ });
+});
+
+function getControl(doc, id) {
+ let control = doc.getElementById(id);
+ ok(control, `Control ${id} exists`);
+ return control;
+}
+
+function synthesizeClick(el) {
+ let target = el.buttonEl ?? el.inputEl ?? el;
+ target.scrollIntoView({ block: "center" });
+ EventUtils.synthesizeMouseAtCenter(target, {}, target.ownerGlobal);
+}
+
+async function openEtpCustomizePage() {
+ await openPreferencesViaOpenPreferencesAPI("etpCustomize", {
+ leaveOpen: true,
+ });
+ let doc = gBrowser.contentDocument;
+ await BrowserTestUtils.waitForCondition(
+ () => doc.getElementById("etpAllowListBaselineEnabledCustom"),
+ "Wait for the ETP customize controls to render"
+ );
+ return {
+ win: gBrowser.contentWindow,
+ doc,
+ };
+}
+
+async function changeMozSelectValue(selectEl, value) {
+ let control = selectEl.control;
+ let changePromise = waitForSettingControlChange(control);
+ selectEl.value = value;
+ selectEl.dispatchEvent(new Event("change", { bubbles: true }));
+ await changePromise;
+}
+
+async function clickBaselineCheckboxWithConfirm(
+ doc,
+ controlId,
+ prefName,
+ expectedValue,
+ buttonNumClick
+) {
+ let checkbox = getControl(doc, controlId);
+
+ let promptPromise = PromptTestUtils.handleNextPrompt(
+ gBrowser.selectedBrowser,
+ { modalType: Services.prompt.MODAL_TYPE_CONTENT },
+ { buttonNumClick }
+ );
+
+ let prefChangePromise = null;
+ if (buttonNumClick === 1) {
+ prefChangePromise = waitForAndAssertPrefState(
+ prefName,
+ expectedValue,
+ `${prefName} updated`
+ );
+ }
+
+ synthesizeClick(checkbox);
+
+ await promptPromise;
+ if (prefChangePromise) {
+ await prefChangePromise;
+ }
+
+ is(
+ checkbox.checked,
+ expectedValue,
+ `Checkbox ${controlId} should be ${expectedValue}`
+ );
+
+ return checkbox;
+}
+
+// Confirms reset buttons drive the category pref and enable/disable appropriately.
+add_task(async function test_etp_reset_buttons_update_category() {
+ await SpecialPowers.pushPrefEnv({
+ set: [[CAT_PREF, "standard"]],
+ });
+
+ let { doc } = await openEtpCustomizePage();
+ let standardButton = getControl(doc, "etpResetStandardButton");
+ let strictButton = getControl(doc, "etpResetStrictButton");
+
+ ok(standardButton.disabled, "Standard reset button disabled on standard");
+ ok(!strictButton.disabled, "Strict reset button enabled");
+
+ let prefChange = waitForAndAssertPrefState(
+ CAT_PREF,
+ "strict",
+ "ETP category pref switched to strict"
+ );
+ synthesizeClick(strictButton);
+ await prefChange;
+
+ ok(strictButton.disabled, "Strict reset button disabled after use");
+ ok(
+ !standardButton.disabled,
+ "Standard reset button enabled after switching to strict"
+ );
+
+ prefChange = waitForAndAssertPrefState(
+ CAT_PREF,
+ "standard",
+ "ETP category pref switched back to standard"
+ );
+ synthesizeClick(standardButton);
+ await prefChange;
+
+ gBrowser.removeCurrentTab();
+});
+
+// Mirrors legacy allow list checkbox behavior and confirmation prompts in the custom pane.
+add_task(async function test_custom_allow_list_controls_match_old_behavior() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [CAT_PREF, "custom"],
+ [BASELINE_PREF, true],
+ [CONVENIENCE_PREF, true],
+ ],
+ });
+
+ let { doc } = await openEtpCustomizePage();
+ let baselineCheckbox = getControl(doc, "etpAllowListBaselineEnabledCustom");
+ let convenienceCheckbox = getControl(
+ doc,
+ "etpAllowListConvenienceEnabledCustom"
+ );
+
+ ok(baselineCheckbox.checked, "Custom baseline checkbox starts checked");
+
+ await clickBaselineCheckboxWithConfirm(
+ doc,
+ "etpAllowListBaselineEnabledCustom",
+ BASELINE_PREF,
+ false,
+ 1
+ );
+
+ ok(
+ !Services.prefs.getBoolPref(BASELINE_PREF),
+ "Baseline pref disabled from custom controls"
+ );
+ ok(
+ convenienceCheckbox.parentDisabled,
+ "Custom convenience checkbox disabled when baseline unchecked"
+ );
+
+ let baselinePrefChange = waitForAndAssertPrefState(
+ BASELINE_PREF,
+ true,
+ "Baseline pref restored"
+ );
+ synthesizeClick(baselineCheckbox);
+ await baselinePrefChange;
+ await BrowserTestUtils.waitForCondition(
+ () => !convenienceCheckbox.parentDisabled,
+ "Custom convenience checkbox enabled once baseline rechecked"
+ );
+
+ gBrowser.removeCurrentTab();
+});
+
+// Validates the cookie toggle/select wiring for custom mode.
+add_task(async function test_custom_cookie_controls() {
+ let defaults = Services.prefs.getDefaultBranch("");
+ let defaultCookieBehavior = defaults.getIntPref(COOKIE_BEHAVIOR_PREF);
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [CAT_PREF, "custom"],
+ [COOKIE_BEHAVIOR_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT],
+ ],
+ });
+
+ let { doc } = await openEtpCustomizePage();
+ let cookieToggle = getControl(doc, "etpCustomCookiesEnabled");
+ let cookieSelect = getControl(doc, "cookieBehavior");
+
+ ok(
+ !cookieToggle.pressed,
+ "Cookie toggle starts disabled when behavior is accept"
+ );
+
+ let prefChange = waitForAndAssertPrefState(
+ COOKIE_BEHAVIOR_PREF,
+ defaultCookieBehavior,
+ "Enabling cookie toggle restores default behavior"
+ );
+ synthesizeClick(cookieToggle.buttonEl);
+ await prefChange;
+
+ ok(cookieToggle.pressed, "Cookie toggle is pressed when enabled");
+
+ info("Select a stricter cookie behavior through the dropdown");
+ let newBehavior = Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN.toString();
+ await changeMozSelectValue(cookieSelect, newBehavior);
+ is(
+ Services.prefs.getIntPref(COOKIE_BEHAVIOR_PREF),
+ Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN,
+ "Cookie behavior pref updated from moz-select"
+ );
+
+ prefChange = waitForAndAssertPrefState(
+ COOKIE_BEHAVIOR_PREF,
+ Ci.nsICookieService.BEHAVIOR_ACCEPT,
+ "Disabling cookie toggle accepts all cookies"
+ );
+ synthesizeClick(cookieToggle.buttonEl);
+ await prefChange;
+
+ ok(!cookieToggle.pressed, "Cookie toggle reflects disabled state");
+
+ gBrowser.removeCurrentTab();
+});
+
+// Checks tracking protection toggle and scope dropdown interactions.
+add_task(async function test_custom_tracking_protection_controls() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [CAT_PREF, "custom"],
+ [TP_PREF, false],
+ [TP_PBM_PREF, true],
+ ],
+ });
+
+ let { doc } = await openEtpCustomizePage();
+ let tpToggle = getControl(doc, "etpCustomTrackingProtectionEnabled");
+ let tpContext = getControl(doc, "etpCustomTrackingProtectionEnabledContext");
+
+ ok(tpToggle.pressed, "Tracking protection toggle starts enabled");
+
+ let prefChange = TestUtils.waitForPrefChange(
+ TP_PBM_PREF,
+ value => value === false
+ );
+ synthesizeClick(tpToggle.buttonEl);
+ await prefChange;
+
+ ok(!tpToggle.pressed, "Tracking protection toggle reflects disabled state");
+ ok(
+ !Services.prefs.getBoolPref(TP_PREF),
+ "All-windows tracking protection pref remains false"
+ );
+
+ prefChange = TestUtils.waitForPrefChange(
+ TP_PBM_PREF,
+ value => value === true
+ );
+ synthesizeClick(tpToggle.buttonEl);
+ await prefChange;
+ ok(tpToggle.pressed, "Tracking protection toggle enabled again");
+ ok(
+ !Services.prefs.getBoolPref(TP_PREF),
+ "All-windows tracking protection pref still false after re-enabling toggle"
+ );
+
+ info("Switch context to protect all windows");
+ await changeMozSelectValue(tpContext, "all");
+ ok(
+ Services.prefs.getBoolPref(TP_PREF),
+ "Tracking protection pref enabled for all windows"
+ );
+ ok(
+ Services.prefs.getBoolPref(TP_PBM_PREF),
+ "Tracking protection PBM pref stays enabled"
+ );
+
+ info("Switch back to private windows only");
+ await changeMozSelectValue(tpContext, "pbmOnly");
+ ok(
+ !Services.prefs.getBoolPref(TP_PREF),
+ "All windows pref disabled when choosing private only"
+ );
+ ok(
+ Services.prefs.getBoolPref(TP_PBM_PREF),
+ "Private windows pref stays enabled"
+ );
+
+ gBrowser.removeCurrentTab();
+});
+
+// Covers cryptomining/fingerprinting toggles and suspect protection context behavior.
+add_task(async function test_custom_fingerprinting_controls() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [CAT_PREF, "custom"],
+ [CRYPTOMINING_PREF, false],
+ [FINGERPRINTING_PREF, false],
+ [SUSPECT_FP_PREF, false],
+ [SUSPECT_FP_PBM_PREF, false],
+ ],
+ });
+
+ let { doc } = await openEtpCustomizePage();
+ let cryptoToggle = getControl(doc, "etpCustomCryptominingProtectionEnabled");
+ let knownFpToggle = getControl(
+ doc,
+ "etpCustomKnownFingerprintingProtectionEnabled"
+ );
+ let suspectFpToggle = getControl(
+ doc,
+ "etpCustomSuspectFingerprintingProtectionEnabled"
+ );
+ let suspectContext = getControl(
+ doc,
+ "etpCustomSuspectFingerprintingProtectionEnabledContext"
+ );
+
+ info("Enable cryptomining protection");
+ let prefChange = waitForAndAssertPrefState(
+ CRYPTOMINING_PREF,
+ true,
+ "Cryptomining pref enabled"
+ );
+ synthesizeClick(cryptoToggle.buttonEl);
+ await prefChange;
+
+ info("Enable known fingerprinting protection");
+ prefChange = waitForAndAssertPrefState(
+ FINGERPRINTING_PREF,
+ true,
+ "Fingerprinting pref enabled"
+ );
+ synthesizeClick(knownFpToggle.buttonEl);
+ await prefChange;
+
+ info("Enable suspect fingerprinting protection");
+ prefChange = TestUtils.waitForPrefChange(
+ SUSPECT_FP_PBM_PREF,
+ value => value === true
+ );
+ synthesizeClick(suspectFpToggle.buttonEl);
+ await prefChange;
+ ok(
+ !Services.prefs.getBoolPref(SUSPECT_FP_PREF),
+ "All-windows suspect fingerprinting pref remains false after toggle"
+ );
+
+ info("Switch suspect protection context to all windows");
+ await changeMozSelectValue(suspectContext, "all");
+ ok(
+ Services.prefs.getBoolPref(SUSPECT_FP_PREF),
+ "All-windows suspect fingerprinting pref enabled"
+ );
+ ok(
+ Services.prefs.getBoolPref(SUSPECT_FP_PBM_PREF),
+ "PBM suspect fingerprinting pref remains enabled"
+ );
+
+ info("Disable suspect protection through the toggle");
+ prefChange = TestUtils.waitForPrefChange(
+ SUSPECT_FP_PBM_PREF,
+ value => value === false
+ );
+ synthesizeClick(suspectFpToggle.buttonEl);
+ await prefChange;
+ ok(
+ !Services.prefs.getBoolPref(SUSPECT_FP_PREF),
+ "All-window suspect pref disabled after toggle off"
+ );
+
+ gBrowser.removeCurrentTab();
+});
diff --git a/browser/components/preferences/widgets/setting-control/setting-control.mjs b/browser/components/preferences/widgets/setting-control/setting-control.mjs
@@ -214,7 +214,7 @@ export class SettingControl extends SettingElement {
control.value = this.value;
}
- control.requestUpdate();
+ control.requestUpdate?.();
}
/**