forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			1450 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1450 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* eslint-env webextensions */
 | 
						|
 | 
						|
const PROXY_PREF = "network.proxy.type";
 | 
						|
const HOMEPAGE_URL_PREF = "browser.startup.homepage";
 | 
						|
const HOMEPAGE_OVERRIDE_KEY = "homepage_override";
 | 
						|
const URL_OVERRIDES_TYPE = "url_overrides";
 | 
						|
const NEW_TAB_KEY = "newTabURL";
 | 
						|
const PREF_SETTING_TYPE = "prefs";
 | 
						|
 | 
						|
ChromeUtils.defineModuleGetter(
 | 
						|
  this,
 | 
						|
  "ExtensionSettingsStore",
 | 
						|
  "resource://gre/modules/ExtensionSettingsStore.jsm"
 | 
						|
);
 | 
						|
 | 
						|
ChromeUtils.defineModuleGetter(
 | 
						|
  this,
 | 
						|
  "AboutNewTab",
 | 
						|
  "resource:///modules/AboutNewTab.jsm"
 | 
						|
);
 | 
						|
 | 
						|
XPCOMUtils.defineLazyPreferenceGetter(this, "proxyType", PROXY_PREF);
 | 
						|
 | 
						|
const { AddonTestUtils } = ChromeUtils.import(
 | 
						|
  "resource://testing-common/AddonTestUtils.jsm"
 | 
						|
);
 | 
						|
AddonTestUtils.initMochitest(this);
 | 
						|
 | 
						|
const { ExtensionPreferencesManager } = ChromeUtils.import(
 | 
						|
  "resource://gre/modules/ExtensionPreferencesManager.jsm"
 | 
						|
);
 | 
						|
 | 
						|
const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 | 
						|
const CHROME_URL_ROOT = TEST_DIR + "/";
 | 
						|
const PERMISSIONS_URL =
 | 
						|
  "chrome://browser/content/preferences/dialogs/sitePermissions.xhtml";
 | 
						|
let sitePermissionsDialog;
 | 
						|
 | 
						|
function getSupportsFile(path) {
 | 
						|
  let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(
 | 
						|
    Ci.nsIChromeRegistry
 | 
						|
  );
 | 
						|
  let uri = Services.io.newURI(CHROME_URL_ROOT + path);
 | 
						|
  let fileurl = cr.convertChromeURL(uri);
 | 
						|
  return fileurl.QueryInterface(Ci.nsIFileURL);
 | 
						|
}
 | 
						|
 | 
						|
function waitForMessageChange(
 | 
						|
  element,
 | 
						|
  cb,
 | 
						|
  opts = { attributes: true, attributeFilter: ["hidden"] }
 | 
						|
) {
 | 
						|
  return waitForMutation(element, opts, cb);
 | 
						|
}
 | 
						|
 | 
						|
function getElement(id, doc = gBrowser.contentDocument) {
 | 
						|
  return doc.getElementById(id);
 | 
						|
}
 | 
						|
 | 
						|
