Bug 1551490 - Fix browser_reinstall.js with HTML about:addons. r=robwu, a=test-only
authorLuca Greco <lgreco@mozilla.com>
Mon, 10 Jun 2019 00:03:42 +0000
changeset 536906 466fe0fc7db3f5d4d740ff388c15aa7dc9eff14b
parent 536905 82e6701f5dbbead6f5c610020fce9b3d62b8ab65
child 536907 a2fc7a9510bdc4d1f18cae3f1938a79c9a8e0c67
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrobwu, test-only
bugs1551490
milestone68.0
Bug 1551490 - Fix browser_reinstall.js with HTML about:addons. r=robwu, a=test-only Differential Revision: https://phabricator.services.mozilla.com/D31496
toolkit/mozapps/extensions/test/browser/browser_reinstall.js
toolkit/mozapps/extensions/test/browser/browser_updateid.js
toolkit/mozapps/extensions/test/browser/head.js
--- a/toolkit/mozapps/extensions/test/browser/browser_reinstall.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_reinstall.js
@@ -3,159 +3,319 @@
  */
 
 // Tests that upgrading bootstrapped add-ons behaves correctly while the
 // manager is open
 
 const {AddonTestUtils} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
 
 const ID = "reinstall@tests.mozilla.org";
+const testIdSuffix = "@tests.mozilla.org";
 
 let gManagerWindow, xpi1, xpi2;
 
+function get_test_items_in_list(aManager) {
+  let item = aManager.document.getElementById("addon-list").firstChild;
+  let items = [];
+
+  while (item) {
+    if (item.localName != "richlistitem") {
+      item = item.nextSibling;
+      continue;
+    }
+
+    if (!item.mAddon || item.mAddon.id.substring(item.mAddon.id.length - testIdSuffix.length) == testIdSuffix)
+      items.push(item);
+    item = item.nextSibling;
+  }
+
+  return items;
+}
+
+function htmlDoc() {
+  return gManagerWindow.document.getElementById("html-view-browser").contentDocument;
+}
+
 function get_list_item_count() {
+  if (gManagerWindow.useHtmlViews) {
+    return htmlDoc()
+      .querySelectorAll(`addon-card[addon-id$="${testIdSuffix}"]`)
+      .length;
+  }
   return get_test_items_in_list(gManagerWindow).length;
 }
 
 function get_node(parent, anonid) {
   return parent.ownerDocument.getAnonymousElementByAttribute(parent, "anonid", anonid);
 }
 
+function removeItem(item) {
+  let button;
+  if (gManagerWindow.useHtmlViews) {
+    button = item.querySelector('[action="remove"]');
+    button.click();
+  } else {
+    button = get_node(item, "remove-btn");
+    EventUtils.synthesizeMouseAtCenter(button, { }, button.ownerGlobal);
+  }
+}
+
 function get_class_node(parent, cls) {
   return parent.ownerDocument.getAnonymousElementByAttribute(parent, "class", cls);
 }
 
+function hasPendingMessage(item, msg) {
+  if (gManagerWindow.useHtmlViews) {
+    let messageBar = htmlDoc().querySelector(`message-bar[addon-id="${item.addon.id}"`);
+    is_element_visible(messageBar, msg);
+  } else {
+    is_element_visible(get_class_node(item, "pending"), msg);
+  }
+}
+
 async function install_addon(xpi) {
   let install = await AddonManager.getInstallForFile(xpi, "application/x-xpinstall");
   return install.install();
 }
 
