forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			1442 lines
		
	
	
	
		
			43 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1442 lines
		
	
	
	
		
			43 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.defineESModuleGetters(this, {
 | |
|   AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs",
 | |
|   ExtensionSettingsStore:
 | |
|     "resource://gre/modules/ExtensionSettingsStore.sys.mjs",
 | |
| });
 | |
| 
 | |
| XPCOMUtils.defineLazyPreferenceGetter(this, "proxyType", PROXY_PREF);
 | |
| 
 | |
| const { AddonTestUtils } = ChromeUtils.importESModule(
 | |
|   "resource://testing-common/AddonTestUtils.sys.mjs"
 | |
| );
 | |
| AddonTestUtils.initMochitest(this);
 | |
| 
 | |
| const { ExtensionPreferencesManager } = ChromeUtils.importESModule(
 | |
|   "resource://gre/modules/ExtensionPreferencesManager.sys.mjs"
 | |
| );
 | |
| 
 | |
| 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",
 | |
|       browser_specific_settings: {
 | |
|         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",
 | |
|       browser_specific_settings: {
 | |
|         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",
 | |
|       browser_specific_settings: {
 | |
|         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",
 | |
|       browser_specific_settings: {
 | |
|         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",
 | |
|       browser_specific_settings: {
 | |
|         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",
 | |
|     browser_specific_settings: { 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-controlling-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(PathUtils.profileDir, 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-controlling-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",
 | |
|       browser_specific_settings: { 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",
 | |
|     browser_specific_settings: { 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-controlling-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-controlling-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-controlling-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",
 | |
|       browser_specific_settings: { 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);
 | |
| });
 | 
