commit eb04fcc25debff99dbfeb67aa7a5945971a3a13d
parent ab5b5007b1240c3a31a9a2397fa03bdc5bcf4196
Author: hannajones <hjones@mozilla.com>
Date: Wed, 5 Nov 2025 16:17:56 +0000
Bug 1998430 - add a listener for toggle events to setting-group r=mstriemer
Differential Revision: https://phabricator.services.mozilla.com/D271410
Diffstat:
4 files changed, 568 insertions(+), 515 deletions(-)
diff --git a/browser/components/preferences/tests/chrome/chrome.toml b/browser/components/preferences/tests/chrome/chrome.toml
@@ -6,7 +6,7 @@ support-files = [
["test_nav_notice.html"]
-["test_setting_control_checkbox.html"]
+["test_setting_control.html"]
["test_setting_control_controlAttrs.html"]
diff --git a/browser/components/preferences/tests/chrome/test_setting_control.html b/browser/components/preferences/tests/chrome/test_setting_control.html
@@ -0,0 +1,566 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>setting-control test</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link
+ rel="stylesheet"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ />
+ <link rel="stylesheet" href="chrome://global/skin/global.css" />
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <script src="../../../../../toolkit/content/tests/widgets/lit-test-helpers.js"></script>
+ <script src="./head.js"></script>
+ <script
+ type="module"
+ src="chrome://browser/content/preferences/widgets/setting-group.mjs"
+ ></script>
+ <script
+ type="module"
+ src="chrome://browser/content/preferences/widgets/setting-control.mjs"
+ ></script>
+ <script
+ type="module"
+ src="chrome://global/content/elements/moz-support-link.mjs"
+ ></script>
+ <script
+ type="application/javascript"
+ src="chrome://global/content/preferencesBindings.js"
+ ></script>
+ <script>
+ /* import-globals-from /toolkit/content/preferencesBindings.js */
+ let html, testHelpers;
+
+ const LABEL_L10N_ID = "browsing-use-autoscroll";
+ const GROUP_L10N_ID = "pane-experimental-reset";
+
+ async function renderTemplate(itemConfig) {
+ let config = {
+ items: [itemConfig],
+ };
+ let result = await testHelpers.renderTemplate(html`
+ <setting-group
+ .config=${config}
+ .getSetting=${(...args) => Preferences.getSetting(...args)}
+ ></setting-group>
+ `);
+ await result.firstElementChild.updateComplete;
+ return result.querySelector("setting-control");
+ }
+
+ function waitForSettingChange(setting) {
+ return new Promise(resolve => {
+ setting.on("change", function handler() {
+ setting.off("change", handler);
+ resolve();
+ });
+ });
+ }
+
+ add_setup(async function setup() {
+ testHelpers = new InputTestHelpers();
+ ({ html } = await testHelpers.setupLit());
+ testHelpers.setupTests({
+ templateFn: () => html`<setting-group></setting-group>`,
+ });
+ MozXULElement.insertFTLIfNeeded("branding/brand.ftl");
+ MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl");
+ });
+
+ add_task(async function testSimpleCheckbox() {
+ const PREF = "test.setting-control.one";
+ const SETTING = "setting-control-one";
+ await SpecialPowers.pushPrefEnv({
+ set: [[PREF, true]],
+ });
+ Preferences.addAll([{ id: PREF, type: "bool" }]);
+ Preferences.addSetting({
+ id: SETTING,
+ pref: PREF,
+ });
+ let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
+ let setting = Preferences.getSetting(SETTING);
+ let control = await renderTemplate(itemConfig);
+ is(
+ control.controlEl.localName,
+ "moz-checkbox",
+ "The control rendered a checkbox"
+ );
+ is(control.controlEl.dataset.l10nId, LABEL_L10N_ID, "Label is set");
+ is(control.controlEl.checked, true, "checkbox is checked");
+ is(control.controlEl.disabled, false, "checkbox is enabled");
+ is(Services.prefs.getBoolPref(PREF), true, "pref is true");
+
+ let settingChanged = waitForSettingChange(setting);
+ synthesizeMouseAtCenter(control.controlEl, {});
+ await settingChanged;
+ is(
+ control.controlEl.checked,
+ false,
+ "checkbox becomes unchecked after click"
+ );
+ is(Services.prefs.getBoolPref(PREF), false, "pref is false");
+
+ settingChanged = waitForSettingChange(setting);
+ Services.prefs.setBoolPref(PREF, true);
+ await settingChanged;
+ is(
+ control.controlEl.checked,
+ true,
+ "checkbox becomes checked after pref change"
+ );
+ is(Services.prefs.getBoolPref(PREF), true, "pref is true");
+
+ // Pref locking
+ settingChanged = waitForSettingChange(setting);
+ Services.prefs.lockPref(PREF);
+ await settingChanged;
+ is(
+ control.controlEl.disabled,
+ true,
+ "checkbox is disabled when locked"
+ );
+
+ settingChanged = waitForSettingChange(setting);
+ Services.prefs.unlockPref(PREF);
+ await settingChanged;
+ is(
+ control.controlEl.disabled,
+ false,
+ "checkbox is enabled when unlocked"
+ );
+ });
+
+ add_task(async function testSimpleToggle() {
+ const PREF = "test.setting-control.toggle";
+ const SETTING = "setting-control-toggle";
+ await SpecialPowers.pushPrefEnv({
+ set: [[PREF, true]],
+ });
+ Preferences.addAll([{ id: PREF, type: "bool" }]);
+ Preferences.addSetting({
+ id: SETTING,
+ pref: PREF,
+ });
+ let itemConfig = {
+ l10nId: LABEL_L10N_ID,
+ id: SETTING,
+ control: "moz-toggle",
+ };
+ let setting = Preferences.getSetting(SETTING);
+ let control = await renderTemplate(itemConfig);
+
+ is(
+ control.controlEl.localName,
+ "moz-toggle",
+ "The control rendered a toggle"
+ );
+ is(control.controlEl.dataset.l10nId, LABEL_L10N_ID, "Label is set");
+ is(control.controlEl.pressed, true, "toggle is pressed");
+ is(control.controlEl.disabled, false, "toggle is enabled");
+ is(Services.prefs.getBoolPref(PREF), true, "pref is true");
+
+ let settingChanged = waitForSettingChange(setting);
+ synthesizeMouseAtCenter(control.controlEl, {});
+ await settingChanged;
+
+ is(
+ control.controlEl.pressed,
+ false,
+ "toggle becomes unchecked after click"
+ );
+ is(Services.prefs.getBoolPref(PREF), false, "pref is false");
+
+ settingChanged = waitForSettingChange(setting);
+ Services.prefs.setBoolPref(PREF, true);
+ await settingChanged;
+
+ is(
+ control.controlEl.pressed,
+ true,
+ "toggle becomes pressed after pref change"
+ );
+ is(Services.prefs.getBoolPref(PREF), true, "pref is true");
+ });
+
+ add_task(async function testSettingSameControlValue() {
+ const SETTING = "setting-control-same-value";
+ Preferences.addSetting({
+ id: SETTING,
+ get: () => false,
+ set: () => false,
+ });
+ let itemConfig = {
+ l10nId: LABEL_L10N_ID,
+ id: SETTING,
+ };
+ let setting = Preferences.getSetting(SETTING);
+ let control = await renderTemplate(itemConfig);
+ ok(control, "Got a control");
+ let checkbox = control.controlEl;
+ is(checkbox.localName, "moz-checkbox", "moz-checkbox is rendered");
+ is(checkbox.checked, false, "checkbox is unchecked on initial render");
+
+ let settingChanged = waitForSettingChange(setting);
+ synthesizeMouseAtCenter(checkbox, {});
+ setting.emit("change");
+ await settingChanged;
+ is(checkbox.checked, false, "checkbox stays unchecked after click");
+ });
+
+ add_task(async function testSupportLinkCheckbox() {
+ const SETTING = "setting-control-support-link";
+ Preferences.addSetting({
+ id: SETTING,
+ get: () => true,
+ });
+ let itemConfig = {
+ l10nId: LABEL_L10N_ID,
+ id: SETTING,
+ supportPage: "foo",
+ };
+ let control = await renderTemplate(
+ itemConfig,
+ Preferences.getSetting(SETTING)
+ );
+ ok(control, "Got a control");
+ let checkbox = control.controlEl;
+ is(checkbox.localName, "moz-checkbox", "moz-checkbox is rendered");
+ is(
+ checkbox.supportPage,
+ "foo",
+ "The checkbox receives the supportPage"
+ );
+ });
+
+ add_task(async function testCommonControlProperties() {
+ const SETTING = "setting-common-props";
+ Preferences.addSetting({
+ id: SETTING,
+ get: () => true,
+ });
+
+ await testCommonSettingControlProperties(async commonConfig => {
+ const control = await renderTemplate({
+ id: SETTING,
+ ...commonConfig,
+ });
+ return control.querySelector("moz-checkbox");
+ });
+ });
+
+ add_task(async function testSupportLinkSubcategory() {
+ const SETTING = "setting-control-subcategory";
+ Preferences.addSetting({
+ id: SETTING,
+ get: () => true,
+ });
+
+ let configOne = {
+ l10nId: LABEL_L10N_ID,
+ id: SETTING,
+ subcategory: "exsubcategory",
+ };
+ let control = await renderTemplate(
+ configOne,
+ Preferences.getSetting(SETTING)
+ );
+ ok(control, "Got the control");
+ is(
+ control.controlEl.dataset.subcategory,
+ "exsubcategory",
+ "Subcategory is set"
+ );
+
+ let configTwo = {
+ l10nId: LABEL_L10N_ID,
+ id: SETTING,
+ subcategory: "exsubcategory2",
+ supportPage: "foo",
+ };
+ control = await renderTemplate(
+ configTwo,
+ Preferences.getSetting(SETTING)
+ );
+ ok(control, "Got the control");
+ is(
+ control.controlEl.dataset.subcategory,
+ "exsubcategory2",
+ "Subcategory is set"
+ );
+
+ is(control.controlEl.supportPage, "foo", "Input got the supportPage");
+ });
+
+ add_task(async function testNestedCheckboxes() {
+ const PREF_PARENT = "test.setting-control.parent";
+ const SETTING_PARENT = "setting-control-parent";
+ const PREF_NESTED = "test.setting-control.nested";
+ const SETTING_NESTED = "setting-control-nested";
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_PARENT, false],
+ [PREF_NESTED, true],
+ ],
+ });
+ Preferences.addAll([
+ { id: PREF_PARENT, type: "bool" },
+ { id: PREF_NESTED, type: "bool" },
+ ]);
+ Preferences.addSetting({
+ id: SETTING_PARENT,
+ pref: PREF_PARENT,
+ });
+ Preferences.addSetting({
+ id: SETTING_NESTED,
+ pref: PREF_NESTED,
+ });
+ let itemConfig = {
+ l10nId: LABEL_L10N_ID,
+ id: SETTING_PARENT,
+ items: [{ l10nId: LABEL_L10N_ID, id: SETTING_NESTED }],
+ };
+ let parentSetting = Preferences.getSetting(SETTING_PARENT);
+ let parentControl = await renderTemplate(itemConfig, parentSetting);
+ is(
+ parentControl.setting.id,
+ SETTING_PARENT,
+ "Parent control id is set"
+ );
+ let nestedControl = parentControl.controlEl.firstElementChild;
+ info("Nested: " + nestedControl.localName);
+ is(
+ nestedControl.setting.id,
+ SETTING_NESTED,
+ "Nested control id is set"
+ );
+ is(parentControl.controlEl.checked, false, "Parent is unchecked");
+ is(
+ parentControl.controlEl.inputEl.disabled,
+ false,
+ "Parent is enabled"
+ );
+ is(nestedControl.controlEl.checked, true, "Nested is checked");
+ is(
+ nestedControl.controlEl.inputEl.disabled,
+ true,
+ "Nested is disabled"
+ );
+
+ let settingChanged = waitForSettingChange(parentSetting);
+ // Click the label since the center of the entire <moz-checkbox> would
+ // be the space between the parent and nested checkboxes.
+ synthesizeMouseAtCenter(parentControl.controlEl.labelEl, {});
+ await settingChanged;
+ await parentControl.updateComplete;
+
+ is(
+ parentControl.controlEl.checked,
+ true,
+ "Parent is checked after click"
+ );
+ is(
+ parentControl.controlEl.inputEl.disabled,
+ false,
+ "Parent is enabled after click"
+ );
+ is(
+ nestedControl.controlEl.checked,
+ true,
+ "Nested is checked after click"
+ );
+ is(
+ nestedControl.controlEl.inputEl.disabled,
+ false,
+ "Nested is enabled after click"
+ );
+
+ settingChanged = waitForSettingChange(parentSetting);
+ Services.prefs.setBoolPref(PREF_PARENT, false);
+ await settingChanged;
+ await parentControl.updateComplete;
+
+ is(
+ parentControl.controlEl.checked,
+ false,
+ "Parent is unchecked after pref change"
+ );
+ is(
+ parentControl.controlEl.inputEl.disabled,
+ false,
+ "Parent is enabled after pref change"
+ );
+ is(
+ nestedControl.controlEl.checked,
+ true,
+ "Nested is checked after pref change"
+ );
+ is(
+ nestedControl.controlEl.inputEl.disabled,
+ true,
+ "Nested is disabled after pref change"
+ );
+ });
+
+ add_task(async function testDepsChangeVisibility() {
+ const DEP_PREF_ID = "test.depsChange.dep";
+ const DEP_SETTING_ID = "testDepsChangeDep";
+ await SpecialPowers.pushPrefEnv({
+ set: [[DEP_PREF_ID, true]],
+ });
+ Preferences.add({ id: DEP_PREF_ID, type: "bool" });
+ Preferences.addSetting({
+ id: DEP_SETTING_ID,
+ pref: DEP_PREF_ID,
+ });
+
+ const PARENT_SETTING_ID = "testDepsChangeParent";
+ Preferences.addSetting({
+ id: PARENT_SETTING_ID,
+ deps: [DEP_SETTING_ID],
+ visible: deps => deps[DEP_SETTING_ID].value,
+ });
+
+ let itemConfig = { l10nId: LABEL_L10N_ID, id: PARENT_SETTING_ID };
+ let setting = Preferences.getSetting(PARENT_SETTING_ID);
+ let control = await renderTemplate(itemConfig, setting);
+ is(
+ control.controlEl.localName,
+ "moz-checkbox",
+ "The control rendered a checkbox"
+ );
+ ok(!control.hidden, "The control is visible");
+ ok(setting.visible, "Setting is visible initially");
+
+ let settingChanged = waitForSettingChange(setting);
+ Services.prefs.setBoolPref(DEP_PREF_ID, false);
+ await settingChanged;
+
+ ok(!setting.visible, "Setting is not visible based on dep");
+ ok(control.hidden, "The control is now hidden");
+ });
+
+ add_task(async function testSettingDisabled() {
+ const SETTING = "setting-control-disabled";
+ let settingDisabled = false;
+ Preferences.addSetting({
+ id: SETTING,
+ disabled: () => settingDisabled,
+ });
+ let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
+ let setting = Preferences.getSetting(SETTING);
+ let control = await renderTemplate(itemConfig, setting);
+ ok(!control.controlEl.disabled, "Setting is enabled");
+
+ // Fake that something changed and the setting should be disabled
+ settingDisabled = true;
+ setting.emit("change");
+ await control.updateComplete;
+
+ ok(control.controlEl.disabled, "Setting is disabled after change");
+ });
+
+ add_task(async function testSettingNotDefined() {
+ const SETTING = "setting-control-not-defined";
+ let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
+ let setting = Preferences.getSetting(SETTING);
+ try {
+ await renderTemplate(itemConfig, setting);
+ ok(false, "Should throw when setting isn't defined");
+ } catch (e) {
+ let control =
+ testHelpers.renderTarget.querySelector("setting-control");
+ ok(control, "setting-control is rendered");
+ is(control.children.length, 0, "setting-control has no children");
+ let SettingControl = customElements.get("setting-control");
+ is(
+ e.constructor,
+ SettingControl.SettingNotDefinedError,
+ "We got an exception"
+ );
+ }
+
+ Preferences.addSetting({ id: SETTING });
+ let control = await renderTemplate(itemConfig, setting);
+ is(
+ control.firstElementChild.localName,
+ "moz-checkbox",
+ "Rendered with a setting"
+ );
+ });
+
+ add_task(async function testTabIndex() {
+ const PREF = "test.setting-control.tabindex";
+ const SETTING = "setting-control-tabindex";
+ await SpecialPowers.pushPrefEnv({
+ set: [[PREF, true]],
+ });
+ Preferences.addAll([{ id: PREF, type: "bool" }]);
+ Preferences.addSetting({
+ id: SETTING,
+ pref: PREF,
+ });
+ let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
+ let control = await renderTemplate(itemConfig);
+
+ // Create an element to help with testing keyboard interactions.
+ let focusTrap = document.createElement("button");
+ focusTrap.textContent = "before";
+ control.prepend(focusTrap);
+
+ ok(
+ !control.getAttribute("tabindex"),
+ "tabindex is not set on the setting-control initially."
+ );
+ ok(
+ !control.controlEl.getAttribute("tabindex"),
+ "tabindex is not set on the inner control element initially."
+ );
+ isnot(
+ document.activeElement,
+ control.controlEl,
+ "The control is not focused initially."
+ );
+
+ focusTrap.focus();
+ synthesizeKey("KEY_Tab", {});
+
+ is(
+ document.activeElement,
+ control.controlEl,
+ "The control element receives focus via keyboard interaction."
+ );
+
+ // Restore focus to the button.
+ focusTrap.focus();
+
+ control.setAttribute("tabindex", "-1");
+ await control.updateComplete;
+
+ is(
+ control.tabIndex,
+ -1,
+ "tabIndex property gets set on the setting-control."
+ );
+ is(
+ control.controlEl.getAttribute("tabindex"),
+ "-1",
+ "tabindex gets propagated to the control el."
+ );
+
+ synthesizeKey("KEY_Tab", {});
+ isnot(
+ document.activeElement,
+ control.controlEl,
+ "The control element no longer receives focus via keyboard interaction."
+ );
+ });
+ </script>
+ </head>
+ <body>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test"></pre>
+ </body>
+</html>
diff --git a/browser/components/preferences/tests/chrome/test_setting_control_checkbox.html b/browser/components/preferences/tests/chrome/test_setting_control_checkbox.html
@@ -1,514 +0,0 @@
-<!doctype html>
-<html>
- <head>
- <meta charset="utf-8" />
- <title>setting-control test</title>
- <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link
- rel="stylesheet"
- href="chrome://mochikit/content/tests/SimpleTest/test.css"
- />
- <link rel="stylesheet" href="chrome://global/skin/global.css" />
- <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
- <script src="../../../../../toolkit/content/tests/widgets/lit-test-helpers.js"></script>
- <script src="./head.js"></script>
- <script
- type="module"
- src="chrome://browser/content/preferences/widgets/setting-group.mjs"
- ></script>
- <script
- type="module"
- src="chrome://browser/content/preferences/widgets/setting-control.mjs"
- ></script>
- <script
- type="module"
- src="chrome://global/content/elements/moz-support-link.mjs"
- ></script>
- <script
- type="application/javascript"
- src="chrome://global/content/preferencesBindings.js"
- ></script>
- <script>
- /* import-globals-from /toolkit/content/preferencesBindings.js */
- let html, testHelpers;
-
- const LABEL_L10N_ID = "browsing-use-autoscroll";
- const GROUP_L10N_ID = "pane-experimental-reset";
-
- async function renderTemplate(itemConfig) {
- let config = {
- items: [itemConfig],
- };
- let result = await testHelpers.renderTemplate(html`
- <setting-group
- .config=${config}
- .getSetting=${(...args) => Preferences.getSetting(...args)}
- ></setting-group>
- `);
- await result.firstElementChild.updateComplete;
- return result.querySelector("setting-control");
- }
-
- function waitForSettingChange(setting) {
- return new Promise(resolve => {
- setting.on("change", function handler() {
- setting.off("change", handler);
- resolve();
- });
- });
- }
-
- add_setup(async function setup() {
- testHelpers = new InputTestHelpers();
- ({ html } = await testHelpers.setupLit());
- testHelpers.setupTests({
- templateFn: () => html`<setting-group></setting-group>`,
- });
- MozXULElement.insertFTLIfNeeded("branding/brand.ftl");
- MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl");
- });
-
- add_task(async function testSimpleCheckbox() {
- const PREF = "test.setting-control.one";
- const SETTING = "setting-control-one";
- await SpecialPowers.pushPrefEnv({
- set: [[PREF, true]],
- });
- Preferences.addAll([{ id: PREF, type: "bool" }]);
- Preferences.addSetting({
- id: SETTING,
- pref: PREF,
- });
- let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
- let setting = Preferences.getSetting(SETTING);
- let control = await renderTemplate(itemConfig);
- is(
- control.controlEl.localName,
- "moz-checkbox",
- "The control rendered a checkbox"
- );
- is(control.controlEl.dataset.l10nId, LABEL_L10N_ID, "Label is set");
- is(control.controlEl.checked, true, "checkbox is checked");
- is(control.controlEl.disabled, false, "checkbox is enabled");
- is(Services.prefs.getBoolPref(PREF), true, "pref is true");
-
- let settingChanged = waitForSettingChange(setting);
- synthesizeMouseAtCenter(control.controlEl, {});
- await settingChanged;
- is(
- control.controlEl.checked,
- false,
- "checkbox becomes unchecked after click"
- );
- is(Services.prefs.getBoolPref(PREF), false, "pref is false");
-
- settingChanged = waitForSettingChange(setting);
- Services.prefs.setBoolPref(PREF, true);
- await settingChanged;
- is(
- control.controlEl.checked,
- true,
- "checkbox becomes checked after pref change"
- );
- is(Services.prefs.getBoolPref(PREF), true, "pref is true");
-
- // Pref locking
- settingChanged = waitForSettingChange(setting);
- Services.prefs.lockPref(PREF);
- await settingChanged;
- is(
- control.controlEl.disabled,
- true,
- "checkbox is disabled when locked"
- );
-
- settingChanged = waitForSettingChange(setting);
- Services.prefs.unlockPref(PREF);
- await settingChanged;
- is(
- control.controlEl.disabled,
- false,
- "checkbox is enabled when unlocked"
- );
- });
-
- add_task(async function testSettingSameControlValue() {
- const SETTING = "setting-control-same-value";
- Preferences.addSetting({
- id: SETTING,
- get: () => false,
- set: () => false,
- });
- let itemConfig = {
- l10nId: LABEL_L10N_ID,
- id: SETTING,
- };
- let setting = Preferences.getSetting(SETTING);
- let control = await renderTemplate(itemConfig);
- ok(control, "Got a control");
- let checkbox = control.controlEl;
- is(checkbox.localName, "moz-checkbox", "moz-checkbox is rendered");
- is(checkbox.checked, false, "checkbox is unchecked on initial render");
-
- let settingChanged = waitForSettingChange(setting);
- synthesizeMouseAtCenter(checkbox, {});
- setting.emit("change");
- await settingChanged;
- is(checkbox.checked, false, "checkbox stays unchecked after click");
- });
-
- add_task(async function testSupportLinkCheckbox() {
- const SETTING = "setting-control-support-link";
- Preferences.addSetting({
- id: SETTING,
- get: () => true,
- });
- let itemConfig = {
- l10nId: LABEL_L10N_ID,
- id: SETTING,
- supportPage: "foo",
- };
- let control = await renderTemplate(
- itemConfig,
- Preferences.getSetting(SETTING)
- );
- ok(control, "Got a control");
- let checkbox = control.controlEl;
- is(checkbox.localName, "moz-checkbox", "moz-checkbox is rendered");
- is(
- checkbox.supportPage,
- "foo",
- "The checkbox receives the supportPage"
- );
- });
-
- add_task(async function testCommonControlProperties() {
- const SETTING = "setting-common-props";
- Preferences.addSetting({
- id: SETTING,
- get: () => true,
- });
-
- await testCommonSettingControlProperties(async commonConfig => {
- const control = await renderTemplate({
- id: SETTING,
- ...commonConfig,
- });
- return control.querySelector("moz-checkbox");
- });
- });
-
- add_task(async function testSupportLinkSubcategory() {
- const SETTING = "setting-control-subcategory";
- Preferences.addSetting({
- id: SETTING,
- get: () => true,
- });
-
- let configOne = {
- l10nId: LABEL_L10N_ID,
- id: SETTING,
- subcategory: "exsubcategory",
- };
- let control = await renderTemplate(
- configOne,
- Preferences.getSetting(SETTING)
- );
- ok(control, "Got the control");
- is(
- control.controlEl.dataset.subcategory,
- "exsubcategory",
- "Subcategory is set"
- );
-
- let configTwo = {
- l10nId: LABEL_L10N_ID,
- id: SETTING,
- subcategory: "exsubcategory2",
- supportPage: "foo",
- };
- control = await renderTemplate(
- configTwo,
- Preferences.getSetting(SETTING)
- );
- ok(control, "Got the control");
- is(
- control.controlEl.dataset.subcategory,
- "exsubcategory2",
- "Subcategory is set"
- );
-
- is(control.controlEl.supportPage, "foo", "Input got the supportPage");
- });
-
- add_task(async function testNestedCheckboxes() {
- const PREF_PARENT = "test.setting-control.parent";
- const SETTING_PARENT = "setting-control-parent";
- const PREF_NESTED = "test.setting-control.nested";
- const SETTING_NESTED = "setting-control-nested";
- await SpecialPowers.pushPrefEnv({
- set: [
- [PREF_PARENT, false],
- [PREF_NESTED, true],
- ],
- });
- Preferences.addAll([
- { id: PREF_PARENT, type: "bool" },
- { id: PREF_NESTED, type: "bool" },
- ]);
- Preferences.addSetting({
- id: SETTING_PARENT,
- pref: PREF_PARENT,
- });
- Preferences.addSetting({
- id: SETTING_NESTED,
- pref: PREF_NESTED,
- });
- let itemConfig = {
- l10nId: LABEL_L10N_ID,
- id: SETTING_PARENT,
- items: [{ l10nId: LABEL_L10N_ID, id: SETTING_NESTED }],
- };
- let parentSetting = Preferences.getSetting(SETTING_PARENT);
- let parentControl = await renderTemplate(itemConfig, parentSetting);
- is(
- parentControl.setting.id,
- SETTING_PARENT,
- "Parent control id is set"
- );
- let nestedControl = parentControl.controlEl.firstElementChild;
- info("Nested: " + nestedControl.localName);
- is(
- nestedControl.setting.id,
- SETTING_NESTED,
- "Nested control id is set"
- );
- is(parentControl.controlEl.checked, false, "Parent is unchecked");
- is(
- parentControl.controlEl.inputEl.disabled,
- false,
- "Parent is enabled"
- );
- is(nestedControl.controlEl.checked, true, "Nested is checked");
- is(
- nestedControl.controlEl.inputEl.disabled,
- true,
- "Nested is disabled"
- );
-
- let settingChanged = waitForSettingChange(parentSetting);
- // Click the label since the center of the entire <moz-checkbox> would
- // be the space between the parent and nested checkboxes.
- synthesizeMouseAtCenter(parentControl.controlEl.labelEl, {});
- await settingChanged;
- await parentControl.updateComplete;
-
- is(
- parentControl.controlEl.checked,
- true,
- "Parent is checked after click"
- );
- is(
- parentControl.controlEl.inputEl.disabled,
- false,
- "Parent is enabled after click"
- );
- is(
- nestedControl.controlEl.checked,
- true,
- "Nested is checked after click"
- );
- is(
- nestedControl.controlEl.inputEl.disabled,
- false,
- "Nested is enabled after click"
- );
-
- settingChanged = waitForSettingChange(parentSetting);
- Services.prefs.setBoolPref(PREF_PARENT, false);
- await settingChanged;
- await parentControl.updateComplete;
-
- is(
- parentControl.controlEl.checked,
- false,
- "Parent is unchecked after pref change"
- );
- is(
- parentControl.controlEl.inputEl.disabled,
- false,
- "Parent is enabled after pref change"
- );
- is(
- nestedControl.controlEl.checked,
- true,
- "Nested is checked after pref change"
- );
- is(
- nestedControl.controlEl.inputEl.disabled,
- true,
- "Nested is disabled after pref change"
- );
- });
-
- add_task(async function testDepsChangeVisibility() {
- const DEP_PREF_ID = "test.depsChange.dep";
- const DEP_SETTING_ID = "testDepsChangeDep";
- await SpecialPowers.pushPrefEnv({
- set: [[DEP_PREF_ID, true]],
- });
- Preferences.add({ id: DEP_PREF_ID, type: "bool" });
- Preferences.addSetting({
- id: DEP_SETTING_ID,
- pref: DEP_PREF_ID,
- });
-
- const PARENT_SETTING_ID = "testDepsChangeParent";
- Preferences.addSetting({
- id: PARENT_SETTING_ID,
- deps: [DEP_SETTING_ID],
- visible: deps => deps[DEP_SETTING_ID].value,
- });
-
- let itemConfig = { l10nId: LABEL_L10N_ID, id: PARENT_SETTING_ID };
- let setting = Preferences.getSetting(PARENT_SETTING_ID);
- let control = await renderTemplate(itemConfig, setting);
- is(
- control.controlEl.localName,
- "moz-checkbox",
- "The control rendered a checkbox"
- );
- ok(!control.hidden, "The control is visible");
- ok(setting.visible, "Setting is visible initially");
-
- let settingChanged = waitForSettingChange(setting);
- Services.prefs.setBoolPref(DEP_PREF_ID, false);
- await settingChanged;
-
- ok(!setting.visible, "Setting is not visible based on dep");
- ok(control.hidden, "The control is now hidden");
- });
-
- add_task(async function testSettingDisabled() {
- const SETTING = "setting-control-disabled";
- let settingDisabled = false;
- Preferences.addSetting({
- id: SETTING,
- disabled: () => settingDisabled,
- });
- let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
- let setting = Preferences.getSetting(SETTING);
- let control = await renderTemplate(itemConfig, setting);
- ok(!control.controlEl.disabled, "Setting is enabled");
-
- // Fake that something changed and the setting should be disabled
- settingDisabled = true;
- setting.emit("change");
- await control.updateComplete;
-
- ok(control.controlEl.disabled, "Setting is disabled after change");
- });
-
- add_task(async function testSettingNotDefined() {
- const SETTING = "setting-control-not-defined";
- let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
- let setting = Preferences.getSetting(SETTING);
- try {
- await renderTemplate(itemConfig, setting);
- ok(false, "Should throw when setting isn't defined");
- } catch (e) {
- let control =
- testHelpers.renderTarget.querySelector("setting-control");
- ok(control, "setting-control is rendered");
- is(control.children.length, 0, "setting-control has no children");
- let SettingControl = customElements.get("setting-control");
- is(
- e.constructor,
- SettingControl.SettingNotDefinedError,
- "We got an exception"
- );
- }
-
- Preferences.addSetting({ id: SETTING });
- let control = await renderTemplate(itemConfig, setting);
- is(
- control.firstElementChild.localName,
- "moz-checkbox",
- "Rendered with a setting"
- );
- });
-
- add_task(async function testTabIndex() {
- const PREF = "test.setting-control.tabindex";
- const SETTING = "setting-control-tabindex";
- await SpecialPowers.pushPrefEnv({
- set: [[PREF, true]],
- });
- Preferences.addAll([{ id: PREF, type: "bool" }]);
- Preferences.addSetting({
- id: SETTING,
- pref: PREF,
- });
- let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
- let control = await renderTemplate(itemConfig);
-
- // Create an element to help with testing keyboard interactions.
- let focusTrap = document.createElement("button");
- focusTrap.textContent = "before";
- control.prepend(focusTrap);
-
- ok(
- !control.getAttribute("tabindex"),
- "tabindex is not set on the setting-control initially."
- );
- ok(
- !control.controlEl.getAttribute("tabindex"),
- "tabindex is not set on the inner control element initially."
- );
- isnot(
- document.activeElement,
- control.controlEl,
- "The control is not focused initially."
- );
-
- focusTrap.focus();
- synthesizeKey("KEY_Tab", {});
-
- is(
- document.activeElement,
- control.controlEl,
- "The control element receives focus via keyboard interaction."
- );
-
- // Restore focus to the button.
- focusTrap.focus();
-
- control.setAttribute("tabindex", "-1");
- await control.updateComplete;
-
- is(
- control.tabIndex,
- -1,
- "tabIndex property gets set on the setting-control."
- );
- is(
- control.controlEl.getAttribute("tabindex"),
- "-1",
- "tabindex gets propagated to the control el."
- );
-
- synthesizeKey("KEY_Tab", {});
- isnot(
- document.activeElement,
- control.controlEl,
- "The control element no longer receives focus via keyboard interaction."
- );
- });
- </script>
- </head>
- <body>
- <p id="display"></p>
- <div id="content" style="display: none"></div>
- <pre id="test"></pre>
- </body>
-</html>
diff --git a/browser/components/preferences/widgets/setting-group/setting-group.mjs b/browser/components/preferences/widgets/setting-group/setting-group.mjs
@@ -118,6 +118,7 @@ export class SettingGroup extends SettingElement {
return html`<moz-fieldset
.headingLevel=${this.config.headingLevel}
@change=${this.onChange}
+ @toggle=${this.onChange}
@click=${this.onClick}
@visibility-change=${this.handleVisibilityChange}
${spread(this.getCommonPropertyMapping(this.config))}