tor-browser

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

test_setting_control.html (20511B)


      1 <!doctype html>
      2 <html>
      3  <head>
      4    <meta charset="utf-8" />
      5    <title>setting-control test</title>
      6    <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
      7    <link
      8      rel="stylesheet"
      9      href="chrome://mochikit/content/tests/SimpleTest/test.css"
     10    />
     11    <link rel="stylesheet" href="chrome://global/skin/global.css" />
     12    <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
     13    <script src="../../../../../toolkit/content/tests/widgets/lit-test-helpers.js"></script>
     14    <script src="./head.js"></script>
     15    <script
     16      type="module"
     17      src="chrome://browser/content/preferences/widgets/setting-group.mjs"
     18    ></script>
     19    <script
     20      type="module"
     21      src="chrome://browser/content/preferences/widgets/setting-control.mjs"
     22    ></script>
     23    <script
     24      type="module"
     25      src="chrome://global/content/elements/moz-support-link.mjs"
     26    ></script>
     27    <script
     28      type="application/javascript"
     29      src="chrome://global/content/preferencesBindings.js"
     30    ></script>
     31    <script>
     32      /* import-globals-from /toolkit/content/preferencesBindings.js */
     33      let html, testHelpers;
     34 
     35      const LABEL_L10N_ID = "browsing-use-autoscroll";
     36      const GROUP_L10N_ID = "pane-experimental-reset";
     37 
     38      async function renderTemplate(itemConfig) {
     39        let config = {
     40          items: [itemConfig],
     41        };
     42        let result = await testHelpers.renderTemplate(html`
     43          <setting-group
     44            .config=${config}
     45            .getSetting=${(...args) => Preferences.getSetting(...args)}
     46          ></setting-group>
     47        `);
     48        await result.firstElementChild.updateComplete;
     49        return result.querySelector("setting-control");
     50      }
     51 
     52      add_setup(async function setup() {
     53        const mockL10nSource = L10nFileSource.createMock(
     54          "test",
     55          "app",
     56          ["en-US"],
     57          "/localization/{locale}/",
     58          [
     59            {
     60              path: "/localization/en-US/mock.ftl",
     61              source: "l10n-test-id =\n .label = Test label",
     62            },
     63          ]
     64        );
     65        L10nRegistry.getInstance().registerSources([mockL10nSource]);
     66        MozXULElement.insertFTLIfNeeded("mock.ftl");
     67        SimpleTest.registerCleanupFunction(() => {
     68          L10nRegistry.getInstance().removeSources([mockL10nSource.name]);
     69        });
     70        testHelpers = new InputTestHelpers();
     71        ({ html } = await testHelpers.setupLit());
     72        testHelpers.setupTests({
     73          templateFn: () => html`<setting-group></setting-group>`,
     74        });
     75        MozXULElement.insertFTLIfNeeded("branding/brand.ftl");
     76        MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl");
     77      });
     78 
     79      add_task(async function testSimpleCheckbox() {
     80        const PREF = "test.setting-control.one";
     81        const SETTING = "setting-control-one";
     82        await SpecialPowers.pushPrefEnv({
     83          set: [[PREF, true]],
     84        });
     85        Preferences.addAll([{ id: PREF, type: "bool" }]);
     86        Preferences.addSetting({
     87          id: SETTING,
     88          pref: PREF,
     89        });
     90        let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
     91        let setting = Preferences.getSetting(SETTING);
     92        let control = await renderTemplate(itemConfig);
     93        is(
     94          control.controlEl.localName,
     95          "moz-checkbox",
     96          "The control rendered a checkbox"
     97        );
     98        is(control.controlEl.dataset.l10nId, LABEL_L10N_ID, "Label is set");
     99        is(control.controlEl.checked, true, "checkbox is checked");
    100        is(control.controlEl.disabled, false, "checkbox is enabled");
    101        is(Services.prefs.getBoolPref(PREF), true, "pref is true");
    102 
    103        let settingChanged = waitForSettingChange(setting);
    104        synthesizeMouseAtCenter(control.controlEl, {});
    105        await settingChanged;
    106        is(
    107          control.controlEl.checked,
    108          false,
    109          "checkbox becomes unchecked after click"
    110        );
    111        is(Services.prefs.getBoolPref(PREF), false, "pref is false");
    112 
    113        settingChanged = waitForSettingChange(setting);
    114        Services.prefs.setBoolPref(PREF, true);
    115        await settingChanged;
    116        is(
    117          control.controlEl.checked,
    118          true,
    119          "checkbox becomes checked after pref change"
    120        );
    121        is(Services.prefs.getBoolPref(PREF), true, "pref is true");
    122 
    123        // Pref locking
    124        settingChanged = waitForSettingChange(setting);
    125        Services.prefs.lockPref(PREF);
    126        await settingChanged;
    127        is(
    128          control.controlEl.disabled,
    129          true,
    130          "checkbox is disabled when locked"
    131        );
    132 
    133        settingChanged = waitForSettingChange(setting);
    134        Services.prefs.unlockPref(PREF);
    135        await settingChanged;
    136        is(
    137          control.controlEl.disabled,
    138          false,
    139          "checkbox is enabled when unlocked"
    140        );
    141      });
    142 
    143      add_task(async function testSimpleToggle() {
    144        const PREF = "test.setting-control.toggle";
    145        const SETTING = "setting-control-toggle";
    146        await SpecialPowers.pushPrefEnv({
    147          set: [[PREF, true]],
    148        });
    149        Preferences.addAll([{ id: PREF, type: "bool" }]);
    150        Preferences.addSetting({
    151          id: SETTING,
    152          pref: PREF,
    153        });
    154        let itemConfig = {
    155          l10nId: LABEL_L10N_ID,
    156          id: SETTING,
    157          control: "moz-toggle",
    158        };
    159        let setting = Preferences.getSetting(SETTING);
    160        let control = await renderTemplate(itemConfig);
    161 
    162        is(
    163          control.controlEl.localName,
    164          "moz-toggle",
    165          "The control rendered a toggle"
    166        );
    167        is(control.controlEl.dataset.l10nId, LABEL_L10N_ID, "Label is set");
    168        is(control.controlEl.pressed, true, "toggle is pressed");
    169        is(control.controlEl.disabled, false, "toggle is enabled");
    170        is(Services.prefs.getBoolPref(PREF), true, "pref is true");
    171 
    172        let settingChanged = waitForSettingChange(setting);
    173        synthesizeMouseAtCenter(control.controlEl, {});
    174        await settingChanged;
    175 
    176        is(
    177          control.controlEl.pressed,
    178          false,
    179          "toggle becomes unchecked after click"
    180        );
    181        is(Services.prefs.getBoolPref(PREF), false, "pref is false");
    182 
    183        settingChanged = waitForSettingChange(setting);
    184        Services.prefs.setBoolPref(PREF, true);
    185        await settingChanged;
    186 
    187        is(
    188          control.controlEl.pressed,
    189          true,
    190          "toggle becomes pressed after pref change"
    191        );
    192        is(Services.prefs.getBoolPref(PREF), true, "pref is true");
    193      });
    194 
    195      add_task(async function testSettingSameControlValue() {
    196        const SETTING = "setting-control-same-value";
    197        Preferences.addSetting({
    198          id: SETTING,
    199          get: () => false,
    200          set: () => false,
    201        });
    202        let itemConfig = {
    203          l10nId: LABEL_L10N_ID,
    204          id: SETTING,
    205        };
    206        let setting = Preferences.getSetting(SETTING);
    207        let control = await renderTemplate(itemConfig);
    208        ok(control, "Got a control");
    209        let checkbox = control.controlEl;
    210        is(checkbox.localName, "moz-checkbox", "moz-checkbox is rendered");
    211        is(checkbox.checked, false, "checkbox is unchecked on initial render");
    212 
    213        let settingChanged = waitForSettingChange(setting);
    214        synthesizeMouseAtCenter(checkbox, {});
    215        setting.emit("change");
    216        await settingChanged;
    217        is(checkbox.checked, false, "checkbox stays unchecked after click");
    218      });
    219 
    220      add_task(async function testSupportLinkCheckbox() {
    221        const SETTING = "setting-control-support-link";
    222        Preferences.addSetting({
    223          id: SETTING,
    224          get: () => true,
    225        });
    226        let itemConfig = {
    227          l10nId: LABEL_L10N_ID,
    228          id: SETTING,
    229          supportPage: "foo",
    230        };
    231        let control = await renderTemplate(
    232          itemConfig,
    233          Preferences.getSetting(SETTING)
    234        );
    235        ok(control, "Got a control");
    236        let checkbox = control.controlEl;
    237        is(checkbox.localName, "moz-checkbox", "moz-checkbox is rendered");
    238        is(
    239          checkbox.supportPage,
    240          "foo",
    241          "The checkbox receives the supportPage"
    242        );
    243      });
    244 
    245      add_task(async function testCommonControlProperties() {
    246        const SETTING = "setting-common-props";
    247        Preferences.addSetting({
    248          id: SETTING,
    249          get: () => true,
    250        });
    251 
    252        await testCommonSettingControlProperties(async commonConfig => {
    253          const control = await renderTemplate({
    254            id: SETTING,
    255            ...commonConfig,
    256          });
    257          return control.querySelector("moz-checkbox");
    258        });
    259      });
    260 
    261      add_task(async function testSupportLinkSubcategory() {
    262        const SETTING = "setting-control-subcategory";
    263        Preferences.addSetting({
    264          id: SETTING,
    265          get: () => true,
    266        });
    267 
    268        let configOne = {
    269          l10nId: LABEL_L10N_ID,
    270          id: SETTING,
    271          subcategory: "exsubcategory",
    272        };
    273        let control = await renderTemplate(
    274          configOne,
    275          Preferences.getSetting(SETTING)
    276        );
    277        ok(control, "Got the control");
    278        is(
    279          control.controlEl.dataset.subcategory,
    280          "exsubcategory",
    281          "Subcategory is set"
    282        );
    283 
    284        let configTwo = {
    285          l10nId: LABEL_L10N_ID,
    286          id: SETTING,
    287          subcategory: "exsubcategory2",
    288          supportPage: "foo",
    289        };
    290        control = await renderTemplate(
    291          configTwo,
    292          Preferences.getSetting(SETTING)
    293        );
    294        ok(control, "Got the control");
    295        is(
    296          control.controlEl.dataset.subcategory,
    297          "exsubcategory2",
    298          "Subcategory is set"
    299        );
    300 
    301        is(control.controlEl.supportPage, "foo", "Input got the supportPage");
    302      });
    303 
    304      add_task(async function testNestedCheckboxes() {
    305        const PREF_PARENT = "test.setting-control.parent";
    306        const SETTING_PARENT = "setting-control-parent";
    307        const PREF_NESTED = "test.setting-control.nested";
    308        const SETTING_NESTED = "setting-control-nested";
    309        await SpecialPowers.pushPrefEnv({
    310          set: [
    311            [PREF_PARENT, false],
    312            [PREF_NESTED, true],
    313          ],
    314        });
    315        Preferences.addAll([
    316          { id: PREF_PARENT, type: "bool" },
    317          { id: PREF_NESTED, type: "bool" },
    318        ]);
    319        Preferences.addSetting({
    320          id: SETTING_PARENT,
    321          pref: PREF_PARENT,
    322        });
    323        Preferences.addSetting({
    324          id: SETTING_NESTED,
    325          pref: PREF_NESTED,
    326        });
    327        let itemConfig = {
    328          l10nId: LABEL_L10N_ID,
    329          id: SETTING_PARENT,
    330          items: [{ l10nId: LABEL_L10N_ID, id: SETTING_NESTED }],
    331        };
    332        let parentSetting = Preferences.getSetting(SETTING_PARENT);
    333        let parentControl = await renderTemplate(itemConfig, parentSetting);
    334        is(
    335          parentControl.setting.id,
    336          SETTING_PARENT,
    337          "Parent control id is set"
    338        );
    339        let nestedControl = parentControl.controlEl.firstElementChild;
    340        info("Nested: " + nestedControl.localName);
    341        is(
    342          nestedControl.setting.id,
    343          SETTING_NESTED,
    344          "Nested control id is set"
    345        );
    346        is(parentControl.controlEl.checked, false, "Parent is unchecked");
    347        is(
    348          parentControl.controlEl.inputEl.disabled,
    349          false,
    350          "Parent is enabled"
    351        );
    352        is(nestedControl.controlEl.checked, true, "Nested is checked");
    353        is(
    354          nestedControl.controlEl.inputEl.disabled,
    355          true,
    356          "Nested is disabled"
    357        );
    358 
    359        let settingChanged = waitForSettingChange(parentSetting);
    360        // Click the label since the center of the entire <moz-checkbox> would
    361        // be the space between the parent and nested checkboxes.
    362        synthesizeMouseAtCenter(parentControl.controlEl.labelEl, {});
    363        await settingChanged;
    364        await parentControl.updateComplete;
    365 
    366        is(
    367          parentControl.controlEl.checked,
    368          true,
    369          "Parent is checked after click"
    370        );
    371        is(
    372          parentControl.controlEl.inputEl.disabled,
    373          false,
    374          "Parent is enabled after click"
    375        );
    376        is(
    377          nestedControl.controlEl.checked,
    378          true,
    379          "Nested is checked after click"
    380        );
    381        is(
    382          nestedControl.controlEl.inputEl.disabled,
    383          false,
    384          "Nested is enabled after click"
    385        );
    386 
    387        settingChanged = waitForSettingChange(parentSetting);
    388        Services.prefs.setBoolPref(PREF_PARENT, false);
    389        await settingChanged;
    390        await parentControl.updateComplete;
    391 
    392        is(
    393          parentControl.controlEl.checked,
    394          false,
    395          "Parent is unchecked after pref change"
    396        );
    397        is(
    398          parentControl.controlEl.inputEl.disabled,
    399          false,
    400          "Parent is enabled after pref change"
    401        );
    402        is(
    403          nestedControl.controlEl.checked,
    404          true,
    405          "Nested is checked after pref change"
    406        );
    407        is(
    408          nestedControl.controlEl.inputEl.disabled,
    409          true,
    410          "Nested is disabled after pref change"
    411        );
    412      });
    413 
    414      add_task(async function testDepsChangeVisibility() {
    415        const DEP_PREF_ID = "test.depsChange.dep";
    416        const DEP_SETTING_ID = "testDepsChangeDep";
    417        await SpecialPowers.pushPrefEnv({
    418          set: [[DEP_PREF_ID, true]],
    419        });
    420        Preferences.add({ id: DEP_PREF_ID, type: "bool" });
    421        Preferences.addSetting({
    422          id: DEP_SETTING_ID,
    423          pref: DEP_PREF_ID,
    424        });
    425 
    426        const PARENT_SETTING_ID = "testDepsChangeParent";
    427        Preferences.addSetting({
    428          id: PARENT_SETTING_ID,
    429          deps: [DEP_SETTING_ID],
    430          visible: deps => deps[DEP_SETTING_ID].value,
    431        });
    432 
    433        let itemConfig = { l10nId: LABEL_L10N_ID, id: PARENT_SETTING_ID };
    434        let setting = Preferences.getSetting(PARENT_SETTING_ID);
    435        let control = await renderTemplate(itemConfig, setting);
    436        is(
    437          control.controlEl.localName,
    438          "moz-checkbox",
    439          "The control rendered a checkbox"
    440        );
    441        ok(!control.hidden, "The control is visible");
    442        ok(setting.visible, "Setting is visible initially");
    443 
    444        let settingChanged = waitForSettingChange(setting);
    445        Services.prefs.setBoolPref(DEP_PREF_ID, false);
    446        await settingChanged;
    447 
    448        ok(!setting.visible, "Setting is not visible based on dep");
    449        ok(control.hidden, "The control is now hidden");
    450      });
    451 
    452      add_task(async function testSettingDisabled() {
    453        const SETTING = "setting-control-disabled";
    454        let settingDisabled = false;
    455        Preferences.addSetting({
    456          id: SETTING,
    457          disabled: () => settingDisabled,
    458        });
    459        let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
    460        let setting = Preferences.getSetting(SETTING);
    461        let control = await renderTemplate(itemConfig, setting);
    462        ok(!control.controlEl.disabled, "Setting is enabled");
    463 
    464        // Fake that something changed and the setting should be disabled
    465        settingDisabled = true;
    466        setting.emit("change");
    467        await control.updateComplete;
    468 
    469        ok(control.controlEl.disabled, "Setting is disabled after change");
    470      });
    471 
    472      add_task(async function testSettingNotDefined() {
    473        const SETTING = "setting-control-not-defined";
    474        let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
    475        let setting = Preferences.getSetting(SETTING);
    476        try {
    477          await renderTemplate(itemConfig, setting);
    478          ok(false, "Should throw when setting isn't defined");
    479        } catch (e) {
    480          let control =
    481            testHelpers.renderTarget.querySelector("setting-control");
    482          ok(control, "setting-control is rendered");
    483          is(control.children.length, 0, "setting-control has no children");
    484          let SettingControl = customElements.get("setting-control");
    485          is(
    486            e.constructor,
    487            SettingControl.SettingNotDefinedError,
    488            "We got an exception"
    489          );
    490        }
    491 
    492        Preferences.addSetting({ id: SETTING });
    493        let control = await renderTemplate(itemConfig, setting);
    494        is(
    495          control.firstElementChild.localName,
    496          "moz-checkbox",
    497          "Rendered with a setting"
    498        );
    499      });
    500 
    501      add_task(async function testTabIndex() {
    502        const PREF = "test.setting-control.tabindex";
    503        const SETTING = "setting-control-tabindex";
    504        await SpecialPowers.pushPrefEnv({
    505          set: [[PREF, true]],
    506        });
    507        Preferences.addAll([{ id: PREF, type: "bool" }]);
    508        Preferences.addSetting({
    509          id: SETTING,
    510          pref: PREF,
    511        });
    512        let itemConfig = { l10nId: LABEL_L10N_ID, id: SETTING };
    513        let control = await renderTemplate(itemConfig);
    514 
    515        // Create an element to help with testing keyboard interactions.
    516        let focusTrap = document.createElement("button");
    517        focusTrap.textContent = "before";
    518        control.prepend(focusTrap);
    519 
    520        ok(
    521          !control.getAttribute("tabindex"),
    522          "tabindex is not set on the setting-control initially."
    523        );
    524        ok(
    525          !control.controlEl.getAttribute("tabindex"),
    526          "tabindex is not set on the inner control element initially."
    527        );
    528        isnot(
    529          document.activeElement,
    530          control.controlEl,
    531          "The control is not focused initially."
    532        );
    533 
    534        focusTrap.focus();
    535        synthesizeKey("KEY_Tab", {});
    536 
    537        is(
    538          document.activeElement,
    539          control.controlEl,
    540          "The control element receives focus via keyboard interaction."
    541        );
    542 
    543        // Restore focus to the button.
    544        focusTrap.focus();
    545 
    546        control.setAttribute("tabindex", "-1");
    547        await control.updateComplete;
    548 
    549        is(
    550          control.tabIndex,
    551          -1,
    552          "tabIndex property gets set on the setting-control."
    553        );
    554        is(
    555          control.controlEl.getAttribute("tabindex"),
    556          "-1",
    557          "tabindex gets propagated to the control el."
    558        );
    559 
    560        synthesizeKey("KEY_Tab", {});
    561        isnot(
    562          document.activeElement,
    563          control.controlEl,
    564          "The control element no longer receives focus via keyboard interaction."
    565        );
    566      });
    567 
    568      add_task(async function testSettingControlSlot() {
    569        const SETTING_PARENT = "setting-control-slot-parent";
    570        const SETTING_CHILD_ACTION = "setting-control-slot-child-action";
    571 
    572        Preferences.addSetting({ id: SETTING_PARENT });
    573        Preferences.addSetting({ id: SETTING_CHILD_ACTION });
    574 
    575        const itemConfig = {
    576          id: SETTING_PARENT,
    577          l10nId: LABEL_L10N_ID,
    578          control: "moz-box-item",
    579          items: [
    580            {
    581              id: SETTING_CHILD_ACTION,
    582              l10nId: LABEL_L10N_ID,
    583              slot: "actions",
    584            },
    585          ],
    586        };
    587 
    588        const parentSetting = Preferences.getSetting(SETTING_PARENT);
    589        const parentControl = await renderTemplate(itemConfig, parentSetting);
    590 
    591        is(
    592          parentControl.setting.id,
    593          SETTING_PARENT,
    594          "Parent control id is set"
    595        );
    596        ok(parentControl.controlEl, "Parent controlEl exists");
    597 
    598        const nestedControl =
    599          parentControl.controlEl.querySelector("setting-control");
    600 
    601        is(
    602          nestedControl.setting.id,
    603          SETTING_CHILD_ACTION,
    604          "Nested control id is set"
    605        );
    606        ok(nestedControl.controlEl, "Nested controlEl exists");
    607        is(
    608          nestedControl.getAttribute("slot"),
    609          "actions",
    610          "Nested setting-control has expected slot name"
    611        );
    612        is(
    613          parentControl.controlEl.shadowRoot
    614            .querySelector("slot[name='actions']")
    615            .assignedElements()[0],
    616          nestedControl,
    617          "Nested setting-control is slotted in the parent control."
    618        );
    619      });
    620    </script>
    621  </head>
    622  <body>
    623    <p id="display"></p>
    624    <div id="content" style="display: none"></div>
    625    <pre id="test"></pre>
    626  </body>
    627 </html>