function waitForMessageHidden(messageId, doc) {
 | 
						|
  return waitForMessageChange(
 | 
						|
    getElement(messageId, doc),
 | 
						|
    target => target.hidden
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
function waitForMessageShown(messageId, doc) {
 | 
						|
  return waitForMessageChange(
 | 
						|
    getElement(messageId, doc),
 | 
						|
    target => !target.hidden
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
function waitForEnableMessage(messageId, doc) {
 | 
						|
  return waitForMessageChange(
 | 
						|
    getElement(messageId, doc),
 | 
						|
    target => target.classList.contains("extension-controlled-disabled"),
 | 
						|
    { attributeFilter: ["class"], attributes: true }
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
function waitForMessageContent(messageId, l10nId, doc) {
 | 
						|
  return waitForMessageChange(
 | 
						|
    getElement(messageId, doc),
 | 
						|
    target => doc.l10n.getAttributes(target).id === l10nId,
 | 
						|
    { childList: true }
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
async function openNotificationsPermissionDialog() {
 | 
						|
  let dialogOpened = promiseLoadSubDialog(PERMISSIONS_URL);
 | 
						|
 | 
						|
  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() {
 | 
						|
    let doc = content.document;
 | 
						|
    let settingsButton = doc.getElementById("notificationSettingsButton");
 | 
						|
    settingsButton.click();
 | 
						|
  });
 | 
						|
 | 
						|
  sitePermissionsDialog = await dialogOpened;
 | 
						|
  await sitePermissionsDialog.document.mozSubdialogReady;
 | 
						|
}
 | 
						|
 | 
						|
async function disableExtensionViaClick(labelId, disableButtonId, doc) {
 | 
						|
  let controlledLabel = doc.getElementById(labelId);
 | 
						|
 | 
						|
  let enableMessageShown = waitForEnableMessage(labelId, doc);
 | 
						|
  doc.getElementById(disableButtonId).click();
 | 
						|
  await enableMessageShown;
 | 
						|
 | 
						|
  let controlledDescription = controlledLabel.querySelector("description");
 | 
						|
  is(
 | 
						|
    doc.l10n.getAttributes(controlledDescription.querySelector("label")).id,
 | 
						|
    "extension-controlled-enable",
 | 
						|
    "The user is notified of how to enable the extension again."
 | 
						|
  );
 | 
						|
 | 
						|
  // The user can dismiss the enable instructions.
 | 
						|
  let hidden = waitForMessageHidden(labelId, doc);
 | 
						|
  controlledLabel.querySelector("image:last-of-type").click();
 | 
						|
  await hidden;
 | 
						|
}
 | 
						|
 | 
						|
async function reEnableExtension(addon, labelId) {
 | 
						|
  let controlledMessageShown = waitForMessageShown(labelId);
 | 
						|
  await addon.enable();
 | 
						|
  await controlledMessageShown;
 | 
						|
}
 | 
						|
 | 
						|
add_task(async function testExtensionControlledHomepage() {
 | 
						|
  const ADDON_ID = "@set_homepage";
 | 
						|
  const SECOND_ADDON_ID = "@second_set_homepage";
 | 
						|
 | 
						|
  await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
 | 
						|
  let homepagePref = () => Services.prefs.getCharPref(HOMEPAGE_URL_PREF);
 | 
						|
  let originalHomepagePref = homepagePref();
 | 
						|
  is(
 | 
						|
    gBrowser.currentURI.spec,
 | 
						|
    "about:preferences#home",
 | 
						|
    "#home should be in the URI for about:preferences"
 | 
						|
  );
 | 
						|
  let doc = gBrowser.contentDocument;
 | 
						|
  let homeModeEl = doc.getElementById("homeMode");
 | 
						|
  let customSettingsSection = doc.getElementById("customSettings");
 | 
						|
 | 
						|
  is(homeModeEl.itemCount, 3, "The menu list starts with 3 options");
 | 
						|
 | 
						|
  let promise = TestUtils.waitForCondition(
 | 
						|
    () => homeModeEl.itemCount === 4,
 | 
						|
    "wait for the addon option to be added as an option in the menu list"
 | 
						|
  );
 | 
						|
  let extension = ExtensionTestUtils.loadExtension({
 | 
						|
    useAddonManager: "permanent",
 | 
						|
    manifest: {
 | 
						|
      version: "1.0",
 | 
						|
      name: "set_homepage",
 | 
						|
      applications: {
 | 
						|
        gecko: {
 | 
						|
          id: ADDON_ID,
 | 
						|
        },
 | 
						|
      },
 | 
						|
      chrome_settings_overrides: { homepage: "/home.html" },
 | 
						|
    },
 | 
						|
  });
 | 
						|
  await extension.startup();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  // The homepage is set to the default and the custom settings section is hidden
 | 
						|
  is(homeModeEl.disabled, false, "The homepage menulist is enabled");
 | 
						|
  is(
 | 
						|
    customSettingsSection.hidden,
 | 
						|
    true,
 | 
						|
    "The custom settings element is hidden"
 | 
						|
  );
 | 
						|
 | 
						|
  let addon = await AddonManager.getAddonByID(ADDON_ID);
 | 
						|
  is(
 | 
						|
    homeModeEl.value,
 | 
						|
    addon.id,
 | 
						|
    "the home select menu's value is set to the addon"
 | 
						|
  );
 | 
						|
 | 
						|
  promise = TestUtils.waitForPrefChange(HOMEPAGE_URL_PREF);
 | 
						|
  // Set the Menu to the default value
 | 
						|
  homeModeEl.value = "0";
 | 
						|
  homeModeEl.dispatchEvent(new Event("command"));
 | 
						|
  await promise;
 | 
						|
  is(homepagePref(), originalHomepagePref, "homepage is set back to default");
 | 
						|
  let levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
 | 
						|
    addon.id,
 | 
						|
    HOMEPAGE_OVERRIDE_KEY,
 | 
						|
    PREF_SETTING_TYPE
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    levelOfControl,
 | 
						|
    "not_controllable",
 | 
						|
    "getLevelOfControl returns not_controllable."
 | 
						|
  );
 | 
						|
  let setting = await ExtensionPreferencesManager.getSetting(
 | 
						|
    HOMEPAGE_OVERRIDE_KEY
 | 
						|
  );
 | 
						|
  ok(!setting.value, "the setting is not set.");
 | 
						|
 | 
						|
  promise = TestUtils.waitForPrefChange(HOMEPAGE_URL_PREF);
 | 
						|
  // Set the menu to the addon value
 | 
						|
  homeModeEl.value = ADDON_ID;
 | 
						|
  homeModeEl.dispatchEvent(new Event("command"));
 | 
						|
  await promise;
 | 
						|
  ok(
 | 
						|
    homepagePref().startsWith("moz-extension") &&
 | 
						|
      homepagePref().endsWith("home.html"),
 | 
						|
    "Home url should be provided by the extension."
 | 
						|
  );
 | 
						|
  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
 | 
						|
    addon.id,
 | 
						|
    HOMEPAGE_OVERRIDE_KEY,
 | 
						|
    PREF_SETTING_TYPE
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    levelOfControl,
 | 
						|
    "controlled_by_this_extension",
 | 
						|
    "getLevelOfControl returns controlled_by_this_extension."
 | 
						|
  );
 | 
						|
  setting = await ExtensionPreferencesManager.getSetting(HOMEPAGE_OVERRIDE_KEY);
 | 
						|
  ok(
 | 
						|
    setting.value.startsWith("moz-extension") &&
 | 
						|
      setting.value.endsWith("home.html"),
 | 
						|
    "The setting value is the same as the extension."
 | 
						|
  );
 | 
						|
 | 
						|
  // Add a second extension, ensure it is added to the menulist and selected.
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => homeModeEl.itemCount == 5,
 | 
						|
    "addon option is added as an option in the menu list"
 | 
						|
  );
 | 
						|
  let secondExtension = ExtensionTestUtils.loadExtension({
 | 
						|
    useAddonManager: "permanent",
 | 
						|
    manifest: {
 | 
						|
      version: "1.0",
 | 
						|
      name: "second_set_homepage",
 | 
						|
      applications: {
 | 
						|
        gecko: {
 | 
						|
          id: SECOND_ADDON_ID,
 | 
						|
        },
 | 
						|
      },
 | 
						|
      chrome_settings_overrides: { homepage: "/home2.html" },
 | 
						|
    },
 | 
						|
  });
 | 
						|
  await secondExtension.startup();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  let secondAddon = await AddonManager.getAddonByID(SECOND_ADDON_ID);
 | 
						|
  is(homeModeEl.value, SECOND_ADDON_ID, "home menulist is set to the add-on");
 | 
						|
 | 
						|
  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
 | 
						|
    secondAddon.id,
 | 
						|
    HOMEPAGE_OVERRIDE_KEY,
 | 
						|
    PREF_SETTING_TYPE
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    levelOfControl,
 | 
						|
    "controlled_by_this_extension",
 | 
						|
    "getLevelOfControl returns controlled_by_this_extension."
 | 
						|
  );
 | 
						|
  setting = await ExtensionPreferencesManager.getSetting(HOMEPAGE_OVERRIDE_KEY);
 | 
						|
  ok(
 | 
						|
    setting.value.startsWith("moz-extension") &&
 | 
						|
      setting.value.endsWith("home2.html"),
 | 
						|
    "The setting value is the same as the extension."
 | 
						|
  );
 | 
						|
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => homeModeEl.itemCount == 4,
 | 
						|
    "addon option is no longer an option in the menu list after disable, even if it was not selected"
 | 
						|
  );
 | 
						|
  await addon.disable();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  // Ensure that re-enabling an addon adds it back to the menulist
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => homeModeEl.itemCount == 5,
 | 
						|
    "addon option is added again to the menulist when enabled"
 | 
						|
  );
 | 
						|
  await addon.enable();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => homeModeEl.itemCount == 4,
 | 
						|
    "addon option is no longer an option in the menu list after disable"
 | 
						|
  );
 | 
						|
  await secondAddon.disable();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => homeModeEl.itemCount == 5,
 | 
						|
    "addon option is added again to the menulist when enabled"
 | 
						|
  );
 | 
						|
  await secondAddon.enable();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => homeModeEl.itemCount == 3,
 | 
						|
    "addon options are no longer an option in the menu list after disabling all addons"
 | 
						|
  );
 | 
						|
  await secondAddon.disable();
 | 
						|
  await addon.disable();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  is(homeModeEl.value, "0", "addon option is not selected in the menu list");
 | 
						|
 | 
						|
  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
 | 
						|
    secondAddon.id,
 | 
						|
    HOMEPAGE_OVERRIDE_KEY,
 | 
						|
    PREF_SETTING_TYPE
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    levelOfControl,
 | 
						|
    "controllable_by_this_extension",
 | 
						|
    "getLevelOfControl returns controllable_by_this_extension."
 | 
						|
  );
 | 
						|
  setting = await ExtensionPreferencesManager.getSetting(HOMEPAGE_OVERRIDE_KEY);
 | 
						|
  ok(!setting.value, "The setting value is back to default.");
 | 
						|
 | 
						|
  // The homepage elements are reset to their original state.
 | 
						|
  is(homepagePref(), originalHomepagePref, "homepage is set back to default");
 | 
						|
  is(homeModeEl.disabled, false, "The homepage menulist is enabled");
 | 
						|
  BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
  await extension.unload();
 | 
						|
  await secondExtension.unload();
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function testPrefLockedHomepage() {
 | 
						|
  const ADDON_ID = "@set_homepage";
 | 
						|
  await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
 | 
						|
  let doc = gBrowser.contentDocument;
 | 
						|
  is(
 | 
						|
    gBrowser.currentURI.spec,
 | 
						|
    "about:preferences#home",
 | 
						|
    "#home should be in the URI for about:preferences"
 | 
						|
  );
 | 
						|
 | 
						|
  let homePagePref = "browser.startup.homepage";
 | 
						|
  let buttonPrefs = [
 | 
						|
    "pref.browser.homepage.disable_button.current_page",
 | 
						|
    "pref.browser.homepage.disable_button.bookmark_page",
 | 
						|
    "pref.browser.homepage.disable_button.restore_default",
 | 
						|
  ];
 | 
						|
  let homeModeEl = doc.getElementById("homeMode");
 | 
						|
  let homePageInput = doc.getElementById("homePageUrl");
 | 
						|
  let prefs = Services.prefs.getDefaultBranch(null);
 | 
						|
  let mutationOpts = { attributes: true, attributeFilter: ["disabled"] };
 | 
						|
 | 
						|
  // Helper functions.
 | 
						|
  let getButton = pref =>
 | 
						|
    doc.querySelector(`.homepage-button[preference="${pref}"`);
 | 
						|
  let waitForAllMutations = () =>
 | 
						|
    Promise.all(
 | 
						|
      buttonPrefs
 | 
						|
        .map(pref => waitForMutation(getButton(pref), mutationOpts))
 | 
						|
        .concat([
 | 
						|
          waitForMutation(homeModeEl, mutationOpts),
 | 
						|
          waitForMutation(homePageInput, mutationOpts),
 | 
						|
        ])
 | 
						|
    );
 | 
						|
  let getHomepage = () =>
 | 
						|
    Services.prefs.getCharPref("browser.startup.homepage");
 | 
						|
 | 
						|
  let originalHomepage = getHomepage();
 | 
						|
  let extensionHomepage = "https://developer.mozilla.org/";
 | 
						|
  let lockedHomepage = "http://www.yahoo.com";
 | 
						|
 | 
						|
  let lockPrefs = () => {
 | 
						|
    buttonPrefs.forEach(pref => {
 | 
						|
      prefs.setBoolPref(pref, true);
 | 
						|
      prefs.lockPref(pref);
 | 
						|
    });
 | 
						|
    // Do the homepage last since that's the only pref that triggers a UI update.
 | 
						|
    prefs.setCharPref(homePagePref, lockedHomepage);
 | 
						|
    prefs.lockPref(homePagePref);
 | 
						|
  };
 | 
						|
  let unlockPrefs = () => {
 | 
						|
    buttonPrefs.forEach(pref => {
 | 
						|
      prefs.unlockPref(pref);
 | 
						|
      prefs.setBoolPref(pref, false);
 | 
						|
    });
 | 
						|
    // Do the homepage last since that's the only pref that triggers a UI update.
 | 
						|
    prefs.unlockPref(homePagePref);
 | 
						|
    prefs.setCharPref(homePagePref, originalHomepage);
 | 
						|
  };
 | 
						|
 | 
						|
  // Lock or unlock prefs then wait for all mutations to finish.
 | 
						|
  // Expects a bool indicating if we should lock or unlock.
 | 
						|
  let waitForLockMutations = lock => {
 | 
						|
    let mutationsDone = waitForAllMutations();
 | 
						|
    if (lock) {
 | 
						|
      lockPrefs();
 | 
						|
    } else {
 | 
						|
      unlockPrefs();
 | 
						|
    }
 | 
						|
    return mutationsDone;
 | 
						|
  };
 | 
						|
 | 
						|
  ok(
 | 
						|
    originalHomepage != extensionHomepage,
 | 
						|
    "The extension will change the homepage"
 | 
						|
  );
 | 
						|
 | 
						|
  // Install an extension that sets the homepage to MDN.
 | 
						|
  let promise = TestUtils.waitForPrefChange(HOMEPAGE_URL_PREF);
 | 
						|
  let extension = ExtensionTestUtils.loadExtension({
 | 
						|
    useAddonManager: "permanent",
 | 
						|
    manifest: {
 | 
						|
      version: "1.0",
 | 
						|
      name: "set_homepage",
 | 
						|
      applications: {
 | 
						|
        gecko: {
 | 
						|
          id: ADDON_ID,
 | 
						|
        },
 | 
						|
      },
 | 
						|
      chrome_settings_overrides: { homepage: "https://developer.mozilla.org/" },
 | 
						|
    },
 | 
						|
  });
 | 
						|
  await extension.startup();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  // Check that everything is still disabled, homepage didn't change.
 | 
						|
  is(
 | 
						|
    getHomepage(),
 | 
						|
    extensionHomepage,
 | 
						|
    "The reported homepage is set by the extension"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    homePageInput.value,
 | 
						|
    extensionHomepage,
 | 
						|
    "The homepage is set by the extension"
 | 
						|
  );
 | 
						|
 | 
						|
  // Lock all of the prefs, wait for the UI to update.
 | 
						|
  await waitForLockMutations(true);
 | 
						|
 | 
						|
  // Check that everything is now disabled.
 | 
						|
  is(getHomepage(), lockedHomepage, "The reported homepage is set by the pref");
 | 
						|
  is(homePageInput.value, lockedHomepage, "The homepage is set by the pref");
 | 
						|
  is(
 | 
						|
    homePageInput.disabled,
 | 
						|
    true,
 | 
						|
    "The homepage is disabed when the pref is locked"
 | 
						|
  );
 | 
						|
 | 
						|
  buttonPrefs.forEach(pref => {
 | 
						|
    is(
 | 
						|
      getButton(pref).disabled,
 | 
						|
      true,
 | 
						|
      `The ${pref} button is disabled when locked`
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  let levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
 | 
						|
    ADDON_ID,
 | 
						|
    HOMEPAGE_OVERRIDE_KEY,
 | 
						|
    PREF_SETTING_TYPE
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    levelOfControl,
 | 
						|
    "not_controllable",
 | 
						|
    "getLevelOfControl returns not_controllable, the pref is locked."
 | 
						|
  );
 | 
						|
 | 
						|
  // Verify that the UI is selecting the extension's Id in the menulist
 | 
						|
  let unlockedPromise = TestUtils.waitForCondition(
 | 
						|
    () => homeModeEl.value == ADDON_ID,
 | 
						|
    "Homepage menulist value is equal to the extension ID"
 | 
						|
  );
 | 
						|
  // Unlock the prefs, wait for the UI to update.
 | 
						|
  unlockPrefs();
 | 
						|
  await unlockedPromise;
 | 
						|
 | 
						|
  is(
 | 
						|
    homeModeEl.disabled,
 | 
						|
    false,
 | 
						|
    "the home select element is not disabled when the pref is not locked"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    homePageInput.disabled,
 | 
						|
    false,
 | 
						|
    "The homepage is enabled when the pref is unlocked"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    getHomepage(),
 | 
						|
    extensionHomepage,
 | 
						|
    "The homepage is reset to extension page"
 | 
						|
  );
 | 
						|
 | 
						|
  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
 | 
						|
    ADDON_ID,
 | 
						|
    HOMEPAGE_OVERRIDE_KEY,
 | 
						|
    PREF_SETTING_TYPE
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    levelOfControl,
 | 
						|
    "controlled_by_this_extension",
 | 
						|
    "getLevelOfControl returns controlled_by_this_extension after prefs are unlocked."
 | 
						|
  );
 | 
						|
  let setting = await ExtensionPreferencesManager.getSetting(
 | 
						|
    HOMEPAGE_OVERRIDE_KEY
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    setting.value,
 | 
						|
    extensionHomepage,
 | 
						|
    "The setting value is equal to the extensionHomepage."
 | 
						|
  );
 | 
						|
 | 
						|
  // Uninstall the add-on.
 | 
						|
  promise = TestUtils.waitForPrefChange(HOMEPAGE_URL_PREF);
 | 
						|
  await extension.unload();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  setting = await ExtensionPreferencesManager.getSetting(HOMEPAGE_OVERRIDE_KEY);
 | 
						|
  ok(!setting, "The setting is gone after the addon is uninstalled.");
 | 
						|
 | 
						|
  // Check that everything is now enabled again.
 | 
						|
  is(
 | 
						|
    getHomepage(),
 | 
						|
    originalHomepage,
 | 
						|
    "The reported homepage is reset to original value"
 | 
						|
  );
 | 
						|
  is(homePageInput.value, "", "The homepage is empty");
 | 
						|
  is(
 | 
						|
    homePageInput.disabled,
 | 
						|
    false,
 | 
						|
    "The homepage is enabled after clearing lock"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    homeModeEl.disabled,
 | 
						|
    false,
 | 
						|
    "Homepage menulist is enabled after clearing lock"
 | 
						|
  );
 | 
						|
  buttonPrefs.forEach(pref => {
 | 
						|
    is(
 | 
						|
      getButton(pref).disabled,
 | 
						|
      false,
 | 
						|
      `The ${pref} button is enabled when unlocked`
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  // Lock the prefs without an extension.
 | 
						|
  await waitForLockMutations(true);
 | 
						|
 | 
						|
  // Check that everything is now disabled.
 | 
						|
  is(getHomepage(), lockedHomepage, "The reported homepage is set by the pref");
 | 
						|
  is(homePageInput.value, lockedHomepage, "The homepage is set by the pref");
 | 
						|
  is(
 | 
						|
    homePageInput.disabled,
 | 
						|
    true,
 | 
						|
    "The homepage is disabed when the pref is locked"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    homeModeEl.disabled,
 | 
						|
    true,
 | 
						|
    "Homepage menulist is disabled when pref is locked"
 | 
						|
  );
 | 
						|
  buttonPrefs.forEach(pref => {
 | 
						|
    is(
 | 
						|
      getButton(pref).disabled,
 | 
						|
      true,
 | 
						|
      `The ${pref} button is disabled when locked`
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  // Unlock the prefs without an extension.
 | 
						|
  await waitForLockMutations(false);
 | 
						|
 | 
						|
  // Check that everything is enabled again.
 | 
						|
  is(
 | 
						|
    getHomepage(),
 | 
						|
    originalHomepage,
 | 
						|
    "The homepage is reset to the original value"
 | 
						|
  );
 | 
						|
  is(homePageInput.value, "", "The homepage is clear after being unlocked");
 | 
						|
  is(
 | 
						|
    homePageInput.disabled,
 | 
						|
    false,
 | 
						|
    "The homepage is enabled after clearing lock"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    homeModeEl.disabled,
 | 
						|
    false,
 | 
						|
    "Homepage menulist is enabled after clearing lock"
 | 
						|
  );
 | 
						|
  buttonPrefs.forEach(pref => {
 | 
						|
    is(
 | 
						|
      getButton(pref).disabled,
 | 
						|
      false,
 | 
						|
      `The ${pref} button is enabled when unlocked`
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function testExtensionControlledNewTab() {
 | 
						|
  const ADDON_ID = "@set_newtab";
 | 
						|
  const SECOND_ADDON_ID = "@second_set_newtab";
 | 
						|
  const DEFAULT_NEWTAB = "about:newtab";
 | 
						|
  const NEWTAB_CONTROLLED_PREF = "browser.newtab.extensionControlled";
 | 
						|
 | 
						|
  await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
 | 
						|
  is(
 | 
						|
    gBrowser.currentURI.spec,
 | 
						|
    "about:preferences#home",
 | 
						|
    "#home should be in the URI for about:preferences"
 | 
						|
  );
 | 
						|
 | 
						|
  let doc = gBrowser.contentDocument;
 | 
						|
  let newTabMenuList = doc.getElementById("newTabMode");
 | 
						|
  // The new tab page is set to the default.
 | 
						|
  is(AboutNewTab.newTabURL, DEFAULT_NEWTAB, "new tab is set to default");
 | 
						|
 | 
						|
  let promise = TestUtils.waitForCondition(
 | 
						|
    () => newTabMenuList.itemCount == 3,
 | 
						|
    "addon option is added as an option in the menu list"
 | 
						|
  );
 | 
						|
  // Install an extension that will set the new tab page.
 | 
						|
  let extension = ExtensionTestUtils.loadExtension({
 | 
						|
    useAddonManager: "permanent",
 | 
						|
    manifest: {
 | 
						|
      version: "1.0",
 | 
						|
      name: "set_newtab",
 | 
						|
      applications: {
 | 
						|
        gecko: {
 | 
						|
          id: ADDON_ID,
 | 
						|
        },
 | 
						|
      },
 | 
						|
      chrome_url_overrides: { newtab: "/newtab.html" },
 | 
						|
    },
 | 
						|
  });
 | 
						|
  await extension.startup();
 | 
						|
 | 
						|
  await promise;
 | 
						|
  let addon = await AddonManager.getAddonByID(ADDON_ID);
 | 
						|
 | 
						|
  is(newTabMenuList.value, ADDON_ID, "New tab menulist is set to the add-on");
 | 
						|
 | 
						|
  let levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
 | 
						|
    addon.id,
 | 
						|
    NEW_TAB_KEY,
 | 
						|
    URL_OVERRIDES_TYPE
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    levelOfControl,
 | 
						|
    "controlled_by_this_extension",
 | 
						|
    "getLevelOfControl returns controlled_by_this_extension."
 | 
						|
  );
 | 
						|
  let setting = ExtensionSettingsStore.getSetting(
 | 
						|
    URL_OVERRIDES_TYPE,
 | 
						|
    NEW_TAB_KEY
 | 
						|
  );
 | 
						|
  ok(
 | 
						|
    setting.value.startsWith("moz-extension") &&
 | 
						|
      setting.value.endsWith("newtab.html"),
 | 
						|
    "The url_overrides is set by this extension"
 | 
						|
  );
 | 
						|
 | 
						|
  promise = TestUtils.waitForPrefChange(NEWTAB_CONTROLLED_PREF);
 | 
						|
  // Set the menu to the default value
 | 
						|
  newTabMenuList.value = "0";
 | 
						|
  newTabMenuList.dispatchEvent(new Event("command"));
 | 
						|
  await promise;
 | 
						|
  let newTabPref = Services.prefs.getBoolPref(NEWTAB_CONTROLLED_PREF, false);
 | 
						|
  is(newTabPref, false, "the new tab is not controlled");
 | 
						|
 | 
						|
  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
 | 
						|
    addon.id,
 | 
						|
    NEW_TAB_KEY,
 | 
						|
    URL_OVERRIDES_TYPE
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    levelOfControl,
 | 
						|
    "not_controllable",
 | 
						|
    "getLevelOfControl returns not_controllable."
 | 
						|
  );
 | 
						|
  setting = ExtensionSettingsStore.getSetting(URL_OVERRIDES_TYPE, NEW_TAB_KEY);
 | 
						|
  ok(!setting.value, "The url_overrides is not set by this extension");
 | 
						|
 | 
						|
  promise = TestUtils.waitForPrefChange(NEWTAB_CONTROLLED_PREF);
 | 
						|
  // Set the menu to a the addon value
 | 
						|
  newTabMenuList.value = ADDON_ID;
 | 
						|
  newTabMenuList.dispatchEvent(new Event("command"));
 | 
						|
  await promise;
 | 
						|
  newTabPref = Services.prefs.getBoolPref(NEWTAB_CONTROLLED_PREF, false);
 | 
						|
  is(newTabPref, true, "the new tab is controlled");
 | 
						|
 | 
						|
  // Add a second extension, ensure it is added to the menulist and selected.
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => newTabMenuList.itemCount == 4,
 | 
						|
    "addon option is added as an option in the menu list"
 | 
						|
  );
 | 
						|
  let secondExtension = ExtensionTestUtils.loadExtension({
 | 
						|
    useAddonManager: "permanent",
 | 
						|
    manifest: {
 | 
						|
      version: "1.0",
 | 
						|
      name: "second_set_newtab",
 | 
						|
      applications: {
 | 
						|
        gecko: {
 | 
						|
          id: SECOND_ADDON_ID,
 | 
						|
        },
 | 
						|
      },
 | 
						|
      chrome_url_overrides: { newtab: "/newtab2.html" },
 | 
						|
    },
 | 
						|
  });
 | 
						|
  await secondExtension.startup();
 | 
						|
  await promise;
 | 
						|
  let secondAddon = await AddonManager.getAddonByID(SECOND_ADDON_ID);
 | 
						|
  is(
 | 
						|
    newTabMenuList.value,
 | 
						|
    SECOND_ADDON_ID,
 | 
						|
    "New tab menulist is set to the add-on"
 | 
						|
  );
 | 
						|
 | 
						|
  levelOfControl = await ExtensionPreferencesManager.getLevelOfControl(
 | 
						|
    secondAddon.id,
 | 
						|
    NEW_TAB_KEY,
 | 
						|
    URL_OVERRIDES_TYPE
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    levelOfControl,
 | 
						|
    "controlled_by_this_extension",
 | 
						|
    "getLevelOfControl returns controlled_by_this_extension."
 | 
						|
  );
 | 
						|
  setting = ExtensionSettingsStore.getSetting(URL_OVERRIDES_TYPE, NEW_TAB_KEY);
 | 
						|
  ok(
 | 
						|
    setting.value.startsWith("moz-extension") &&
 | 
						|
      setting.value.endsWith("newtab2.html"),
 | 
						|
    "The url_overrides is set by the second extension"
 | 
						|
  );
 | 
						|
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => newTabMenuList.itemCount == 3,
 | 
						|
    "addon option is no longer an option in the menu list after disable, even if it was not selected"
 | 
						|
  );
 | 
						|
  await addon.disable();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  // Ensure that re-enabling an addon adds it back to the menulist
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => newTabMenuList.itemCount == 4,
 | 
						|
    "addon option is added again to the menulist when enabled"
 | 
						|
  );
 | 
						|
  await addon.enable();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => newTabMenuList.itemCount == 3,
 | 
						|
    "addon option is no longer an option in the menu list after disable"
 | 
						|
  );
 | 
						|
  await secondAddon.disable();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => newTabMenuList.itemCount == 4,
 | 
						|
    "addon option is added again to the menulist when enabled"
 | 
						|
  );
 | 
						|
  await secondAddon.enable();
 | 
						|
  await promise;
 | 
						|
 | 
						|
  promise = TestUtils.waitForCondition(
 | 
						|
    () => newTabMenuList.itemCount == 2,
 | 
						|
    "addon options are all removed after disabling all"
 | 
						|
  );
 | 
						|
  await addon.disable();
 | 
						|
  await secondAddon.disable();
 | 
						|
  await promise;
 | 
						|
  is(
 | 
						|
    AboutNewTab.newTabURL,
 | 
						|
    DEFAULT_NEWTAB,
 | 
						|
    "new tab page is set back to default"
 | 
						|
  );
 | 
						|
 | 
						|
  // Cleanup the tabs and add-on.
 | 
						|
  BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
  await extension.unload();
 | 
						|
  await secondExtension.unload();
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function testExtensionControlledWebNotificationsPermission() {
 | 
						|
  let manifest = {
 | 
						|
    manifest_version: 2,
 | 
						|
    name: "TestExtension",
 | 
						|
    version: "1.0",
 | 
						|
    description: "Testing WebNotificationsDisable",
 | 
						|
    applications: { gecko: { id: "@web_notifications_disable" } },
 | 
						|
    permissions: ["browserSettings"],
 | 
						|
    browser_action: {
 | 
						|
      default_title: "Testing",
 | 
						|
    },
 | 
						|
  };
 | 
						|
 | 
						|
  await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
 | 
						|
  await openNotificationsPermissionDialog();
 | 
						|
 | 
						|
  let doc = sitePermissionsDialog.document;
 | 
						|
  let extensionControlledContent = doc.getElementById(
 | 
						|
    "browserNotificationsPermissionExtensionContent"
 | 
						|
  );
 | 
						|
 | 
						|
  // Test that extension content is initially hidden.
 | 
						|
  ok(
 | 
						|
    extensionControlledContent.hidden,
 | 
						|
    "Extension content is initially hidden"
 | 
						|
  );
 | 
						|
 | 
						|
  // Install an extension that will disable web notifications permission.
 | 
						|
  let messageShown = waitForMessageShown(
 | 
						|
    "browserNotificationsPermissionExtensionContent",
 | 
						|
    doc
 | 
						|
  );
 | 
						|
  let extension = ExtensionTestUtils.loadExtension({
 | 
						|
    manifest,
 | 
						|
    useAddonManager: "permanent",
 | 
						|
    background() {
 | 
						|
      browser.browserSettings.webNotificationsDisabled.set({ value: true });
 | 
						|
      browser.test.sendMessage("load-extension");
 | 
						|
    },
 | 
						|
  });
 | 
						|
  await extension.startup();
 | 
						|
  await extension.awaitMessage("load-extension");
 | 
						|
  await messageShown;
 | 
						|
 | 
						|
  let controlledDesc = extensionControlledContent.querySelector("description");
 | 
						|
  Assert.deepEqual(
 | 
						|
    doc.l10n.getAttributes(controlledDesc),
 | 
						|
    {
 | 
						|
      id: "extension-controlled-web-notifications",
 | 
						|
      args: {
 | 
						|
        name: "TestExtension",
 | 
						|
      },
 | 
						|
    },
 | 
						|
    "The user is notified that an extension is controlling the web notifications permission"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    extensionControlledContent.hidden,
 | 
						|
    false,
 | 
						|
    "The extension controlled row is not hidden"
 | 
						|
  );
 | 
						|
 | 
						|
  // Disable the extension.
 | 
						|
  doc.getElementById("disableNotificationsPermissionExtension").click();
 | 
						|
 | 
						|
  // Verify the user is notified how to enable the extension.
 | 
						|
  await waitForEnableMessage(extensionControlledContent.id, doc);
 | 
						|
  is(
 | 
						|
    doc.l10n.getAttributes(controlledDesc.querySelector("label")).id,
 | 
						|
    "extension-controlled-enable",
 | 
						|
    "The user is notified of how to enable the extension again"
 | 
						|
  );
 | 
						|
 | 
						|
  // Verify the enable message can be dismissed.
 | 
						|
  let hidden = waitForMessageHidden(extensionControlledContent.id, doc);
 | 
						|
  let dismissButton = controlledDesc.querySelector("image:last-of-type");
 | 
						|
  dismissButton.click();
 | 
						|
  await hidden;
 | 
						|
 | 
						|
  // Verify that the extension controlled content in hidden again.
 | 
						|
  is(
 | 
						|
    extensionControlledContent.hidden,
 | 
						|
    true,
 | 
						|
    "The extension controlled row is now hidden"
 | 
						|
  );
 | 
						|
 | 
						|
  await extension.unload();
 | 
						|
  BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function testExtensionControlledHomepageUninstalledAddon() {
 | 
						|
  async function checkHomepageEnabled() {
 | 
						|
    await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
 | 
						|
    let doc = gBrowser.contentDocument;
 | 
						|
    is(
 | 
						|
      gBrowser.currentURI.spec,
 | 
						|
      "about:preferences#home",
 | 
						|
      "#home should be in the URI for about:preferences"
 | 
						|
    );
 | 
						|
 | 
						|
    // The homepage is enabled.
 | 
						|
    let homepageInput = doc.getElementById("homePageUrl");
 | 
						|
    is(homepageInput.disabled, false, "The homepage input is enabled");
 | 
						|
    is(homepageInput.value, "", "The homepage input is empty");
 | 
						|
 | 
						|
    BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
  }
 | 
						|
 | 
						|
  await ExtensionSettingsStore.initialize();
 | 
						|
 | 
						|
  // Verify the setting isn't reported as controlled and the inputs are enabled.
 | 
						|
  is(
 | 
						|
    ExtensionSettingsStore.getSetting("prefs", "homepage_override"),
 | 
						|
    null,
 | 
						|
    "The homepage_override is not set"
 | 
						|
  );
 | 
						|
  await checkHomepageEnabled();
 | 
						|
 | 
						|
  // Disarm any pending writes before we modify the JSONFile directly.
 | 
						|
  await ExtensionSettingsStore._reloadFile(false);
 | 
						|
 | 
						|
  // Write out a bad store file.
 | 
						|
  let storeData = {
 | 
						|
    prefs: {
 | 
						|
      homepage_override: {
 | 
						|
        initialValue: "",
 | 
						|
        precedenceList: [
 | 
						|
          {
 | 
						|
            id: "bad@mochi.test",
 | 
						|
            installDate: 1508802672,
 | 
						|
            value: "https://developer.mozilla.org",
 | 
						|
            enabled: true,
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
    },
 | 
						|
  };
 | 
						|
  let jsonFileName = "extension-settings.json";
 | 
						|
  let storePath = PathUtils.join(await PathUtils.getProfileDir(), jsonFileName);
 | 
						|
 | 
						|
  await IOUtils.writeUTF8(storePath, JSON.stringify(storeData));
 | 
						|
 | 
						|
  // Reload the ExtensionSettingsStore so it will read the file on disk. Don't
 | 
						|
  // finalize the current store since it will overwrite our file.
 | 
						|
  await ExtensionSettingsStore._reloadFile(false);
 | 
						|
 | 
						|
  // Verify that the setting is reported as set, but the homepage is still enabled
 | 
						|
  // since there is no matching installed extension.
 | 
						|
  is(
 | 
						|
    ExtensionSettingsStore.getSetting("prefs", "homepage_override").value,
 | 
						|
    "https://developer.mozilla.org",
 | 
						|
    "The homepage_override appears to be set"
 | 
						|
  );
 | 
						|
  await checkHomepageEnabled();
 | 
						|
 | 
						|
  // Remove the bad store file that we used.
 | 
						|
  await IOUtils.remove(storePath);
 | 
						|
 | 
						|
  // Reload the ExtensionSettingsStore again so it clears the data we added.
 | 
						|
  // Don't finalize the current store since it will write out the bad data.
 | 
						|
  await ExtensionSettingsStore._reloadFile(false);
 | 
						|
 | 
						|
  is(
 | 
						|
    ExtensionSettingsStore.getSetting("prefs", "homepage_override"),
 | 
						|
    null,
 | 
						|
    "The ExtensionSettingsStore is left empty."
 | 
						|
  );
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function testExtensionControlledTrackingProtection() {
 | 
						|
  const TP_PREF = "privacy.trackingprotection.enabled";
 | 
						|
  const TP_DEFAULT = false;
 | 
						|
  const EXTENSION_ID = "@set_tp";
 | 
						|
  const CONTROLLED_LABEL_ID =
 | 
						|
    "contentBlockingTrackingProtectionExtensionContentLabel";
 | 
						|
  const CONTROLLED_BUTTON_ID =
 | 
						|
    "contentBlockingDisableTrackingProtectionExtension";
 | 
						|
 | 
						|
  let tpEnabledPref = () => Services.prefs.getBoolPref(TP_PREF);
 | 
						|
 | 
						|
  await SpecialPowers.pushPrefEnv({ set: [[TP_PREF, TP_DEFAULT]] });
 | 
						|
 | 
						|
  function background() {
 | 
						|
    browser.privacy.websites.trackingProtectionMode.set({ value: "always" });
 | 
						|
  }
 | 
						|
 | 
						|
  function verifyState(isControlled) {
 | 
						|
    is(tpEnabledPref(), isControlled, "TP pref is set to the expected value.");
 | 
						|
 | 
						|
    let controlledLabel = doc.getElementById(CONTROLLED_LABEL_ID);
 | 
						|
    let controlledButton = doc.getElementById(CONTROLLED_BUTTON_ID);
 | 
						|
 | 
						|
    is(
 | 
						|
      controlledLabel.hidden,
 | 
						|
      !isControlled,
 | 
						|
      "The extension controlled row's visibility is as expected."
 | 
						|
    );
 | 
						|
    is(
 | 
						|
      controlledButton.hidden,
 | 
						|
      !isControlled,
 | 
						|
      "The disable extension button's visibility is as expected."
 | 
						|
    );
 | 
						|
    if (isControlled) {
 | 
						|
      let controlledDesc = controlledLabel.querySelector("description");
 | 
						|
      Assert.deepEqual(
 | 
						|
        doc.l10n.getAttributes(controlledDesc),
 | 
						|
        {
 | 
						|
          id: "extension-controlled-websites-content-blocking-all-trackers",
 | 
						|
          args: {
 | 
						|
            name: "set_tp",
 | 
						|
          },
 | 
						|
        },
 | 
						|
        "The user is notified that an extension is controlling TP."
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    is(
 | 
						|
      doc.getElementById("trackingProtectionMenu").disabled,
 | 
						|
      isControlled,
 | 
						|
      "TP control is enabled."
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  await openPreferencesViaOpenPreferencesAPI("panePrivacy", {
 | 
						|
    leaveOpen: true,
 | 
						|
  });
 | 
						|
  let doc = gBrowser.contentDocument;
 | 
						|
 | 
						|
  is(
 | 
						|
    gBrowser.currentURI.spec,
 | 
						|
    "about:preferences#privacy",
 | 
						|
    "#privacy should be in the URI for about:preferences"
 | 
						|
  );
 | 
						|
 | 
						|
  verifyState(false);
 | 
						|
 | 
						|
  // Install an extension that sets Tracking Protection.
 | 
						|
  let extension = ExtensionTestUtils.loadExtension({
 | 
						|
    useAddonManager: "permanent",
 | 
						|
    manifest: {
 | 
						|
      name: "set_tp",
 | 
						|
      applications: { gecko: { id: EXTENSION_ID } },
 | 
						|
      permissions: ["privacy"],
 | 
						|
    },
 | 
						|
    background,
 | 
						|
  });
 | 
						|
 | 
						|
  let messageShown = waitForMessageShown(CONTROLLED_LABEL_ID);
 | 
						|
  await extension.startup();
 | 
						|
  await messageShown;
 | 
						|
  let addon = await AddonManager.getAddonByID(EXTENSION_ID);
 | 
						|
 | 
						|
  verifyState(true);
 | 
						|
 | 
						|
  await disableExtensionViaClick(
 | 
						|
    CONTROLLED_LABEL_ID,
 | 
						|
    CONTROLLED_BUTTON_ID,
 | 
						|
    doc
 | 
						|
  );
 | 
						|
 | 
						|
  verifyState(false);
 | 
						|
 | 
						|
  // Enable the extension so we get the UNINSTALL event, which is needed by
 | 
						|
  // ExtensionPreferencesManager to clean up properly.
 | 
						|
  // TODO: BUG 1408226
 | 
						|
  await reEnableExtension(addon, CONTROLLED_LABEL_ID);
 | 
						|
 | 
						|
  await extension.unload();
 | 
						|
 | 
						|
  BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function testExtensionControlledPasswordManager() {
 | 
						|
  const PASSWORD_MANAGER_ENABLED_PREF = "signon.rememberSignons";
 | 
						|
  const PASSWORD_MANAGER_ENABLED_DEFAULT = true;
 | 
						|
  const CONTROLLED_BUTTON_ID = "disablePasswordManagerExtension";
 | 
						|
  const CONTROLLED_LABEL_ID = "passwordManagerExtensionContent";
 | 
						|
  const EXTENSION_ID = "@remember_signons";
 | 
						|
  let manifest = {
 | 
						|
    manifest_version: 2,
 | 
						|
    name: "testPasswordManagerExtension",
 | 
						|
    version: "1.0",
 | 
						|
    description: "Testing rememberSignons",
 | 
						|
    applications: { gecko: { id: EXTENSION_ID } },
 | 
						|
    permissions: ["privacy"],
 | 
						|
    browser_action: {
 | 
						|
      default_title: "Testing rememberSignons",
 | 
						|
    },
 | 
						|
  };
 | 
						|
 | 
						|
  let passwordManagerEnabledPref = () =>
 | 
						|
    Services.prefs.getBoolPref(PASSWORD_MANAGER_ENABLED_PREF);
 | 
						|
 | 
						|
  await SpecialPowers.pushPrefEnv({
 | 
						|
    set: [[PASSWORD_MANAGER_ENABLED_PREF, PASSWORD_MANAGER_ENABLED_DEFAULT]],
 | 
						|
  });
 | 
						|
  is(
 | 
						|
    passwordManagerEnabledPref(),
 | 
						|
    true,
 | 
						|
    "Password manager is enabled by default."
 | 
						|
  );
 | 
						|
 | 
						|
  function verifyState(isControlled) {
 | 
						|
    is(
 | 
						|
      passwordManagerEnabledPref(),
 | 
						|
      !isControlled,
 | 
						|
      "Password manager pref is set to the expected value."
 | 
						|
    );
 | 
						|
    let controlledLabel = gBrowser.contentDocument.getElementById(
 | 
						|
      CONTROLLED_LABEL_ID
 | 
						|
    );
 | 
						|
    let controlledButton = gBrowser.contentDocument.getElementById(
 | 
						|
      CONTROLLED_BUTTON_ID
 | 
						|
    );
 | 
						|
    is(
 | 
						|
      controlledLabel.hidden,
 | 
						|
      !isControlled,
 | 
						|
      "The extension's controlled row visibility is as expected."
 | 
						|
    );
 | 
						|
    is(
 | 
						|
      controlledButton.hidden,
 | 
						|
      !isControlled,
 | 
						|
      "The extension's controlled button visibility is as expected."
 | 
						|
    );
 | 
						|
    if (isControlled) {
 | 
						|
      let controlledDesc = controlledLabel.querySelector("description");
 | 
						|
      Assert.deepEqual(
 | 
						|
        gBrowser.contentDocument.l10n.getAttributes(controlledDesc),
 | 
						|
        {
 | 
						|
          id: "extension-controlled-password-saving",
 | 
						|
          args: {
 | 
						|
            name: "testPasswordManagerExtension",
 | 
						|
          },
 | 
						|
        },
 | 
						|
        "The user is notified that an extension is controlling the remember signons pref."
 | 
						|
      );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  await openPreferencesViaOpenPreferencesAPI("panePrivacy", {
 | 
						|
    leaveOpen: true,
 | 
						|
  });
 | 
						|
 | 
						|
  info("Verify that no extension is controlling the password manager pref.");
 | 
						|
  verifyState(false);
 | 
						|
 | 
						|
  let extension = ExtensionTestUtils.loadExtension({
 | 
						|
    manifest,
 | 
						|
    useAddonManager: "permanent",
 | 
						|
    background() {
 | 
						|
      browser.privacy.services.passwordSavingEnabled.set({ value: false });
 | 
						|
    },
 | 
						|
  });
 | 
						|
  let messageShown = waitForMessageShown(CONTROLLED_LABEL_ID);
 | 
						|
  await extension.startup();
 | 
						|
  await messageShown;
 | 
						|
 | 
						|
  info(
 | 
						|
    "Verify that the test extension is controlling the password manager pref."
 | 
						|
  );
 | 
						|
  verifyState(true);
 | 
						|
 | 
						|
  info("Verify that the extension shows as controlled when loaded again.");
 | 
						|
  BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
  await openPreferencesViaOpenPreferencesAPI("panePrivacy", {
 | 
						|
    leaveOpen: true,
 | 
						|
  });
 | 
						|
  verifyState(true);
 | 
						|
 | 
						|
  await disableExtensionViaClick(
 | 
						|
    CONTROLLED_LABEL_ID,
 | 
						|
    CONTROLLED_BUTTON_ID,
 | 
						|
    gBrowser.contentDocument
 | 
						|
  );
 | 
						|
 | 
						|
  info(
 | 
						|
    "Verify that disabling the test extension removes the lock on the password manager pref."
 | 
						|
  );
 | 
						|
  verifyState(false);
 | 
						|
 | 
						|
  await extension.unload();
 | 
						|
 | 
						|
  BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function testExtensionControlledProxyConfig() {
 | 
						|
  const proxySvc = Ci.nsIProtocolProxyService;
 | 
						|
  const PROXY_DEFAULT = proxySvc.PROXYCONFIG_SYSTEM;
 | 
						|
  const EXTENSION_ID = "@set_proxy";
 | 
						|
  const CONTROLLED_SECTION_ID = "proxyExtensionContent";
 | 
						|
  const CONTROLLED_BUTTON_ID = "disableProxyExtension";
 | 
						|
  const CONNECTION_SETTINGS_DESC_ID = "connectionSettingsDescription";
 | 
						|
  const PANEL_URL =
 | 
						|
    "chrome://browser/content/preferences/dialogs/connection.xhtml";
 | 
						|
 | 
						|
  await SpecialPowers.pushPrefEnv({ set: [[PROXY_PREF, PROXY_DEFAULT]] });
 | 
						|
 | 
						|
  function background() {
 | 
						|
    browser.proxy.settings.set({ value: { proxyType: "none" } });
 | 
						|
  }
 | 
						|
 | 
						|
  function expectedConnectionSettingsMessage(doc, isControlled) {
 | 
						|
    return isControlled
 | 
						|
      ? "extension-controlled-proxy-config"
 | 
						|
      : "network-proxy-connection-description";
 | 
						|
  }
 | 
						|
 | 
						|
  function connectionSettingsMessagePromise(doc, isControlled) {
 | 
						|
    return waitForMessageContent(
 | 
						|
      CONNECTION_SETTINGS_DESC_ID,
 | 
						|
      expectedConnectionSettingsMessage(doc, isControlled),
 | 
						|
      doc
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  function verifyProxyState(doc, isControlled) {
 | 
						|
    let isPanel = doc.getElementById(CONTROLLED_BUTTON_ID);
 | 
						|
    is(
 | 
						|
      proxyType === proxySvc.PROXYCONFIG_DIRECT,
 | 
						|
      isControlled,
 | 
						|
      "Proxy pref is set to the expected value."
 | 
						|
    );
 | 
						|
 | 
						|
    if (isPanel) {
 | 
						|
      let controlledSection = doc.getElementById(CONTROLLED_SECTION_ID);
 | 
						|
 | 
						|
      is(
 | 
						|
        controlledSection.hidden,
 | 
						|
        !isControlled,
 | 
						|
        "The extension controlled row's visibility is as expected."
 | 
						|
      );
 | 
						|
      if (isPanel) {
 | 
						|
        is(
 | 
						|
          doc.getElementById(CONTROLLED_BUTTON_ID).hidden,
 | 
						|
          !isControlled,
 | 
						|
          "The disable extension button's visibility is as expected."
 | 
						|
        );
 | 
						|
      }
 | 
						|
      if (isControlled) {
 | 
						|
        let controlledDesc = controlledSection.querySelector("description");
 | 
						|
        Assert.deepEqual(
 | 
						|
          doc.l10n.getAttributes(controlledDesc),
 | 
						|
          {
 | 
						|
            id: "extension-controlled-proxy-config",
 | 
						|
            args: {
 | 
						|
              name: "set_proxy",
 | 
						|
            },
 | 
						|
          },
 | 
						|
          "The user is notified that an extension is controlling proxy settings."
 | 
						|
        );
 | 
						|
      }
 | 
						|
      function getProxyControls() {
 | 
						|
        let controlGroup = doc.getElementById("networkProxyType");
 | 
						|
        let manualControlContainer = controlGroup.querySelector("#proxy-grid");
 | 
						|
        return {
 | 
						|
          manualControls: [
 | 
						|
            ...manualControlContainer.querySelectorAll(
 | 
						|
              "label[data-l10n-id]:not([control=networkProxyNone])"
 | 
						|
            ),
 | 
						|
            ...manualControlContainer.querySelectorAll("input"),
 | 
						|
            ...manualControlContainer.querySelectorAll("checkbox"),
 | 
						|
            ...doc.querySelectorAll("#networkProxySOCKSVersion > radio"),
 | 
						|
          ],
 | 
						|
          pacControls: [doc.getElementById("networkProxyAutoconfigURL")],
 | 
						|
          otherControls: [
 | 
						|
            doc.querySelector("label[control=networkProxyNone]"),
 | 
						|
            doc.getElementById("networkProxyNone"),
 | 
						|
            ...controlGroup.querySelectorAll(":scope > radio"),
 | 
						|
            ...doc.querySelectorAll("#ConnectionsDialogPane > checkbox"),
 | 
						|
          ],
 | 
						|
        };
 | 
						|
      }
 | 
						|
      let controlState = isControlled ? "disabled" : "enabled";
 | 
						|
      let controls = getProxyControls();
 | 
						|
      for (let element of controls.manualControls) {
 | 
						|
        let disabled =
 | 
						|
          isControlled || proxyType !== proxySvc.PROXYCONFIG_MANUAL;
 | 
						|
        is(
 | 
						|
          element.disabled,
 | 
						|
          disabled,
 | 
						|
          `Manual proxy controls should be ${controlState} - control: ${element.outerHTML}.`
 | 
						|
        );
 | 
						|
      }
 | 
						|
      for (let element of controls.pacControls) {
 | 
						|
        let disabled = isControlled || proxyType !== proxySvc.PROXYCONFIG_PAC;
 | 
						|
        is(
 | 
						|
          element.disabled,
 | 
						|
          disabled,
 | 
						|
          `PAC proxy controls should be ${controlState} - control: ${element.outerHTML}.`
 | 
						|
        );
 | 
						|
      }
 | 
						|
      for (let element of controls.otherControls) {
 | 
						|
        is(
 | 
						|
          element.disabled,
 | 
						|
          isControlled,
 | 
						|
          `Other proxy controls should be ${controlState} - control: ${element.outerHTML}.`
 | 
						|
        );
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      let elem = doc.getElementById(CONNECTION_SETTINGS_DESC_ID);
 | 
						|
      is(
 | 
						|
        doc.l10n.getAttributes(elem).id,
 | 
						|
        expectedConnectionSettingsMessage(doc, isControlled),
 | 
						|
        "The connection settings description is as expected."
 | 
						|
      );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  async function reEnableProxyExtension(addon) {
 | 
						|
    let messageChanged = connectionSettingsMessagePromise(mainDoc, true);
 | 
						|
    await addon.enable();
 | 
						|
    await messageChanged;
 | 
						|
  }
 | 
						|
 | 
						|
  async function openProxyPanel() {
 | 
						|
    let panel = await openAndLoadSubDialog(PANEL_URL);
 | 
						|
    let closingPromise = BrowserTestUtils.waitForEvent(
 | 
						|
      panel.document.getElementById("ConnectionsDialog"),
 | 
						|
      "dialogclosing"
 | 
						|
    );
 | 
						|
    ok(panel, "Proxy panel opened.");
 | 
						|
    return { panel, closingPromise };
 | 
						|
  }
 | 
						|
 | 
						|
  async function closeProxyPanel(panelObj) {
 | 
						|
    let dialog = panelObj.panel.document.getElementById("ConnectionsDialog");
 | 
						|
    dialog.cancelDialog();
 | 
						|
    let panelClosingEvent = await panelObj.closingPromise;
 | 
						|
    ok(panelClosingEvent, "Proxy panel closed.");
 | 
						|
  }
 | 
						|
 | 
						|
  await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
 | 
						|
    leaveOpen: true,
 | 
						|
  });
 | 
						|
  let mainDoc = gBrowser.contentDocument;
 | 
						|
 | 
						|
  is(
 | 
						|
    gBrowser.currentURI.spec,
 | 
						|
    "about:preferences#general",
 | 
						|
    "#general should be in the URI for about:preferences"
 | 
						|
  );
 | 
						|
 | 
						|
  verifyProxyState(mainDoc, false);
 | 
						|
 | 
						|
  // Open the connections panel.
 | 
						|
  let panelObj = await openProxyPanel();
 | 
						|
  let panelDoc = panelObj.panel.document;
 | 
						|
 | 
						|
  verifyProxyState(panelDoc, false);
 | 
						|
 | 
						|
  await closeProxyPanel(panelObj);
 | 
						|
 | 
						|
  verifyProxyState(mainDoc, false);
 | 
						|
 | 
						|
  // Install an extension that controls proxy settings. The extension needs
 | 
						|
  // incognitoOverride because controlling the proxy.settings requires private
 | 
						|
  // browsing access.
 | 
						|
  let extension = ExtensionTestUtils.loadExtension({
 | 
						|
    incognitoOverride: "spanning",
 | 
						|
    useAddonManager: "permanent",
 | 
						|
    manifest: {
 | 
						|
      name: "set_proxy",
 | 
						|
      applications: { gecko: { id: EXTENSION_ID } },
 | 
						|
      permissions: ["proxy"],
 | 
						|
    },
 | 
						|
    background,
 | 
						|
  });
 | 
						|
 | 
						|
  let messageChanged = connectionSettingsMessagePromise(mainDoc, true);
 | 
						|
  await extension.startup();
 | 
						|
  await messageChanged;
 | 
						|
  let addon = await AddonManager.getAddonByID(EXTENSION_ID);
 | 
						|
 | 
						|
  verifyProxyState(mainDoc, true);
 | 
						|
  messageChanged = connectionSettingsMessagePromise(mainDoc, false);
 | 
						|
 | 
						|
  panelObj = await openProxyPanel();
 | 
						|
  panelDoc = panelObj.panel.document;
 | 
						|
 | 
						|
  verifyProxyState(panelDoc, true);
 | 
						|
 | 
						|
  await disableExtensionViaClick(
 | 
						|
    CONTROLLED_SECTION_ID,
 | 
						|
    CONTROLLED_BUTTON_ID,
 | 
						|
    panelDoc
 | 
						|
  );
 | 
						|
 | 
						|
  verifyProxyState(panelDoc, false);
 | 
						|
 | 
						|
  await closeProxyPanel(panelObj);
 | 
						|
  await messageChanged;
 | 
						|
 | 
						|
  verifyProxyState(mainDoc, false);
 | 
						|
 | 
						|
  await reEnableProxyExtension(addon);
 | 
						|
 | 
						|
  verifyProxyState(mainDoc, true);
 | 
						|
  messageChanged = connectionSettingsMessagePromise(mainDoc, false);
 | 
						|
 | 
						|
  panelObj = await openProxyPanel();
 | 
						|
  panelDoc = panelObj.panel.document;
 | 
						|
 | 
						|
  verifyProxyState(panelDoc, true);
 | 
						|
 | 
						|
  await disableExtensionViaClick(
 | 
						|
    CONTROLLED_SECTION_ID,
 | 
						|
    CONTROLLED_BUTTON_ID,
 | 
						|
    panelDoc
 | 
						|
  );
 | 
						|
 | 
						|
  verifyProxyState(panelDoc, false);
 | 
						|
 | 
						|
  await closeProxyPanel(panelObj);
 | 
						|
  await messageChanged;
 | 
						|
 | 
						|
  verifyProxyState(mainDoc, false);
 | 
						|
 | 
						|
  // Enable the extension so we get the UNINSTALL event, which is needed by
 | 
						|
  // ExtensionPreferencesManager to clean up properly.
 | 
						|
  // TODO: BUG 1408226
 | 
						|
  await reEnableProxyExtension(addon);
 | 
						|
 | 
						|
  await extension.unload();
 | 
						|
 | 
						|
  BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
});
 | 
						|
 | 
						|
// Test that the newtab menu selection is correct when loading about:preferences
 | 
						|
add_task(async function testMenuSyncFromPrefs() {
 | 
						|
  const DEFAULT_NEWTAB = "about:newtab";
 | 
						|
 | 
						|
  await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
 | 
						|
  is(
 | 
						|
    gBrowser.currentURI.spec,
 | 
						|
    "about:preferences#home",
 | 
						|
    "#home should be in the URI for about:preferences"
 | 
						|
  );
 | 
						|
 | 
						|
  let doc = gBrowser.contentDocument;
 | 
						|
  let newTabMenuList = doc.getElementById("newTabMode");
 | 
						|
  // The new tab page is set to the default.
 | 
						|
  is(AboutNewTab.newTabURL, DEFAULT_NEWTAB, "new tab is set to default");
 | 
						|
 | 
						|
  is(newTabMenuList.value, "0", "New tab menulist is set to the default");
 | 
						|
 | 
						|
  newTabMenuList.value = "1";
 | 
						|
  newTabMenuList.dispatchEvent(new Event("command"));
 | 
						|
  is(newTabMenuList.value, "1", "New tab menulist is set to blank");
 | 
						|
 | 
						|
  gBrowser.reloadTab(gBrowser.selectedTab);
 | 
						|
 | 
						|
  await TestUtils.waitForCondition(
 | 
						|
    () => gBrowser.contentDocument.getElementById("newTabMode"),
 | 
						|
    "wait until element exists in new contentDoc"
 | 
						|
  );
 | 
						|
 | 
						|
  is(
 | 
						|
    gBrowser.contentDocument.getElementById("newTabMode").value,
 | 
						|
    "1",
 | 
						|
    "New tab menulist is still set to blank"
 | 
						|
  );
 | 
						|
 | 
						|
  // Cleanup
 | 
						|
  newTabMenuList.value = "0";
 | 
						|
  newTabMenuList.dispatchEvent(new Event("command"));
 | 
						|
  is(AboutNewTab.newTabURL, DEFAULT_NEWTAB, "new tab is set to default");
 | 
						|
  BrowserTestUtils.removeTab(gBrowser.selectedTab);
 | 
						|
});
 |