tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 12b4adb7efa5bbcd4eff9522044c2fef91d84af8
parent 34b94c2ba9563b11b24f89a825b0254e3a0f64aa
Author: Mark Striemer <mstriemer@mozilla.com>
Date:   Fri, 14 Nov 2025 19:28:54 +0000

Bug 1975762 - Tests for setting-pane sub pages r=desktop-theme-reviewers,mconley,tgiles

Differential Revision: https://phabricator.services.mozilla.com/D270940

Diffstat:
Mbrowser/components/preferences/main.js | 7+++----
Mbrowser/components/preferences/preferences.js | 110++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mbrowser/components/preferences/tests/browser.toml | 58++++++++++++++++++++++++++++++++++++++++++----------------
Abrowser/components/preferences/tests/browser_setting_pane_sub_pane.js | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/preferences/tests/head.js | 14++++++++++++++
Mbrowser/components/preferences/widgets/setting-pane/setting-pane.mjs | 11+++++++++++
Mtoolkit/content/widgets/moz-button/moz-button.css | 4++++
Mtoolkit/content/widgets/moz-page-header/moz-page-header.mjs | 5+++++
8 files changed, 262 insertions(+), 37 deletions(-)

diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js @@ -1127,8 +1127,7 @@ Preferences.addSetting({ }, }); -/** @type {Record<string, SettingGroupConfig>} */ -let SETTINGS_CONFIG = { +SettingGroupManager.registerGroups({ containers: { // This section is marked as in progress for testing purposes inProgress: true, @@ -1879,7 +1878,7 @@ let SETTINGS_CONFIG = { }, ], }, -}; +}); /** * @param {string} id - ID of {@link SettingGroup} custom element. @@ -1887,7 +1886,7 @@ let SETTINGS_CONFIG = { function initSettingGroup(id) { /** @type {SettingGroup} */ let group = document.querySelector(`setting-group[groupid=${id}]`); - const config = SETTINGS_CONFIG[id]; + const config = SettingGroupManager.get(id); if (group && config) { if (config.inProgress && !srdSectionEnabled(id)) { group.remove(); diff --git a/browser/components/preferences/preferences.js b/browser/components/preferences/preferences.js @@ -176,14 +176,102 @@ function srdSectionEnabled(section) { return srdSectionPrefs.all || srdSectionPrefs[section]; } -/** @type {Record<string, SettingPaneConfig>} */ -const CONFIG_PANES = { +var SettingPaneManager = { + /** @type {Map<string, SettingPaneConfig>} */ + _data: new Map(), + + /** + * @param {string} id + */ + get(id) { + if (!this._data.has(id)) { + throw new Error(`Setting pane "${id}" not found`); + } + return this._data.get(id); + }, + + /** + * @param {string} id + * @param {SettingPaneConfig} config + */ + registerPane(id, config) { + if (this._data.has(id)) { + throw new Error(`Setting pane "${id}" already registered`); + } + this._data.set(id, config); + let subPane = friendlyPrefCategoryNameToInternalName(id); + let settingPane = /** @type {SettingPane} */ ( + document.createElement("setting-pane") + ); + settingPane.name = subPane; + settingPane.config = config; + settingPane.isSubPane = !!config.parent; + document.getElementById("mainPrefPane").append(settingPane); + register_module(subPane, { + init() { + settingPane.init(); + }, + }); + }, + + /** + * @param {Record<string, SettingPaneConfig>} paneConfigs + */ + registerPanes(paneConfigs) { + for (let id in paneConfigs) { + this.registerPane(id, paneConfigs[id]); + } + }, +}; + +var SettingGroupManager = { + /** @type {Map<string, SettingGroupConfig>} */ + _data: new Map(), + + /** + * @param {string} id + */ + get(id) { + if (!this._data.has(id)) { + throw new Error(`Setting group "${id}" not found`); + } + return this._data.get(id); + }, + + /** + * @param {string} id + * @param {SettingGroupConfig} config + */ + registerGroup(id, config) { + if (this._data.has(id)) { + throw new Error(`Setting group "${id}" already registered`); + } + this._data.set(id, config); + }, + + /** + * @param {Record<string, SettingGroupConfig>} groupConfigs + */ + registerGroups(groupConfigs) { + for (let id in groupConfigs) { + this.registerGroup(id, groupConfigs[id]); + } + }, +}; + +/** + * Register initial config-based setting panes here. If you need to register a + * pane elsewhere, use {@link SettingPaneManager['registerPane']}. + * + * @type {Record<string, SettingPaneConfig>} + */ +const CONFIG_PANES = Object.freeze({ containers2: { parent: "general", l10nId: "containers-section-header", groupIds: ["containers"], }, -}; +}); var gLastCategory = { category: undefined, subcategory: undefined }; const gXULDOMParser = new DOMParser(); @@ -237,20 +325,8 @@ function init_all() { register_module("panePrivacy", gPrivacyPane); register_module("paneContainers", gContainersPane); - for (let [subPane, config] of Object.entries(CONFIG_PANES)) { - subPane = friendlyPrefCategoryNameToInternalName(subPane); - let settingPane = /** @type {SettingPane} */ ( - document.createElement("setting-pane") - ); - settingPane.name = subPane; - settingPane.config = config; - settingPane.isSubPane = !!config.parent; - document.getElementById("mainPrefPane").append(settingPane); - register_module(subPane, { - init() { - settingPane.init(); - }, - }); + for (let [id, config] of Object.entries(CONFIG_PANES)) { + SettingPaneManager.registerPane(id, config); } if (Services.prefs.getBoolPref("browser.translations.newSettingsUI.enable")) { diff --git a/browser/components/preferences/tests/browser.toml b/browser/components/preferences/tests/browser.toml @@ -20,7 +20,9 @@ tags = "os_integration" ["browser_about_settings.js"] ["browser_advanced_update.js"] -run-if = ["updater"] +run-if = [ + "updater", +] ["browser_application_xml_handle_internally.js"] @@ -31,7 +33,9 @@ run-if = ["updater"] ["browser_basic_rebuild_fonts_test.js"] ["browser_browser_languages_subdialog.js"] -skip-if = ["tsan"] +skip-if = [ + "tsan", +] ["browser_bug410900.js"] @@ -53,7 +57,9 @@ support-files = ["browser_bug1184989_prevent_scrolling_when_preferences_flipped. ["browser_cert_export.js"] ["browser_change_app_handler.js"] -run-if = ["os == 'win'"] # Windows-specific handler application selection dialog +run-if = [ + "os == 'win'", # Windows-specific handler application selection dialog +] ["browser_checkspelling.js"] @@ -68,7 +74,9 @@ run-if = ["os == 'win'"] # Windows-specific handler application selection dialog ["browser_connection_bug1505330.js"] ["browser_connection_system_wpad.js"] -run-if = ["os == 'win'"] +run-if = [ + "os == 'win'", +] ["browser_connection_telemetry.js"] @@ -100,10 +108,10 @@ run-if = ["os == 'win'"] ["browser_experimental_features_filter.js"] skip-if = [ - "os == 'linux' && os_version == '24.04' && processor == 'x86_64'", # Bug 1969933 - "os == 'mac' && os_version == '10.15' && processor == 'x86_64' && opt", # Bug 1969933 - "os == 'win' && os_version == '11.26100' && processor == 'x86_64'", # Bug 1969933 - "os == 'win' && os_version == '11.26100' && processor == 'x86'", # Bug 1969933 + "os == 'linux' && os_version == '24.04' && arch == 'x86_64'", # Bug 1969933 + "os == 'mac' && os_version == '10.15' && arch == 'x86_64' && opt", # Bug 1969933 + "os == 'win' && os_version == '11.26100' && arch == 'x86'", # Bug 1969933 + "os == 'win' && os_version == '11.26100' && arch == 'x86_64'", # Bug 1969933 ] ["browser_experimental_features_hidden_when_not_public.js"] @@ -139,14 +147,18 @@ https_first_disabled = true ["browser_ignore_invalid_capability.js"] ["browser_keyboardfocus.js"] -run-if = ["os == 'mac'"] +run-if = [ + "os == 'mac'", +] ["browser_languages_subdialog.js"] ["browser_layersacceleration.js"] ["browser_localSearchShortcuts.js"] -fail-if = ["a11y_checks"] # Bug 1854636 clicked treechildren#engineChildren may not be focusable +fail-if = [ + "a11y_checks", # Bug 1854636 clicked treechildren#engineChildren may not be focusable +] ["browser_moreFromMozilla.js"] @@ -172,7 +184,9 @@ support-files = ["empty_pdf_file.pdf"] ["browser_performance_e10srollout.js"] ["browser_performance_non_e10s.js"] -skip-if = ["true"] +skip-if = [ + "true", +] ["browser_permissions_checkPermissionsWereAdded.js"] @@ -187,7 +201,9 @@ skip-if = ["true"] ["browser_primaryPassword.js"] ["browser_privacy_allowListPreference.js"] -skip-if = ["os == 'linux' && os_version == '24.04' && processor == 'x86_64' && tsan"] # Bug 1984525 +skip-if = [ + "os == 'linux' && os_version == '24.04' && arch == 'x86_64' && tsan", # Bug 1984525 +] ["browser_privacy_allowListPreference_dialog.js"] @@ -239,7 +255,9 @@ support-files = ["!/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js ["browser_searchShowSuggestionsFirst.js"] ["browser_search_engineList.js"] -fail-if = ["a11y_checks"] # Bug 1854636 clicked treechildren#engineChildren may not be focusable +fail-if = [ + "a11y_checks", # Bug 1854636 clicked treechildren#engineChildren may not be focusable +] ["browser_search_firefoxSuggest.js"] @@ -252,7 +270,9 @@ fail-if = ["a11y_checks"] # Bug 1854636 clicked treechildren#engineChildren may ["browser_search_subdialog_tooltip_saved_addresses.js"] ["browser_search_subdialogs_within_preferences_1.js"] -skip-if = ["tsan"] # Bug 1678829 +skip-if = [ + "tsan", # Bug 1678829 +] ["browser_search_subdialogs_within_preferences_2.js"] @@ -290,6 +310,8 @@ skip-if = ["tsan"] # Bug 1678829 ["browser_setting_group_in_progress.js"] +["browser_setting_pane_sub_pane.js"] + ["browser_site_login_exceptions.js"] ["browser_site_login_exceptions_policy.js"] @@ -323,7 +345,11 @@ support-files = [ ["browser_warning_permanent_private_browsing.js"] ["browser_windows_launch_on_login.js"] -run-if = ["os == 'win' && !msix"] +run-if = [ + "os == 'win' && !msix", +] ["browser_windows_launch_on_login_msix.js"] -run-if = ["os == 'win' && msix"] +run-if = [ + "os == 'win' && msix", +] diff --git a/browser/components/preferences/tests/browser_setting_pane_sub_pane.js b/browser/components/preferences/tests/browser_setting_pane_sub_pane.js @@ -0,0 +1,90 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +describe("setting-pane", () => { + let doc, win, testSubPaneButton; + + beforeEach(async function setup() { + await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true }); + doc = gBrowser.selectedBrowser.contentDocument; + win = doc.ownerGlobal; + testSubPaneButton = doc.createElement("moz-button"); + testSubPaneButton.hidden = true; + testSubPaneButton.setAttribute("data-category", "panePrivacy"); + testSubPaneButton.textContent = "Go to test pane"; + testSubPaneButton.addEventListener("click", () => + win.gotoPref("paneTestSubPane") + ); + let privacyHeading = doc.getElementById("browserPrivacyCategory"); + privacyHeading.insertAdjacentElement("afterend", testSubPaneButton); + win.Preferences.addSetting({ + id: "testSetting", + get: () => true, + }); + win.SettingGroupManager.registerGroup("testGroup", { + l10nId: "downloads-header-2", + headingLevel: 2, + items: [ + { + id: "testSetting", + controlAttrs: { + label: "Test setting", + }, + }, + ], + }); + win.SettingPaneManager.registerPane("testSubPane", { + parent: "privacy", + l10nId: "containers-section-header", + groupIds: ["testGroup"], + }); + }); + + afterEach(() => BrowserTestUtils.removeTab(gBrowser.selectedTab)); + + it("can load/go back sub-pane", async () => { + let pane = doc.querySelector( + 'setting-pane[data-category="paneTestSubPane"]' + ); + is_element_hidden(pane, "Sub pane is initially hidden"); + + // Load the privacy pane + let paneLoaded = waitForPaneChange("privacy"); + EventUtils.synthesizeMouseAtCenter( + doc.getElementById("category-privacy"), + {}, + win + ); + await paneLoaded; + + // Load the sub pane + paneLoaded = waitForPaneChange("testSubPane"); + EventUtils.synthesizeMouseAtCenter(testSubPaneButton, {}, win); + await paneLoaded; + + is_element_visible(pane, "Page header is visible"); + ok(pane, "There is a setting pane"); + await pane.updateComplete; + let pageHeader = pane.pageHeaderEl; + ok(pageHeader, "There is a page header"); + is( + pageHeader.dataset.l10nId, + "containers-section-header", + "Page header has its l10nId" + ); + let heading = pageHeader.headingEl; + ok(heading, "There is a heading in the header"); + ok(heading.innerText, "The heading has text"); + is(heading.innerText, pageHeader.heading, "The text is localized"); + let backButton = pageHeader.backButtonEl; + ok(backButton, "There is a back button"); + + // Go back + paneLoaded = waitForPaneChange("privacy"); + EventUtils.synthesizeMouseAtCenter(backButton, {}, win); + await paneLoaded; + is_element_hidden(pane, "Sub pane is hidden again"); + }); +}); diff --git a/browser/components/preferences/tests/head.js b/browser/components/preferences/tests/head.js @@ -704,3 +704,17 @@ async function updateCheckBox(win, id, value) { // Toggle the state. await EventUtils.synthesizeMouseAtCenter(checkbox, {}, checkbox.ownerGlobal); } + +/** + * Wait for the current setting pane to change. + * + * @param {string} paneId + */ +async function waitForPaneChange(paneId) { + let doc = gBrowser.selectedBrowser.contentDocument; + let event = await BrowserTestUtils.waitForEvent(doc, "paneshown"); + let expectId = paneId.startsWith("pane") + ? paneId + : `pane${paneId[0].toUpperCase()}${paneId.substring(1)}`; + is(event.detail.category, expectId, "Loaded the correct pane"); +} diff --git a/browser/components/preferences/widgets/setting-pane/setting-pane.mjs b/browser/components/preferences/widgets/setting-pane/setting-pane.mjs @@ -19,6 +19,10 @@ export class SettingPane extends MozLitElement { config: { type: Object }, }; + static queries = { + pageHeaderEl: "moz-page-header", + }; + constructor() { super(); /** @type {string} */ @@ -33,6 +37,13 @@ export class SettingPane extends MozLitElement { return this; } + async getUpdateComplete() { + let result = await super.getUpdateComplete(); + // @ts-ignore bug 1997478 + await this.pageHeaderEl.updateComplete; + return result; + } + goBack() { window.gotoPref(this.config.parent); } diff --git a/toolkit/content/widgets/moz-button/moz-button.css b/toolkit/content/widgets/moz-button/moz-button.css @@ -2,6 +2,10 @@ * 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/. */ +:host([hidden]) { + display: none !important; +} + :host { display: inline-block; height: fit-content; diff --git a/toolkit/content/widgets/moz-page-header/moz-page-header.mjs b/toolkit/content/widgets/moz-page-header/moz-page-header.mjs @@ -29,6 +29,11 @@ export default class MozPageHeader extends MozLitElement { backButton: { type: Boolean }, }; + static queries = { + headingEl: "h1", + backButtonEl: "moz-button", + }; + constructor() { super(); this.heading = "";