tor-browser

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

browser_extension_controlled.js (43714B)


      1 /* eslint-env webextensions */
      2 
      3 const PROXY_PREF = "network.proxy.type";
      4 const HOMEPAGE_URL_PREF = "browser.startup.homepage";
      5 const HOMEPAGE_OVERRIDE_KEY = "homepage_override";
      6 const URL_OVERRIDES_TYPE = "url_overrides";
      7 const NEW_TAB_KEY = "newTabURL";
      8 const PREF_SETTING_TYPE = "prefs";
      9 
     10 ChromeUtils.defineESModuleGetters(this, {
     11  AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs",
     12  ExtensionSettingsStore:
     13    "resource://gre/modules/ExtensionSettingsStore.sys.mjs",
     14 });
     15 
     16 XPCOMUtils.defineLazyPreferenceGetter(this, "proxyType", PROXY_PREF);
     17 
     18 const { AddonTestUtils } = ChromeUtils.importESModule(
     19  "resource://testing-common/AddonTestUtils.sys.mjs"
     20 );
     21 AddonTestUtils.initMochitest(this);
     22 
     23 const { ExtensionPreferencesManager } = ChromeUtils.importESModule(
     24  "resource://gre/modules/ExtensionPreferencesManager.sys.mjs"
     25 );
     26 
     27 const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
     28 const CHROME_URL_ROOT = TEST_DIR + "/";
     29 const PERMISSIONS_URL =
     30  "chrome://browser/content/preferences/dialogs/sitePermissions.xhtml";
     31 let sitePermissionsDialog;
     32 
     33 function getSupportsFile(path) {
     34  let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(
     35    Ci.nsIChromeRegistry
     36  );
     37  let uri = Services.io.newURI(CHROME_URL_ROOT + path);
     38  let fileurl = cr.convertChromeURL(uri);
     39  return fileurl.QueryInterface(Ci.nsIFileURL);
     40 }
     41 
     42 function waitForMessageChange(
     43  element,
     44  cb,
     45  opts = { attributes: true, attributeFilter: ["hidden"] }
     46 ) {
     47  return waitForMutation(element, opts, cb);
     48 }
     49 
     50 function getElement(id, doc = gBrowser.contentDocument) {
     51  return doc.getElementById(id);
     52 }
     53 
     54 function waitForMessageHidden(messageId, doc) {
     55  return waitForMessageChange(
     56    getElement(messageId, doc),
     57    target => target.hidden
     58  );
     59 }
     60 
     61 function waitForMessageShown(messageId, doc) {
     62  return waitForMessageChange(
     63    getElement(messageId, doc),
     64    target => !target.hidden
     65  );
     66 }
     67 
     68 function waitForEnableMessage(messageId, doc) {
     69  return waitForMessageChange(
     70    getElement(messageId, doc),
     71    target => target.classList.contains("extension-controlled-disabled"),
     72    { attributeFilter: ["class"], attributes: true }
     73  );
     74 }
     75 
     76 function waitForMessageContent(messageId, l10nId, doc) {
     77  return waitForMessageChange(
     78    getElement(messageId, doc),
     79    target => doc.l10n.getAttributes(target).id === l10nId,
     80    { childList: true }
     81  );
     82 }
     83 
     84 async function openNotificationsPermissionDialog() {
     85  let dialogOpened = promiseLoadSubDialog(PERMISSIONS_URL);
     86 
     87  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
     88    let doc = content.document;
     89    let settingsButton = doc.getElementById("notificationSettingsButton");
     90    settingsButton.click();
     91  });
     92 
     93  sitePermissionsDialog = await dialogOpened;
     94  await sitePermissionsDialog.document.mozSubdialogReady;
     95 }
     96 
     97 async function disableExtensionViaClick(labelId, disableButtonId, doc) {
     98  let controlledLabel = doc.getElementById(labelId);
     99 
    100  let enableMessageShown = waitForEnableMessage(labelId, doc);
    101  doc.getElementById(disableButtonId).click();
    102  await enableMessageShown;
    103 
    104  let controlledDescription = controlledLabel.querySelector("description");
    105  is(
    106    doc.l10n.getAttributes(controlledDescription.querySelector("label")).id,
    107    "extension-controlled-enable",
    108    "The user is notified of how to enable the extension again."
    109  );
    110 
    111  // The user can dismiss the enable instructions.
    112  let hidden = waitForMessageHidden(labelId, doc);
    113  controlledLabel.querySelector("image:last-of-type").click();
    114  await hidden;
    115 }
    116 
    117 async function reEnableExtension(addon, labelId) {
    118  let controlledMessageShown = waitForMessageShown(labelId);
    119  await addon.enable();
    120  await controlledMessageShown;
    121 }
    122 
    123 add_task(async function testExtensionControlledHomepage() {
    124  const ADDON_ID = "@set_homepage";
    125  const SECOND_ADDON_ID = "@second_set_homepage";
    126 
    127  await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
    128  let homepagePref = () => Services.prefs.getCharPref(HOMEPAGE_URL_PREF);
    129  let originalHomepagePref = homepagePref();
    130  is(
    131    gBrowser.currentURI.spec,
    132    "about:preferences#home",
    133    "#home should be in the URI for about:preferences"
    134  );
    135  let doc = gBrowser.contentDocument;
    136  let homeModeEl = doc.getElementById("homeMode");
    137  let customSettingsSection = doc.getElementById("customSettings");
    138 
    139  is(homeModeEl.itemCount, 3, "The menu list starts with 3 options");
    140 
    141  let promise = TestUtils.waitForCondition(
    142    () => homeModeEl.itemCount === 4,
    143    "wait for the addon option to be added as an option in the menu list"
    144  );
    145  let extension = ExtensionTestUtils.loadExtension({
    146    useAddonManager: "permanent",
    147    manifest: {
    148      version: "1.0",
    149      name: "set_homepage",
    150      browser_specific_settings: {
    151        gecko: {
    152          id: ADDON_ID,
    153        },
    154      },
    155      chrome_settings_overrides: { homepage: "/home.html" },
    156    },
    157  });
    158  await extension.startup();
    159  await promise;
    160 
    161  // The homepage is set to the default and the custom settings section is hidden
    162  is(homeModeEl.disabled, false, "The homepage menulist is enabled");
    163  is(
    164    customSettingsSection.hidden,
    165    true,
    166    "The custom settings element is hidden"
    167  );
    168 
    169  let addon = await AddonManager.getAddonByID(ADDON_ID);
    170  is(
    171    homeModeEl.value,
    172    addon.id,
    173    "the home select menu's value is set to the addon"
    174  );
    175 
    176  promise = TestUtils.waitForPrefChange(HOMEPAGE_URL_PREF);
    177  // Set the Menu to the default value
    178  homeModeEl.value = "0";
    179  homeModeEl.dispatchEvent(new Event("command"));
    180  await promise;
    181  is(homepagePref(), originalHomepagePref, "homepage is set back to default");
    182  let levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
    183    addon.id,
    184    HOMEPAGE_OVERRIDE_KEY,
    185    PREF_SETTING_TYPE
    186  );
    187  is(
    188    levelOfControl,
    189    "not_controllable",
    190    "getLevelOfControl returns not_controllable."
    191  );
    192  let setting = await ExtensionPreferencesManager.getSetting(
    193    HOMEPAGE_OVERRIDE_KEY
    194  );
    195  ok(!setting.value, "the setting is not set.");
    196 
    197  promise = TestUtils.waitForPrefChange(HOMEPAGE_URL_PREF);
    198  // Set the menu to the addon value
    199  homeModeEl.value = ADDON_ID;
    200  homeModeEl.dispatchEvent(new Event("command"));
    201  await promise;
    202  ok(
    203    homepagePref().startsWith("moz-extension") &&
    204      homepagePref().endsWith("home.html"),
    205    "Home url should be provided by the extension."
    206  );
    207  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
    208    addon.id,
    209    HOMEPAGE_OVERRIDE_KEY,
    210    PREF_SETTING_TYPE
    211  );
    212  is(
    213    levelOfControl,
    214    "controlled_by_this_extension",
    215    "getLevelOfControl returns controlled_by_this_extension."
    216  );
    217  setting = await ExtensionPreferencesManager.getSetting(HOMEPAGE_OVERRIDE_KEY);
    218  ok(
    219    setting.value.startsWith("moz-extension") &&
    220      setting.value.endsWith("home.html"),
    221    "The setting value is the same as the extension."
    222  );
    223 
    224  // Add a second extension, ensure it is added to the menulist and selected.
    225  promise = TestUtils.waitForCondition(
    226    () => homeModeEl.itemCount == 5,
    227    "addon option is added as an option in the menu list"
    228  );
    229  let secondExtension = ExtensionTestUtils.loadExtension({
    230    useAddonManager: "permanent",
    231    manifest: {
    232      version: "1.0",
    233      name: "second_set_homepage",
    234      browser_specific_settings: {
    235        gecko: {
    236          id: SECOND_ADDON_ID,
    237        },
    238      },
    239      chrome_settings_overrides: { homepage: "/home2.html" },
    240    },
    241  });
    242  await secondExtension.startup();
    243  await promise;
    244 
    245  let secondAddon = await AddonManager.getAddonByID(SECOND_ADDON_ID);
    246  is(homeModeEl.value, SECOND_ADDON_ID, "home menulist is set to the add-on");
    247 
    248  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
    249    secondAddon.id,
    250    HOMEPAGE_OVERRIDE_KEY,
    251    PREF_SETTING_TYPE
    252  );
    253  is(
    254    levelOfControl,
    255    "controlled_by_this_extension",
    256    "getLevelOfControl returns controlled_by_this_extension."
    257  );
    258  setting = await ExtensionPreferencesManager.getSetting(HOMEPAGE_OVERRIDE_KEY);
    259  ok(
    260    setting.value.startsWith("moz-extension") &&
    261      setting.value.endsWith("home2.html"),
    262    "The setting value is the same as the extension."
    263  );
    264 
    265  promise = TestUtils.waitForCondition(
    266    () => homeModeEl.itemCount == 4,
    267    "addon option is no longer an option in the menu list after disable, even if it was not selected"
    268  );
    269  await addon.disable();
    270  await promise;
    271 
    272  // Ensure that re-enabling an addon adds it back to the menulist
    273  promise = TestUtils.waitForCondition(
    274    () => homeModeEl.itemCount == 5,
    275    "addon option is added again to the menulist when enabled"
    276  );
    277  await addon.enable();
    278  await promise;
    279 
    280  promise = TestUtils.waitForCondition(
    281    () => homeModeEl.itemCount == 4,
    282    "addon option is no longer an option in the menu list after disable"
    283  );
    284  await secondAddon.disable();
    285  await promise;
    286 
    287  promise = TestUtils.waitForCondition(
    288    () => homeModeEl.itemCount == 5,
    289    "addon option is added again to the menulist when enabled"
    290  );
    291  await secondAddon.enable();
    292  await promise;
    293 
    294  promise = TestUtils.waitForCondition(
    295    () => homeModeEl.itemCount == 3,
    296    "addon options are no longer an option in the menu list after disabling all addons"
    297  );
    298  await secondAddon.disable();
    299  await addon.disable();
    300  await promise;
    301 
    302  is(homeModeEl.value, "0", "addon option is not selected in the menu list");
    303 
    304  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
    305    secondAddon.id,
    306    HOMEPAGE_OVERRIDE_KEY,
    307    PREF_SETTING_TYPE
    308  );
    309  is(
    310    levelOfControl,
    311    "controllable_by_this_extension",
    312    "getLevelOfControl returns controllable_by_this_extension."
    313  );
    314  setting = await ExtensionPreferencesManager.getSetting(HOMEPAGE_OVERRIDE_KEY);
    315  ok(!setting.value, "The setting value is back to default.");
    316 
    317  // The homepage elements are reset to their original state.
    318  is(homepagePref(), originalHomepagePref, "homepage is set back to default");
    319  is(homeModeEl.disabled, false, "The homepage menulist is enabled");
    320  BrowserTestUtils.removeTab(gBrowser.selectedTab);
    321  await extension.unload();
    322  await secondExtension.unload();
    323 });
    324 
    325 add_task(async function testPrefLockedHomepage() {
    326  const ADDON_ID = "@set_homepage";
    327  await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
    328  let doc = gBrowser.contentDocument;
    329  is(
    330    gBrowser.currentURI.spec,
    331    "about:preferences#home",
    332    "#home should be in the URI for about:preferences"
    333  );
    334 
    335  let homePagePref = "browser.startup.homepage";
    336  let buttonPrefs = [
    337    "pref.browser.homepage.disable_button.current_page",
    338    "pref.browser.homepage.disable_button.bookmark_page",
    339    "pref.browser.homepage.disable_button.restore_default",
    340  ];
    341  let homeModeEl = doc.getElementById("homeMode");
    342  let homePageInput = doc.getElementById("homePageUrl");
    343  let prefs = Services.prefs.getDefaultBranch(null);
    344  let mutationOpts = { attributes: true, attributeFilter: ["disabled"] };
    345 
    346  // Helper functions.
    347  let getButton = pref =>
    348    doc.querySelector(`.homepage-button[preference="${pref}"`);
    349  let waitForAllMutations = () =>
    350    Promise.all(
    351      buttonPrefs
    352        .map(pref => waitForMutation(getButton(pref), mutationOpts))
    353        .concat([
    354          waitForMutation(homeModeEl, mutationOpts),
    355          waitForMutation(homePageInput, mutationOpts),
    356        ])
    357    );
    358  let getHomepage = () =>
    359    Services.prefs.getCharPref("browser.startup.homepage");
    360 
    361  let originalHomepage = getHomepage();
    362  let extensionHomepage = "https://developer.mozilla.org/";
    363  let lockedHomepage = "http://www.yahoo.com";
    364 
    365  let lockPrefs = () => {
    366    buttonPrefs.forEach(pref => {
    367      prefs.setBoolPref(pref, true);
    368      prefs.lockPref(pref);
    369    });
    370    // Do the homepage last since that's the only pref that triggers a UI update.
    371    prefs.setCharPref(homePagePref, lockedHomepage);
    372    prefs.lockPref(homePagePref);
    373  };
    374  let unlockPrefs = () => {
    375    buttonPrefs.forEach(pref => {
    376      prefs.unlockPref(pref);
    377      prefs.setBoolPref(pref, false);
    378    });
    379    // Do the homepage last since that's the only pref that triggers a UI update.
    380    prefs.unlockPref(homePagePref);
    381    prefs.setCharPref(homePagePref, originalHomepage);
    382  };
    383 
    384  // Lock or unlock prefs then wait for all mutations to finish.
    385  // Expects a bool indicating if we should lock or unlock.
    386  let waitForLockMutations = lock => {
    387    let mutationsDone = waitForAllMutations();
    388    if (lock) {
    389      lockPrefs();
    390    } else {
    391      unlockPrefs();
    392    }
    393    return mutationsDone;
    394  };
    395 
    396  Assert.notEqual(
    397    originalHomepage,
    398    extensionHomepage,
    399    "The extension will change the homepage"
    400  );
    401 
    402  // Install an extension that sets the homepage to MDN.
    403  let promise = TestUtils.waitForPrefChange(HOMEPAGE_URL_PREF);
    404  let extension = ExtensionTestUtils.loadExtension({
    405    useAddonManager: "permanent",
    406    manifest: {
    407      version: "1.0",
    408      name: "set_homepage",
    409      browser_specific_settings: {
    410        gecko: {
    411          id: ADDON_ID,
    412        },
    413      },
    414      chrome_settings_overrides: { homepage: "https://developer.mozilla.org/" },
    415    },
    416  });
    417  await extension.startup();
    418  await promise;
    419 
    420  // Check that everything is still disabled, homepage didn't change.
    421  is(
    422    getHomepage(),
    423    extensionHomepage,
    424    "The reported homepage is set by the extension"
    425  );
    426  is(
    427    homePageInput.value,
    428    extensionHomepage,
    429    "The homepage is set by the extension"
    430  );
    431 
    432  // Lock all of the prefs, wait for the UI to update.
    433  await waitForLockMutations(true);
    434 
    435  // Check that everything is now disabled.
    436  is(getHomepage(), lockedHomepage, "The reported homepage is set by the pref");
    437  is(homePageInput.value, lockedHomepage, "The homepage is set by the pref");
    438  is(
    439    homePageInput.disabled,
    440    true,
    441    "The homepage is disabed when the pref is locked"
    442  );
    443 
    444  buttonPrefs.forEach(pref => {
    445    is(
    446      getButton(pref).disabled,
    447      true,
    448      `The ${pref} button is disabled when locked`
    449    );
    450  });
    451 
    452  let levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
    453    ADDON_ID,
    454    HOMEPAGE_OVERRIDE_KEY,
    455    PREF_SETTING_TYPE
    456  );
    457  is(
    458    levelOfControl,
    459    "not_controllable",
    460    "getLevelOfControl returns not_controllable, the pref is locked."
    461  );
    462 
    463  // Verify that the UI is selecting the extension's Id in the menulist
    464  let unlockedPromise = TestUtils.waitForCondition(
    465    () => homeModeEl.value == ADDON_ID,
    466    "Homepage menulist value is equal to the extension ID"
    467  );
    468  // Unlock the prefs, wait for the UI to update.
    469  unlockPrefs();
    470  await unlockedPromise;
    471 
    472  is(
    473    homeModeEl.disabled,
    474    false,
    475    "the home select element is not disabled when the pref is not locked"
    476  );
    477  is(
    478    homePageInput.disabled,
    479    false,
    480    "The homepage is enabled when the pref is unlocked"
    481  );
    482  is(
    483    getHomepage(),
    484    extensionHomepage,
    485    "The homepage is reset to extension page"
    486  );
    487 
    488  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
    489    ADDON_ID,
    490    HOMEPAGE_OVERRIDE_KEY,
    491    PREF_SETTING_TYPE
    492  );
    493  is(
    494    levelOfControl,
    495    "controlled_by_this_extension",
    496    "getLevelOfControl returns controlled_by_this_extension after prefs are unlocked."
    497  );
    498  let setting = await ExtensionPreferencesManager.getSetting(
    499    HOMEPAGE_OVERRIDE_KEY
    500  );
    501  is(
    502    setting.value,
    503    extensionHomepage,
    504    "The setting value is equal to the extensionHomepage."
    505  );
    506 
    507  // Uninstall the add-on.
    508  promise = TestUtils.waitForPrefChange(HOMEPAGE_URL_PREF);
    509  await extension.unload();
    510  await promise;
    511 
    512  setting = await ExtensionPreferencesManager.getSetting(HOMEPAGE_OVERRIDE_KEY);
    513  ok(!setting, "The setting is gone after the addon is uninstalled.");
    514 
    515  // Check that everything is now enabled again.
    516  is(
    517    getHomepage(),
    518    originalHomepage,
    519    "The reported homepage is reset to original value"
    520  );
    521  is(homePageInput.value, "", "The homepage is empty");
    522  is(
    523    homePageInput.disabled,
    524    false,
    525    "The homepage is enabled after clearing lock"
    526  );
    527  is(
    528    homeModeEl.disabled,
    529    false,
    530    "Homepage menulist is enabled after clearing lock"
    531  );
    532  buttonPrefs.forEach(pref => {
    533    is(
    534      getButton(pref).disabled,
    535      false,
    536      `The ${pref} button is enabled when unlocked`
    537    );
    538  });
    539 
    540  // Lock the prefs without an extension.
    541  await waitForLockMutations(true);
    542 
    543  // Check that everything is now disabled.
    544  is(getHomepage(), lockedHomepage, "The reported homepage is set by the pref");
    545  is(homePageInput.value, lockedHomepage, "The homepage is set by the pref");
    546  is(
    547    homePageInput.disabled,
    548    true,
    549    "The homepage is disabed when the pref is locked"
    550  );
    551  is(
    552    homeModeEl.disabled,
    553    true,
    554    "Homepage menulist is disabled when pref is locked"
    555  );
    556  buttonPrefs.forEach(pref => {
    557    is(
    558      getButton(pref).disabled,
    559      true,
    560      `The ${pref} button is disabled when locked`
    561    );
    562  });
    563 
    564  // Unlock the prefs without an extension.
    565  await waitForLockMutations(false);
    566 
    567  // Check that everything is enabled again.
    568  is(
    569    getHomepage(),
    570    originalHomepage,
    571    "The homepage is reset to the original value"
    572  );
    573  is(homePageInput.value, "", "The homepage is clear after being unlocked");
    574  is(
    575    homePageInput.disabled,
    576    false,
    577    "The homepage is enabled after clearing lock"
    578  );
    579  is(
    580    homeModeEl.disabled,
    581    false,
    582    "Homepage menulist is enabled after clearing lock"
    583  );
    584  buttonPrefs.forEach(pref => {
    585    is(
    586      getButton(pref).disabled,
    587      false,
    588      `The ${pref} button is enabled when unlocked`
    589    );
    590  });
    591 
    592  BrowserTestUtils.removeTab(gBrowser.selectedTab);
    593 });
    594 
    595 add_task(async function testExtensionControlledNewTab() {
    596  const ADDON_ID = "@set_newtab";
    597  const SECOND_ADDON_ID = "@second_set_newtab";
    598  const DEFAULT_NEWTAB = "about:newtab";
    599  const NEWTAB_CONTROLLED_PREF = "browser.newtab.extensionControlled";
    600 
    601  await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
    602  is(
    603    gBrowser.currentURI.spec,
    604    "about:preferences#home",
    605    "#home should be in the URI for about:preferences"
    606  );
    607 
    608  let doc = gBrowser.contentDocument;
    609  let newTabMenuList = doc.getElementById("newTabMode");
    610  // The new tab page is set to the default.
    611  is(AboutNewTab.newTabURL, DEFAULT_NEWTAB, "new tab is set to default");
    612 
    613  let promise = TestUtils.waitForCondition(
    614    () => newTabMenuList.itemCount == 3,
    615    "addon option is added as an option in the menu list"
    616  );
    617  // Install an extension that will set the new tab page.
    618  let extension = ExtensionTestUtils.loadExtension({
    619    useAddonManager: "permanent",
    620    manifest: {
    621      version: "1.0",
    622      name: "set_newtab",
    623      browser_specific_settings: {
    624        gecko: {
    625          id: ADDON_ID,
    626        },
    627      },
    628      chrome_url_overrides: { newtab: "/newtab.html" },
    629    },
    630  });
    631  await extension.startup();
    632 
    633  await promise;
    634  let addon = await AddonManager.getAddonByID(ADDON_ID);
    635 
    636  is(newTabMenuList.value, ADDON_ID, "New tab menulist is set to the add-on");
    637 
    638  let levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
    639    addon.id,
    640    NEW_TAB_KEY,
    641    URL_OVERRIDES_TYPE
    642  );
    643  is(
    644    levelOfControl,
    645    "controlled_by_this_extension",
    646    "getLevelOfControl returns controlled_by_this_extension."
    647  );
    648  let setting = ExtensionSettingsStore.getSetting(
    649    URL_OVERRIDES_TYPE,
    650    NEW_TAB_KEY
    651  );
    652  ok(
    653    setting.value.startsWith("moz-extension") &&
    654      setting.value.endsWith("newtab.html"),
    655    "The url_overrides is set by this extension"
    656  );
    657 
    658  promise = TestUtils.waitForPrefChange(NEWTAB_CONTROLLED_PREF);
    659  // Set the menu to the default value
    660  newTabMenuList.value = "0";
    661  newTabMenuList.dispatchEvent(new Event("command"));
    662  await promise;
    663  let newTabPref = Services.prefs.getBoolPref(NEWTAB_CONTROLLED_PREF, false);
    664  is(newTabPref, false, "the new tab is not controlled");
    665 
    666  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
    667    addon.id,
    668    NEW_TAB_KEY,
    669    URL_OVERRIDES_TYPE
    670  );
    671  is(
    672    levelOfControl,
    673    "not_controllable",
    674    "getLevelOfControl returns not_controllable."
    675  );
    676  setting = ExtensionSettingsStore.getSetting(URL_OVERRIDES_TYPE, NEW_TAB_KEY);
    677  ok(!setting.value, "The url_overrides is not set by this extension");
    678 
    679  promise = TestUtils.waitForPrefChange(NEWTAB_CONTROLLED_PREF);
    680  // Set the menu to a the addon value
    681  newTabMenuList.value = ADDON_ID;
    682  newTabMenuList.dispatchEvent(new Event("command"));
    683  await promise;
    684  newTabPref = Services.prefs.getBoolPref(NEWTAB_CONTROLLED_PREF, false);
    685  is(newTabPref, true, "the new tab is controlled");
    686 
    687  // Add a second extension, ensure it is added to the menulist and selected.
    688  promise = TestUtils.waitForCondition(
    689    () => newTabMenuList.itemCount == 4,
    690    "addon option is added as an option in the menu list"
    691  );
    692  let secondExtension = ExtensionTestUtils.loadExtension({
    693    useAddonManager: "permanent",
    694    manifest: {
    695      version: "1.0",
    696      name: "second_set_newtab",
    697      browser_specific_settings: {
    698        gecko: {
    699          id: SECOND_ADDON_ID,
    700        },
    701      },
    702      chrome_url_overrides: { newtab: "/newtab2.html" },
    703    },
    704  });
    705  await secondExtension.startup();
    706  await promise;
    707  let secondAddon = await AddonManager.getAddonByID(SECOND_ADDON_ID);
    708  is(
    709    newTabMenuList.value,
    710    SECOND_ADDON_ID,
    711    "New tab menulist is set to the add-on"
    712  );
    713 
    714  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
    715    secondAddon.id,
    716    NEW_TAB_KEY,
    717    URL_OVERRIDES_TYPE
    718  );
    719  is(
    720    levelOfControl,
    721    "controlled_by_this_extension",
    722    "getLevelOfControl returns controlled_by_this_extension."
    723  );
    724  setting = ExtensionSettingsStore.getSetting(URL_OVERRIDES_TYPE, NEW_TAB_KEY);
    725  ok(
    726    setting.value.startsWith("moz-extension") &&
    727      setting.value.endsWith("newtab2.html"),
    728    "The url_overrides is set by the second extension"
    729  );
    730 
    731  promise = TestUtils.waitForCondition(
    732    () => newTabMenuList.itemCount == 3,
    733    "addon option is no longer an option in the menu list after disable, even if it was not selected"
    734  );
    735  await addon.disable();
    736  await promise;
    737 
    738  // Ensure that re-enabling an addon adds it back to the menulist
    739  promise = TestUtils.waitForCondition(
    740    () => newTabMenuList.itemCount == 4,
    741    "addon option is added again to the menulist when enabled"
    742  );
    743  await addon.enable();
    744  await promise;
    745 
    746  promise = TestUtils.waitForCondition(
    747    () => newTabMenuList.itemCount == 3,
    748    "addon option is no longer an option in the menu list after disable"
    749  );
    750  await secondAddon.disable();
    751  await promise;
    752 
    753  promise = TestUtils.waitForCondition(
    754    () => newTabMenuList.itemCount == 4,
    755    "addon option is added again to the menulist when enabled"
    756  );
    757  await secondAddon.enable();
    758  await promise;
    759 
    760  promise = TestUtils.waitForCondition(
    761    () => newTabMenuList.itemCount == 2,
    762    "addon options are all removed after disabling all"
    763  );
    764  await addon.disable();
    765  await secondAddon.disable();
    766  await promise;
    767  is(
    768    AboutNewTab.newTabURL,
    769    DEFAULT_NEWTAB,
    770    "new tab page is set back to default"
    771  );
    772 
    773  // Cleanup the tabs and add-on.
    774  BrowserTestUtils.removeTab(gBrowser.selectedTab);
    775  await extension.unload();
    776  await secondExtension.unload();
    777 });
    778 
    779 add_task(async function testExtensionControlledWebNotificationsPermission() {
    780  let manifest = {
    781    manifest_version: 2,
    782    name: "TestExtension",
    783    version: "1.0",
    784    description: "Testing WebNotificationsDisable",
    785    browser_specific_settings: { gecko: { id: "@web_notifications_disable" } },
    786    permissions: ["browserSettings"],
    787    browser_action: {
    788      default_title: "Testing",
    789    },
    790  };
    791 
    792  await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
    793  await openNotificationsPermissionDialog();
    794 
    795  let doc = sitePermissionsDialog.document;
    796  let extensionControlledContent = doc.getElementById(
    797    "browserNotificationsPermissionExtensionContent"
    798  );
    799 
    800  // Test that extension content is initially hidden.
    801  ok(
    802    extensionControlledContent.hidden,
    803    "Extension content is initially hidden"
    804  );
    805 
    806  // Install an extension that will disable web notifications permission.
    807  let messageShown = waitForMessageShown(
    808    "browserNotificationsPermissionExtensionContent",
    809    doc
    810  );
    811  let extension = ExtensionTestUtils.loadExtension({
    812    manifest,
    813    useAddonManager: "permanent",
    814    background() {
    815      browser.browserSettings.webNotificationsDisabled.set({ value: true });
    816      browser.test.sendMessage("load-extension");
    817    },
    818  });
    819  await extension.startup();
    820  await extension.awaitMessage("load-extension");
    821  await messageShown;
    822 
    823  let controlledDesc = extensionControlledContent.querySelector("description");
    824  Assert.deepEqual(
    825    doc.l10n.getAttributes(controlledDesc),
    826    {
    827      id: "extension-controlling-web-notifications",
    828      args: {
    829        name: "TestExtension",
    830      },
    831    },
    832    "The user is notified that an extension is controlling the web notifications permission"
    833  );
    834  is(
    835    extensionControlledContent.hidden,
    836    false,
    837    "The extension controlled row is not hidden"
    838  );
    839 
    840  // Disable the extension.
    841  doc.getElementById("disableNotificationsPermissionExtension").click();
    842 
    843  // Verify the user is notified how to enable the extension.
    844  await waitForEnableMessage(extensionControlledContent.id, doc);
    845  is(
    846    doc.l10n.getAttributes(controlledDesc.querySelector("label")).id,
    847    "extension-controlled-enable",
    848    "The user is notified of how to enable the extension again"
    849  );
    850 
    851  // Verify the enable message can be dismissed.
    852  let hidden = waitForMessageHidden(extensionControlledContent.id, doc);
    853  let dismissButton = controlledDesc.querySelector("image:last-of-type");
    854  dismissButton.click();
    855  await hidden;
    856 
    857  // Verify that the extension controlled content in hidden again.
    858  is(
    859    extensionControlledContent.hidden,
    860    true,
    861    "The extension controlled row is now hidden"
    862  );
    863 
    864  await extension.unload();
    865  BrowserTestUtils.removeTab(gBrowser.selectedTab);
    866 });
    867 
    868 add_task(async function testExtensionControlledHomepageUninstalledAddon() {
    869  async function checkHomepageEnabled() {
    870    await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
    871    let doc = gBrowser.contentDocument;
    872    is(
    873      gBrowser.currentURI.spec,
    874      "about:preferences#home",
    875      "#home should be in the URI for about:preferences"
    876    );
    877 
    878    // The homepage is enabled.
    879    let homepageInput = doc.getElementById("homePageUrl");
    880    is(homepageInput.disabled, false, "The homepage input is enabled");
    881    is(homepageInput.value, "", "The homepage input is empty");
    882 
    883    BrowserTestUtils.removeTab(gBrowser.selectedTab);
    884  }
    885 
    886  await ExtensionSettingsStore.initialize();
    887 
    888  // Verify the setting isn't reported as controlled and the inputs are enabled.
    889  is(
    890    ExtensionSettingsStore.getSetting("prefs", "homepage_override"),
    891    null,
    892    "The homepage_override is not set"
    893  );
    894  await checkHomepageEnabled();
    895 
    896  // Disarm any pending writes before we modify the JSONFile directly.
    897  await ExtensionSettingsStore._reloadFile(false);
    898 
    899  // Write out a bad store file.
    900  let storeData = {
    901    prefs: {
    902      homepage_override: {
    903        initialValue: "",
    904        precedenceList: [
    905          {
    906            id: "bad@mochi.test",
    907            installDate: 1508802672,
    908            value: "https://developer.mozilla.org",
    909            enabled: true,
    910          },
    911        ],
    912      },
    913    },
    914  };
    915  let jsonFileName = "extension-settings.json";
    916  let storePath = PathUtils.join(PathUtils.profileDir, jsonFileName);
    917 
    918  await IOUtils.writeUTF8(storePath, JSON.stringify(storeData));
    919 
    920  // Reload the ExtensionSettingsStore so it will read the file on disk. Don't
    921  // finalize the current store since it will overwrite our file.
    922  await ExtensionSettingsStore._reloadFile(false);
    923 
    924  // Verify that the setting is reported as set, but the homepage is still enabled
    925  // since there is no matching installed extension.
    926  is(
    927    ExtensionSettingsStore.getSetting("prefs", "homepage_override").value,
    928    "https://developer.mozilla.org",
    929    "The homepage_override appears to be set"
    930  );
    931  await checkHomepageEnabled();
    932 
    933  // Remove the bad store file that we used.
    934  await IOUtils.remove(storePath);
    935 
    936  // Reload the ExtensionSettingsStore again so it clears the data we added.
    937  // Don't finalize the current store since it will write out the bad data.
    938  await ExtensionSettingsStore._reloadFile(false);
    939 
    940  is(
    941    ExtensionSettingsStore.getSetting("prefs", "homepage_override"),
    942    null,
    943    "The ExtensionSettingsStore is left empty."
    944  );
    945 });
    946 
    947 add_task(async function testExtensionControlledTrackingProtection() {
    948  const TP_PREF = "privacy.trackingprotection.enabled";
    949  const TP_DEFAULT = false;
    950  const EXTENSION_ID = "@set_tp";
    951  const CONTROLLED_LABEL_ID =
    952    "contentBlockingTrackingProtectionExtensionContentLabel";
    953  const CONTROLLED_BUTTON_ID =
    954    "contentBlockingDisableTrackingProtectionExtension";
    955 
    956  let tpEnabledPref = () => Services.prefs.getBoolPref(TP_PREF);
    957 
    958  await SpecialPowers.pushPrefEnv({ set: [[TP_PREF, TP_DEFAULT]] });
    959 
    960  function background() {
    961    browser.privacy.websites.trackingProtectionMode.set({ value: "always" });
    962  }
    963 
    964  function verifyState(isControlled) {
    965    is(tpEnabledPref(), isControlled, "TP pref is set to the expected value.");
    966 
    967    let controlledLabel = doc.getElementById(CONTROLLED_LABEL_ID);
    968    let controlledButton = doc.getElementById(CONTROLLED_BUTTON_ID);
    969 
    970    is(
    971      controlledLabel.hidden,
    972      !isControlled,
    973      "The extension controlled row's visibility is as expected."
    974    );
    975    is(
    976      controlledButton.hidden,
    977      !isControlled,
    978      "The disable extension button's visibility is as expected."
    979    );
    980    if (isControlled) {
    981      let controlledDesc = controlledLabel.querySelector("description");
    982      Assert.deepEqual(
    983        doc.l10n.getAttributes(controlledDesc),
    984        {
    985          id: "extension-controlling-websites-content-blocking-all-trackers",
    986          args: {
    987            name: "set_tp",
    988          },
    989        },
    990        "The user is notified that an extension is controlling TP."
    991      );
    992    }
    993 
    994    is(
    995      doc.getElementById("trackingProtectionMenu").disabled,
    996      isControlled,
    997      "TP control is enabled."
    998    );
    999  }
   1000 
   1001  await openPreferencesViaOpenPreferencesAPI("panePrivacy", {
   1002    leaveOpen: true,
   1003  });
   1004  let doc = gBrowser.contentDocument;
   1005 
   1006  is(
   1007    gBrowser.currentURI.spec,
   1008    "about:preferences#privacy",
   1009    "#privacy should be in the URI for about:preferences"
   1010  );
   1011 
   1012  verifyState(false);
   1013 
   1014  // Install an extension that sets Tracking Protection.
   1015  let extension = ExtensionTestUtils.loadExtension({
   1016    useAddonManager: "permanent",
   1017    manifest: {
   1018      name: "set_tp",
   1019      browser_specific_settings: { gecko: { id: EXTENSION_ID } },
   1020      permissions: ["privacy"],
   1021    },
   1022    background,
   1023  });
   1024 
   1025  let messageShown = waitForMessageShown(CONTROLLED_LABEL_ID);
   1026  await extension.startup();
   1027  await messageShown;
   1028  let addon = await AddonManager.getAddonByID(EXTENSION_ID);
   1029 
   1030  verifyState(true);
   1031 
   1032  await disableExtensionViaClick(
   1033    CONTROLLED_LABEL_ID,
   1034    CONTROLLED_BUTTON_ID,
   1035    doc
   1036  );
   1037 
   1038  verifyState(false);
   1039 
   1040  // Enable the extension so we get the UNINSTALL event, which is needed by
   1041  // ExtensionPreferencesManager to clean up properly.
   1042  // TODO: BUG 1408226
   1043  await reEnableExtension(addon, CONTROLLED_LABEL_ID);
   1044 
   1045  await extension.unload();
   1046 
   1047  BrowserTestUtils.removeTab(gBrowser.selectedTab);
   1048 });
   1049 
   1050 add_task(async function testExtensionControlledPasswordManager() {
   1051  await SpecialPowers.pushPrefEnv({
   1052    set: [["browser.settings-redesign.enabled", false]],
   1053  });
   1054  const PASSWORD_MANAGER_ENABLED_PREF = "signon.rememberSignons";
   1055  const PASSWORD_MANAGER_ENABLED_DEFAULT = true;
   1056  const CONTROLLED_BUTTON_ID = "disablePasswordManagerExtension";
   1057  const CONTROLLED_LABEL_ID = "passwordManagerExtensionContent";
   1058  const EXTENSION_ID = "@remember_signons";
   1059  let manifest = {
   1060    manifest_version: 2,
   1061    name: "testPasswordManagerExtension",
   1062    version: "1.0",
   1063    description: "Testing rememberSignons",
   1064    browser_specific_settings: { gecko: { id: EXTENSION_ID } },
   1065    permissions: ["privacy"],
   1066    browser_action: {
   1067      default_title: "Testing rememberSignons",
   1068    },
   1069  };
   1070 
   1071  let passwordManagerEnabledPref = () =>
   1072    Services.prefs.getBoolPref(PASSWORD_MANAGER_ENABLED_PREF);
   1073 
   1074  await SpecialPowers.pushPrefEnv({
   1075    set: [[PASSWORD_MANAGER_ENABLED_PREF, PASSWORD_MANAGER_ENABLED_DEFAULT]],
   1076  });
   1077  is(
   1078    passwordManagerEnabledPref(),
   1079    true,
   1080    "Password manager is enabled by default."
   1081  );
   1082 
   1083  function verifyState(isControlled) {
   1084    is(
   1085      passwordManagerEnabledPref(),
   1086      !isControlled,
   1087      "Password manager pref is set to the expected value."
   1088    );
   1089    let controlledLabel =
   1090      gBrowser.contentDocument.getElementById(CONTROLLED_LABEL_ID);
   1091    let controlledButton =
   1092      gBrowser.contentDocument.getElementById(CONTROLLED_BUTTON_ID);
   1093    is(
   1094      controlledLabel.hidden,
   1095      !isControlled,
   1096      "The extension's controlled row visibility is as expected."
   1097    );
   1098    is(
   1099      controlledButton.hidden,
   1100      !isControlled,
   1101      "The extension's controlled button visibility is as expected."
   1102    );
   1103    if (isControlled) {
   1104      let controlledDesc = controlledLabel.querySelector("description");
   1105      Assert.deepEqual(
   1106        gBrowser.contentDocument.l10n.getAttributes(controlledDesc),
   1107        {
   1108          id: "extension-controlling-password-saving",
   1109          args: {
   1110            name: "testPasswordManagerExtension",
   1111          },
   1112        },
   1113        "The user is notified that an extension is controlling the remember signons pref."
   1114      );
   1115    }
   1116  }
   1117 
   1118  await openPreferencesViaOpenPreferencesAPI("panePrivacy", {
   1119    leaveOpen: true,
   1120  });
   1121 
   1122  info("Verify that no extension is controlling the password manager pref.");
   1123  verifyState(false);
   1124 
   1125  let extension = ExtensionTestUtils.loadExtension({
   1126    manifest,
   1127    useAddonManager: "permanent",
   1128    background() {
   1129      browser.privacy.services.passwordSavingEnabled.set({ value: false });
   1130    },
   1131  });
   1132  let messageShown = waitForMessageShown(CONTROLLED_LABEL_ID);
   1133  await extension.startup();
   1134  await messageShown;
   1135 
   1136  info(
   1137    "Verify that the test extension is controlling the password manager pref."
   1138  );
   1139  verifyState(true);
   1140 
   1141  info("Verify that the extension shows as controlled when loaded again.");
   1142  BrowserTestUtils.removeTab(gBrowser.selectedTab);
   1143  await openPreferencesViaOpenPreferencesAPI("panePrivacy", {
   1144    leaveOpen: true,
   1145  });
   1146  verifyState(true);
   1147 
   1148  await disableExtensionViaClick(
   1149    CONTROLLED_LABEL_ID,
   1150    CONTROLLED_BUTTON_ID,
   1151    gBrowser.contentDocument
   1152  );
   1153 
   1154  info(
   1155    "Verify that disabling the test extension removes the lock on the password manager pref."
   1156  );
   1157  verifyState(false);
   1158 
   1159  await extension.unload();
   1160 
   1161  BrowserTestUtils.removeTab(gBrowser.selectedTab);
   1162 });
   1163 
   1164 add_task(async function testExtensionControlledProxyConfig() {
   1165  const proxySvc = Ci.nsIProtocolProxyService;
   1166  const PROXY_DEFAULT = proxySvc.PROXYCONFIG_SYSTEM;
   1167  const EXTENSION_ID = "@set_proxy";
   1168  const CONTROLLED_SECTION_ID = "proxyExtensionContent";
   1169  const CONTROLLED_BUTTON_ID = "disableProxyExtension";
   1170  const CONNECTION_SETTINGS_DESC_ID = "connectionSettingsDescription";
   1171  const PANEL_URL =
   1172    "chrome://browser/content/preferences/dialogs/connection.xhtml";
   1173 
   1174  await SpecialPowers.pushPrefEnv({ set: [[PROXY_PREF, PROXY_DEFAULT]] });
   1175 
   1176  function background() {
   1177    browser.proxy.settings.set({ value: { proxyType: "none" } });
   1178  }
   1179 
   1180  function expectedConnectionSettingsMessage(doc, isControlled) {
   1181    return isControlled
   1182      ? "extension-controlling-proxy-config"
   1183      : "network-proxy-connection-description";
   1184  }
   1185 
   1186  function connectionSettingsMessagePromise(doc, isControlled) {
   1187    return waitForMessageContent(
   1188      CONNECTION_SETTINGS_DESC_ID,
   1189      expectedConnectionSettingsMessage(doc, isControlled),
   1190      doc
   1191    );
   1192  }
   1193 
   1194  function verifyProxyState(doc, isControlled) {
   1195    let isPanel = doc.getElementById(CONTROLLED_BUTTON_ID);
   1196    is(
   1197      proxyType === proxySvc.PROXYCONFIG_DIRECT,
   1198      isControlled,
   1199      "Proxy pref is set to the expected value."
   1200    );
   1201 
   1202    if (isPanel) {
   1203      let controlledSection = doc.getElementById(CONTROLLED_SECTION_ID);
   1204 
   1205      is(
   1206        controlledSection.hidden,
   1207        !isControlled,
   1208        "The extension controlled row's visibility is as expected."
   1209      );
   1210      if (isPanel) {
   1211        is(
   1212          doc.getElementById(CONTROLLED_BUTTON_ID).hidden,
   1213          !isControlled,
   1214          "The disable extension button's visibility is as expected."
   1215        );
   1216      }
   1217      if (isControlled) {
   1218        let controlledDesc = controlledSection.querySelector("description");
   1219        Assert.deepEqual(
   1220          doc.l10n.getAttributes(controlledDesc),
   1221          {
   1222            id: "extension-controlling-proxy-config",
   1223            args: {
   1224              name: "set_proxy",
   1225            },
   1226          },
   1227          "The user is notified that an extension is controlling proxy settings."
   1228        );
   1229      }
   1230      function getProxyControls() {
   1231        let controlGroup = doc.getElementById("networkProxyType");
   1232        let manualControlContainer = controlGroup.querySelector("#proxy-grid");
   1233        return {
   1234          manualControls: [
   1235            ...manualControlContainer.querySelectorAll(
   1236              "label[data-l10n-id]:not([control=networkProxyNone])"
   1237            ),
   1238            ...manualControlContainer.querySelectorAll("input"),
   1239            ...manualControlContainer.querySelectorAll("checkbox"),
   1240            ...doc.querySelectorAll("#networkProxySOCKSVersion > radio"),
   1241          ],
   1242          pacControls: [doc.getElementById("networkProxyAutoconfigURL")],
   1243          otherControls: [
   1244            doc.querySelector("label[control=networkProxyNone]"),
   1245            doc.getElementById("networkProxyNone"),
   1246            ...controlGroup.querySelectorAll(":scope > radio"),
   1247            ...doc.querySelectorAll("#ConnectionsDialogPane > checkbox"),
   1248          ],
   1249        };
   1250      }
   1251      let controlState = isControlled ? "disabled" : "enabled";
   1252      let controls = getProxyControls();
   1253      for (let element of controls.manualControls) {
   1254        let disabled =
   1255          isControlled || proxyType !== proxySvc.PROXYCONFIG_MANUAL;
   1256        is(
   1257          element.disabled,
   1258          disabled,
   1259          `Manual proxy controls should be ${controlState} - control: ${element.outerHTML}.`
   1260        );
   1261      }
   1262      for (let element of controls.pacControls) {
   1263        let disabled = isControlled || proxyType !== proxySvc.PROXYCONFIG_PAC;
   1264        is(
   1265          element.disabled,
   1266          disabled,
   1267          `PAC proxy controls should be ${controlState} - control: ${element.outerHTML}.`
   1268        );
   1269      }
   1270      for (let element of controls.otherControls) {
   1271        is(
   1272          element.disabled,
   1273          isControlled,
   1274          `Other proxy controls should be ${controlState} - control: ${element.outerHTML}.`
   1275        );
   1276      }
   1277    } else {
   1278      let elem = doc.getElementById(CONNECTION_SETTINGS_DESC_ID);
   1279      is(
   1280        doc.l10n.getAttributes(elem).id,
   1281        expectedConnectionSettingsMessage(doc, isControlled),
   1282        "The connection settings description is as expected."
   1283      );
   1284    }
   1285  }
   1286 
   1287  async function reEnableProxyExtension(addon) {
   1288    let messageChanged = connectionSettingsMessagePromise(mainDoc, true);
   1289    await addon.enable();
   1290    await messageChanged;
   1291  }
   1292 
   1293  async function openProxyPanel() {
   1294    let panel = await openAndLoadSubDialog(PANEL_URL);
   1295    let closingPromise = BrowserTestUtils.waitForEvent(
   1296      panel.document.getElementById("ConnectionsDialog"),
   1297      "dialogclosing"
   1298    );
   1299    ok(panel, "Proxy panel opened.");
   1300    return { panel, closingPromise };
   1301  }
   1302 
   1303  async function closeProxyPanel(panelObj) {
   1304    let dialog = panelObj.panel.document.getElementById("ConnectionsDialog");
   1305    dialog.cancelDialog();
   1306    let panelClosingEvent = await panelObj.closingPromise;
   1307    ok(panelClosingEvent, "Proxy panel closed.");
   1308  }
   1309 
   1310  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
   1311    leaveOpen: true,
   1312  });
   1313  let mainDoc = gBrowser.contentDocument;
   1314 
   1315  is(
   1316    gBrowser.currentURI.spec,
   1317    "about:preferences#general",
   1318    "#general should be in the URI for about:preferences"
   1319  );
   1320 
   1321  verifyProxyState(mainDoc, false);
   1322 
   1323  // Open the connections panel.
   1324  let panelObj = await openProxyPanel();
   1325  let panelDoc = panelObj.panel.document;
   1326 
   1327  verifyProxyState(panelDoc, false);
   1328 
   1329  await closeProxyPanel(panelObj);
   1330 
   1331  verifyProxyState(mainDoc, false);
   1332 
   1333  // Install an extension that controls proxy settings. The extension needs
   1334  // incognitoOverride because controlling the proxy.settings requires private
   1335  // browsing access.
   1336  let extension = ExtensionTestUtils.loadExtension({
   1337    incognitoOverride: "spanning",
   1338    useAddonManager: "permanent",
   1339    manifest: {
   1340      name: "set_proxy",
   1341      browser_specific_settings: { gecko: { id: EXTENSION_ID } },
   1342      permissions: ["proxy"],
   1343    },
   1344    background,
   1345  });
   1346 
   1347  let messageChanged = connectionSettingsMessagePromise(mainDoc, true);
   1348  await extension.startup();
   1349  await messageChanged;
   1350  let addon = await AddonManager.getAddonByID(EXTENSION_ID);
   1351 
   1352  verifyProxyState(mainDoc, true);
   1353  messageChanged = connectionSettingsMessagePromise(mainDoc, false);
   1354 
   1355  panelObj = await openProxyPanel();
   1356  panelDoc = panelObj.panel.document;
   1357 
   1358  verifyProxyState(panelDoc, true);
   1359 
   1360  await disableExtensionViaClick(
   1361    CONTROLLED_SECTION_ID,
   1362    CONTROLLED_BUTTON_ID,
   1363    panelDoc
   1364  );
   1365 
   1366  verifyProxyState(panelDoc, false);
   1367 
   1368  await closeProxyPanel(panelObj);
   1369  await messageChanged;
   1370 
   1371  verifyProxyState(mainDoc, false);
   1372 
   1373  await reEnableProxyExtension(addon);
   1374 
   1375  verifyProxyState(mainDoc, true);
   1376  messageChanged = connectionSettingsMessagePromise(mainDoc, false);
   1377 
   1378  panelObj = await openProxyPanel();
   1379  panelDoc = panelObj.panel.document;
   1380 
   1381  verifyProxyState(panelDoc, true);
   1382 
   1383  await disableExtensionViaClick(
   1384    CONTROLLED_SECTION_ID,
   1385    CONTROLLED_BUTTON_ID,
   1386    panelDoc
   1387  );
   1388 
   1389  verifyProxyState(panelDoc, false);
   1390 
   1391  await closeProxyPanel(panelObj);
   1392  await messageChanged;
   1393 
   1394  verifyProxyState(mainDoc, false);
   1395 
   1396  // Enable the extension so we get the UNINSTALL event, which is needed by
   1397  // ExtensionPreferencesManager to clean up properly.
   1398  // TODO: BUG 1408226
   1399  await reEnableProxyExtension(addon);
   1400 
   1401  await extension.unload();
   1402 
   1403  BrowserTestUtils.removeTab(gBrowser.selectedTab);
   1404 });
   1405 
   1406 // Test that the newtab menu selection is correct when loading about:preferences
   1407 add_task(async function testMenuSyncFromPrefs() {
   1408  const DEFAULT_NEWTAB = "about:newtab";
   1409 
   1410  await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
   1411  is(
   1412    gBrowser.currentURI.spec,
   1413    "about:preferences#home",
   1414    "#home should be in the URI for about:preferences"
   1415  );
   1416 
   1417  let doc = gBrowser.contentDocument;
   1418  let newTabMenuList = doc.getElementById("newTabMode");
   1419  // The new tab page is set to the default.
   1420  is(AboutNewTab.newTabURL, DEFAULT_NEWTAB, "new tab is set to default");
   1421 
   1422  is(newTabMenuList.value, "0", "New tab menulist is set to the default");
   1423 
   1424  newTabMenuList.value = "1";
   1425  newTabMenuList.dispatchEvent(new Event("command"));
   1426  is(newTabMenuList.value, "1", "New tab menulist is set to blank");
   1427 
   1428  gBrowser.reloadTab(gBrowser.selectedTab);
   1429 
   1430  await TestUtils.waitForCondition(
   1431    () => gBrowser.contentDocument.getElementById("newTabMode"),
   1432    "wait until element exists in new contentDoc"
   1433  );
   1434 
   1435  is(
   1436    gBrowser.contentDocument.getElementById("newTabMode").value,
   1437    "1",
   1438    "New tab menulist is still set to blank"
   1439  );
   1440 
   1441  // Cleanup
   1442  newTabMenuList.value = "0";
   1443  newTabMenuList.dispatchEvent(new Event("command"));
   1444  is(AboutNewTab.newTabURL, DEFAULT_NEWTAB, "new tab is set to default");
   1445  BrowserTestUtils.removeTab(gBrowser.selectedTab);
   1446 });