-var check_addon = async function(aAddon, aVersion) {
+async function check_addon(aAddon, aVersion) {
   is(get_list_item_count(), 1, "Should be one item in the list");
   is(aAddon.version, aVersion, "Add-on should have the right version");
 
   let item = get_addon_element(gManagerWindow, ID);
   ok(!!item, "Should see the add-on in the list");
 
   // Force XBL to apply
   item.clientTop;
 
-  let { version } = await get_tooltip_info(item);
+  let { version } = await get_tooltip_info(item, gManagerWindow);
   is(version, aVersion, "Version should be correct");
 
-  if (aAddon.userDisabled)
+  if (gManagerWindow.useHtmlViews) {
+    const l10nAttrs = item.ownerDocument.l10n.getAttributes(item.querySelector(".addon-name"));
+    if (aAddon.userDisabled) {
+      Assert.deepEqual(l10nAttrs, {id: "addon-name-disabled", args: {name: aAddon.name}},
+                       "localized addon name is marked as disabled");
+     } else {
+       Assert.deepEqual(l10nAttrs, {id: null, args: null},
+                        "localized addon name is not marked as disabled");
+    }
+
+    return;
+  }
+
+  if (aAddon.userDisabled) {
     is_element_visible(get_class_node(item, "disabled-postfix"), "Disabled postfix should be hidden");
-  else
+  } else {
     is_element_hidden(get_class_node(item, "disabled-postfix"), "Disabled postfix should be hidden");
-};
+  }
+}
+
+async function wait_for_addon_item_added(addonId) {
+  if (gManagerWindow.useHtmlViews) {
+    await BrowserTestUtils.waitForEvent(htmlDoc().querySelector("addon-list"), "add");
+    const item = get_addon_element(gManagerWindow, addonId);
+    ok(item, `Found addon card for ${addonId}`);
+  }
+}
+
+async function wait_for_addon_item_removed(addonId) {
+  if (gManagerWindow.useHtmlViews) {
+    await BrowserTestUtils.waitForEvent(htmlDoc().querySelector("addon-list"), "remove");
+    const item = get_addon_element(gManagerWindow, addonId);
+    ok(!item, `There shouldn't be an addon card for ${addonId}`);
+  }
+}
+
+async function wait_for_addon_item_updated(addonId) {
+  if (gManagerWindow.useHtmlViews) {
+    await BrowserTestUtils.waitForEvent(get_addon_element(gManagerWindow, addonId), "update");
+  }
+}
+
+// Install version 1 then upgrade to version 2 with the manager open
+async function test_upgrade_v1_to_v2() {
+  let promiseItemAdded = wait_for_addon_item_added(ID);
+  await install_addon(xpi1);
+  await promiseItemAdded;
+
+  let addon = await promiseAddonByID(ID);
+  await check_addon(addon, "1.0");
+  ok(!addon.userDisabled, "Add-on should not be disabled");
+
+  let promiseItemUpdated = wait_for_addon_item_updated(ID);
+  await install_addon(xpi2);
+  await promiseItemUpdated;
+
+  addon = await promiseAddonByID(ID);
+  await check_addon(addon, "2.0");
+  ok(!addon.userDisabled, "Add-on should not be disabled");
+
+  let promiseItemRemoved = wait_for_addon_item_removed(ID);
+  await addon.uninstall();
+  await promiseItemRemoved;
+
+  is(get_list_item_count(), 0, "Should be no items in the list");
+}
+
+// Install version 1 mark it as disabled then upgrade to version 2 with the
+// manager open
+async function test_upgrade_disabled_v1_to_v2() {
+  let promiseItemAdded = wait_for_addon_item_added(ID);
+  await install_addon(xpi1);
+  await promiseItemAdded;
+
+  let promiseItemUpdated = wait_for_addon_item_updated(ID);
+  let addon = await promiseAddonByID(ID);
+  await addon.disable();
+  await promiseItemUpdated;
+
+  await check_addon(addon, "1.0");
+  ok(addon.userDisabled, "Add-on should be disabled");
+
+  promiseItemUpdated = wait_for_addon_item_updated(ID);
+  await install_addon(xpi2);
+  await promiseItemUpdated;
+
+  addon = await promiseAddonByID(ID);
+  await check_addon(addon, "2.0");
+  ok(addon.userDisabled, "Add-on should be disabled");
+
+  let promiseItemRemoved = wait_for_addon_item_removed(ID);
+  await addon.uninstall();
+  await promiseItemRemoved;
+
+  is(get_list_item_count(), 0, "Should be no items in the list");
+}
+
+// Install version 1 click the remove button and then upgrade to version 2 with
+// the manager open
+async function test_upgrade_pending_uninstall_v1_to_v2() {
+  let promiseItemAdded = wait_for_addon_item_added(ID);
+  await install_addon(xpi1);
+  await promiseItemAdded;
+
+  let addon = await promiseAddonByID(ID);
+  await check_addon(addon, "1.0");
+  ok(!addon.userDisabled, "Add-on should not be disabled");
+
+  let item = get_addon_element(gManagerWindow, ID);
+
+  let promiseItemRemoved = wait_for_addon_item_removed(ID);
+  removeItem(item);
+
+  // Force XBL to apply
+  item.clientTop;
+
+  await promiseItemRemoved;
+
+  ok(!!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+  hasPendingMessage(item, "Pending message should be visible");
+
+  promiseItemAdded = wait_for_addon_item_added(ID);
+  await install_addon(xpi2);
+  await promiseItemAdded;
+
+  addon = await promiseAddonByID(ID);
+  await check_addon(addon, "2.0");
+  ok(!addon.userDisabled, "Add-on should not be disabled");
+
+  promiseItemRemoved = wait_for_addon_item_removed(ID);
+  await addon.uninstall();
+  await promiseItemRemoved;
+
+  is(get_list_item_count(), 0, "Should be no items in the list");
+}
+
+// Install version 1, disable it, click the remove button and then upgrade to
+// version 2 with the manager open
+async function test_upgrade_pending_uninstall_disabled_v1_to_v2() {
+  let promiseItemAdded = wait_for_addon_item_added(ID);
+  await install_addon(xpi1);
+  await promiseItemAdded;
+
+  let promiseItemUpdated = wait_for_addon_item_updated(ID);
+  let addon = await promiseAddonByID(ID);
+  await addon.disable();
+  await promiseItemUpdated;
+
+  await check_addon(addon, "1.0");
+  ok(addon.userDisabled, "Add-on should be disabled");
+
+  let item = get_addon_element(gManagerWindow, ID);
+
+  let promiseItemRemoved = wait_for_addon_item_removed(ID);
+  removeItem(item);
+
+  // Force XBL to apply
+  item.clientTop;
+
+  await promiseItemRemoved;
+  ok(!!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+  hasPendingMessage(item, "Pending message should be visible");
+
+  promiseItemAdded = wait_for_addon_item_added(ID);
+  await install_addon(xpi2);
+  addon = await promiseAddonByID(ID);
+
+  await promiseItemAdded;
+  await check_addon(addon, "2.0");
+  ok(addon.userDisabled, "Add-on should be disabled");
+
+  promiseItemRemoved = wait_for_addon_item_removed(ID);
+  await addon.uninstall();
+  await promiseItemRemoved;
+
+  is(get_list_item_count(), 0, "Should be no items in the list");
+}
+
+async function test_upgrades(useHtmlViews) {
+  await SpecialPowers.pushPrefEnv({
+    set: [["extensions.htmlaboutaddons.enabled", useHtmlViews]],
+  });
+
+  // Close existing about:addons tab if a test failure has
+  // prevented it from being closed.
+  if (gManagerWindow) {
+    await close_manager(gManagerWindow);
+  }
+
+  gManagerWindow = await open_manager("addons://list/extension");
+  is(gManagerWindow.useHtmlViews, useHtmlViews,
+     "Got about:addons window in the expected mode");
+
+  await test_upgrade_v1_to_v2();
+  await test_upgrade_disabled_v1_to_v2();
+  await test_upgrade_pending_uninstall_v1_to_v2();
+  await test_upgrade_pending_uninstall_disabled_v1_to_v2();
+
+  await close_manager(gManagerWindow);
+  gManagerWindow = null;
+
+  // No popPrefEnv because of bug 1557397.
+}
 
 add_task(async function setup() {
-  gManagerWindow = await open_manager("addons://list/extension");
-
   xpi1 = await AddonTestUtils.createTempWebExtensionFile({
     manifest: {
       version: "1.0",
       applications: {gecko: {id: ID}},
     },
   });
 
   xpi2 = await AddonTestUtils.createTempWebExtensionFile({
     manifest: {
       version: "2.0",
       applications: {gecko: {id: ID}},
     },
   });
-});
 
-// Install version 1 then upgrade to version 2 with the manager open
-add_task(async function() {
-  await install_addon(xpi1);
-  let addon = await promiseAddonByID(ID);
-  await check_addon(addon, "1.0");
-  ok(!addon.userDisabled, "Add-on should not be disabled");
-
-  await install_addon(xpi2);
-  addon = await promiseAddonByID(ID);
-  await check_addon(addon, "2.0");
-  ok(!addon.userDisabled, "Add-on should not be disabled");
-
-  await addon.uninstall();
-
-  is(get_list_item_count(), 0, "Should be no items in the list");
-});
-
-// Install version 1 mark it as disabled then upgrade to version 2 with the
-// manager open
-add_task(async function() {
-  await install_addon(xpi1);
-  let addon = await promiseAddonByID(ID);
-  await addon.disable();
-  await check_addon(addon, "1.0");
-  ok(addon.userDisabled, "Add-on should be disabled");
-
-  await install_addon(xpi2);
-  addon = await promiseAddonByID(ID);
-  await check_addon(addon, "2.0");
-  ok(addon.userDisabled, "Add-on should be disabled");
-
-  await addon.uninstall();
-
-  is(get_list_item_count(), 0, "Should be no items in the list");
+  // Accept all prompts.
+  mockPromptService()._response = 0;
 });
 
-// Install version 1 click the remove button and then upgrade to version 2 with
-// the manager open
-add_task(async function() {
-  await install_addon(xpi1);
-  let addon = await promiseAddonByID(ID);
-  await check_addon(addon, "1.0");
-  ok(!addon.userDisabled, "Add-on should not be disabled");
-
-  let item = get_addon_element(gManagerWindow, ID);
-  EventUtils.synthesizeMouseAtCenter(get_node(item, "remove-btn"), { }, gManagerWindow);
-
-  // Force XBL to apply
-  item.clientTop;
-
-  ok(!!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
-  is_element_visible(get_class_node(item, "pending"), "Pending message should be visible");
-
-  await install_addon(xpi2);
-  addon = await promiseAddonByID(ID);
-  await check_addon(addon, "2.0");
-  ok(!addon.userDisabled, "Add-on should not be disabled");
-
-  await addon.uninstall();
-
-  is(get_list_item_count(), 0, "Should be no items in the list");
+add_task(function run_tests_on_XUL_aboutaddons() {
+  return test_upgrades(false);
 });
 
-// Install version 1, disable it, click the remove button and then upgrade to
-// version 2 with the manager open
-add_task(async function() {
-  await install_addon(xpi1);
-  let addon = await promiseAddonByID(ID);
-  await addon.disable();
-  await check_addon(addon, "1.0");
-  ok(addon.userDisabled, "Add-on should be disabled");
-
-  let item = get_addon_element(gManagerWindow, ID);
-  EventUtils.synthesizeMouseAtCenter(get_node(item, "remove-btn"), { }, gManagerWindow);
-
-  // Force XBL to apply
-  item.clientTop;
-
-  ok(!!(addon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
-  is_element_visible(get_class_node(item, "pending"), "Pending message should be visible");
-
-  await install_addon(xpi2);
-  addon = await promiseAddonByID(ID);
-  await check_addon(addon, "2.0");
-  ok(addon.userDisabled, "Add-on should be disabled");
-
-  await addon.uninstall();
-
-  is(get_list_item_count(), 0, "Should be no items in the list");
+add_task(function run_tests_on_HTML_aboutaddons() {
+  return test_upgrades(true);
 });
-
-add_task(function end_test() {
-  return close_manager(gManagerWindow);
-});
--- a/toolkit/mozapps/extensions/test/browser/browser_updateid.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_updateid.js
@@ -3,60 +3,98 @@
  */
 
 // Tests that updates that change an add-on's ID show up correctly in the UI
 
 var gProvider;
 var gManagerWindow;
 var gCategoryUtilities;
 
-async function test() {
-  waitForExplicitFinish();
+function getName(item) {
+  if (gManagerWindow.useHtmlViews) {
+    return item.querySelector(".addon-name").textContent;
+  }
+  return gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "name").textContent;
+}
+
+async function getUpdateButton(item) {
+  if (gManagerWindow.useHtmlViews) {
+    let button = item.querySelector('[action="install-update"]');
+    let panel = button.closest("panel-list");
+    let shown = BrowserTestUtils.waitForEvent(panel, "shown");
+    panel.show();
+    await shown;
+    return button;
+  }
+  return gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "update-btn");
+}
+
+async function test_updateid() {
+  // Close the existing about:addons tab and unrestier the existing MockProvider
+  // instance if a previous failed test has not been able to clear them.
+  if (gManagerWindow) {
+    await close_manager(gManagerWindow);
+  }
+  if (gProvider) {
+    gProvider.unregister();
+  }
 
   gProvider = new MockProvider();
 
   gProvider.createAddons([{
     id: "addon1@tests.mozilla.org",
     name: "manually updating addon",
     version: "1.0",
     applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
   }]);
 
-  let aWindow = await open_manager("addons://list/extension");
-  gManagerWindow = aWindow;
+  gManagerWindow = await open_manager("addons://list/extension");
   gCategoryUtilities = new CategoryUtilities(gManagerWindow);
-  run_next_test();
-}
+  await gCategoryUtilities.openType("extension");
 
-async function end_test() {
-  await close_manager(gManagerWindow);
-  finish();
-}
-
-add_test(async function() {
-  await gCategoryUtilities.openType("extension");
   gProvider.createInstalls([{
     name: "updated add-on",
     existingAddon: gProvider.addons[0],
     version: "2.0",
   }]);
   var newAddon = new MockAddon("addon2@tests.mozilla.org");
   newAddon.name = "updated add-on";
   newAddon.version = "2.0";
   newAddon.pendingOperations = AddonManager.PENDING_INSTALL;
   gProvider.installs[0]._addonToInstall = newAddon;
 
   var item = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
-  var name = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "name");
-  is(name.textContent, "manually updating addon", "Should show the old name in the list");
-  get_tooltip_info(item).then(({ name, version }) => {
-    is(name, "manually updating addon", "Should show the old name in the tooltip");
-    is(version, "1.0", "Should still show the old version in the tooltip");
+  is(getName(item), "manually updating addon", "Should show the old name in the list");
+  const {name, version} = await get_tooltip_info(item, gManagerWindow);
+  is(name, "manually updating addon", "Should show the old name in the tooltip");
+  is(version, "1.0", "Should still show the old version in the tooltip");
+
+  var update = await getUpdateButton(item);
+  is_element_visible(update, "Update button should be visible");
+
+  item = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
+  is(item, null, "Should not show the new version in the list");
+
+  await close_manager(gManagerWindow);
+  gManagerWindow = null;
+  gProvider.unregister();
+  gProvider = null;
+}
 
-    var update = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "update-btn");
-    is_element_visible(update, "Update button should be visible");
+add_task(async function test_XUL_updateid() {
+  await SpecialPowers.pushPrefEnv({
+    set: [["extensions.htmlaboutaddons.enabled", false]],
+  });
+
+  await test_updateid();
+
+  // No popPrefEnv because of bug 1557397.
+});
 
-    item = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
-    is(item, null, "Should not show the new version in the list");
+add_task(async function test_HTML_updateid() {
+  await SpecialPowers.pushPrefEnv({
+    set: [["extensions.htmlaboutaddons.enabled", true]],
+  });
 
-    run_next_test();
-  });
+  await test_updateid();
+
+  // No popPrefEnv because of bug 1557397.
 });
--- a/toolkit/mozapps/extensions/test/browser/head.js
+++ b/toolkit/mozapps/extensions/test/browser/head.js
@@ -207,38 +207,59 @@ function run_next_test() {
     info("Running test " + gTestsRun + " (" + test.name + ")");
   else
     info("Running test " + gTestsRun);
 
   gTestStart = Date.now();
   executeSoon(() => log_exceptions(test));
 }
 
-var get_tooltip_info = async function(addon) {
-  let managerWindow = addon.ownerGlobal;
+var get_tooltip_info = async function(addonEl, managerWindow) {
+  if (managerWindow && managerWindow.useHtmlViews) {
+    // Extract from title attribute.
+    const {addon} = addonEl;
+    const name = addon.name;
+    const nameEl = addonEl.querySelector(".addon-name");
 
-  // The popup code uses a triggering event's target to set the
+    let nameWithVersion = nameEl.title;
+    if (addonEl.addon.userDisabled) {
+      // TODO - Bug 1558077: Currently Fluent is clearing the addon title
+      // when the addon is disabled, fixing it requires changes to the
+      // HTML about:addons localized strings, and then remove this
+      // workaround.
+      nameWithVersion = `${name} ${addon.version}`;
+    }
+
+    return {
+      name,
+      version: nameWithVersion.substring(name.length + 1),
+    };
+  }
+
+  // Retrieve the tooltip from the XUL about:addons view,
+  // the popup code uses a triggering event's target to set the
   // document.tooltipNode property.
-  let nameNode = addon.ownerDocument.getAnonymousElementByAttribute(addon, "anonid", "name");
-  let event = new managerWindow.CustomEvent("TriggerEvent");
+  let doc = addonEl.ownerDocument;
+  let nameNode = doc.getAnonymousElementByAttribute(addonEl, "anonid", "name");
+  let event = new doc.ownerGlobal.CustomEvent("TriggerEvent");
   nameNode.dispatchEvent(event);
 
-  let tooltip = managerWindow.document.getElementById("addonitem-tooltip");
+  let tooltip = doc.getElementById("addonitem-tooltip");
 
   let promise = BrowserTestUtils.waitForEvent(tooltip, "popupshown");
   tooltip.openPopup(nameNode, "after_start", 0, 0, false, false, event);
   await promise;
 
   let tiptext = tooltip.label;
 
   promise = BrowserTestUtils.waitForEvent(tooltip, "popuphidden");
   tooltip.hidePopup();
   await promise;
 
-  let expectedName = addon.getAttribute("name");
+  let expectedName = addonEl.getAttribute("name");
   is(tiptext.substring(0, expectedName.length), expectedName,
      "Tooltip should always start with the expected name");
 
   if (expectedName.length == tiptext.length) {
     return {
       name: tiptext,
       version: undefined,
     };
@@ -268,36 +289,16 @@ function get_current_view(aManager) {
   let view = aManager.document.getElementById("view-port").selectedPanel;
   if (view.id == "headered-views") {
     view = aManager.document.getElementById("headered-views-content").selectedPanel;
   }
   is(view, aManager.gViewController.displayedView, "view controller is tracking the displayed view correctly");
   return view;
 }
 
-function get_test_items_in_list(aManager) {
-  var tests = "@tests.mozilla.org";
-
-  let item = aManager.document.getElementById("addon-list").firstChild;
-  let items = [];
-
-  while (item) {
-    if (item.localName != "richlistitem") {
-      item = item.nextSibling;
-      continue;
-    }
-
-    if (!item.mAddon || item.mAddon.id.substring(item.mAddon.id.length - tests.length) == tests)
-      items.push(item);
-    item = item.nextSibling;
-  }
-
-  return items;
-}
-
 function check_all_in_list(aManager, aIds, aIgnoreExtras) {
   var doc = aManager.document;
   var list = doc.getElementById("addon-list");
 
   var inlist = [];
   var node = list.firstChild;
   while (node) {
     if (node.value)