summaryrefslogtreecommitdiffstats
path: root/browser/components/preferences/tests/browser_applications_selection.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/preferences/tests/browser_applications_selection.js')
-rw-r--r--browser/components/preferences/tests/browser_applications_selection.js403
1 files changed, 403 insertions, 0 deletions
diff --git a/browser/components/preferences/tests/browser_applications_selection.js b/browser/components/preferences/tests/browser_applications_selection.js
new file mode 100644
index 0000000000..683ce76a89
--- /dev/null
+++ b/browser/components/preferences/tests/browser_applications_selection.js
@@ -0,0 +1,403 @@
+SimpleTest.requestCompleteLog();
+const { HandlerServiceTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/HandlerServiceTestUtils.sys.mjs"
+);
+
+let gHandlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(
+ Ci.nsIHandlerService
+);
+
+let gOldMailHandlers = [];
+let gDummyHandlers = [];
+let gOriginalPreferredMailHandler;
+let gOriginalPreferredPDFHandler;
+
+registerCleanupFunction(function () {
+ function removeDummyHandlers(handlers) {
+ // Remove any of the dummy handlers we created.
+ for (let i = handlers.Count() - 1; i >= 0; i--) {
+ try {
+ if (
+ gDummyHandlers.some(
+ h =>
+ h.uriTemplate ==
+ handlers.queryElementAt(i, Ci.nsIWebHandlerApp).uriTemplate
+ )
+ ) {
+ handlers.removeElementAt(i);
+ }
+ } catch (ex) {
+ /* ignore non-web-app handlers */
+ }
+ }
+ }
+ // Re-add the original protocol handlers:
+ let mailHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("mailto");
+ let mailHandlers = mailHandlerInfo.possibleApplicationHandlers;
+ for (let h of gOldMailHandlers) {
+ mailHandlers.appendElement(h);
+ }
+ removeDummyHandlers(mailHandlers);
+ mailHandlerInfo.preferredApplicationHandler = gOriginalPreferredMailHandler;
+ gHandlerService.store(mailHandlerInfo);
+
+ let pdfHandlerInfo =
+ HandlerServiceTestUtils.getHandlerInfo("application/pdf");
+ removeDummyHandlers(pdfHandlerInfo.possibleApplicationHandlers);
+ pdfHandlerInfo.preferredApplicationHandler = gOriginalPreferredPDFHandler;
+ gHandlerService.store(pdfHandlerInfo);
+
+ gBrowser.removeCurrentTab();
+});
+
+function scrubMailtoHandlers(handlerInfo) {
+ // Remove extant web handlers because they have icons that
+ // we fetch from the web, which isn't allowed in tests.
+ let handlers = handlerInfo.possibleApplicationHandlers;
+ for (let i = handlers.Count() - 1; i >= 0; i--) {
+ try {
+ let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
+ gOldMailHandlers.push(handler);
+ // If we get here, this is a web handler app. Remove it:
+ handlers.removeElementAt(i);
+ } catch (ex) {}
+ }
+}
+
+add_setup(async function () {
+ // Create our dummy handlers
+ let handler1 = Cc["@mozilla.org/uriloader/web-handler-app;1"].createInstance(
+ Ci.nsIWebHandlerApp
+ );
+ handler1.name = "Handler 1";
+ handler1.uriTemplate = "https://example.com/first/%s";
+
+ let handler2 = Cc["@mozilla.org/uriloader/web-handler-app;1"].createInstance(
+ Ci.nsIWebHandlerApp
+ );
+ handler2.name = "Handler 2";
+ handler2.uriTemplate = "http://example.org/second/%s";
+ gDummyHandlers.push(handler1, handler2);
+
+ function substituteWebHandlers(handlerInfo) {
+ // Append the dummy handlers to replace them:
+ let handlers = handlerInfo.possibleApplicationHandlers;
+ handlers.appendElement(handler1);
+ handlers.appendElement(handler2);
+ gHandlerService.store(handlerInfo);
+ }
+ // Set up our mailto handler test infrastructure.
+ let mailtoHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("mailto");
+ scrubMailtoHandlers(mailtoHandlerInfo);
+ gOriginalPreferredMailHandler = mailtoHandlerInfo.preferredApplicationHandler;
+ substituteWebHandlers(mailtoHandlerInfo);
+
+ // Now do the same for pdf handler:
+ let pdfHandlerInfo =
+ HandlerServiceTestUtils.getHandlerInfo("application/pdf");
+ // PDF doesn't have built-in web handlers, so no need to scrub.
+ gOriginalPreferredPDFHandler = pdfHandlerInfo.preferredApplicationHandler;
+ substituteWebHandlers(pdfHandlerInfo);
+
+ await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
+ info("Preferences page opened on the general pane.");
+
+ await gBrowser.selectedBrowser.contentWindow.promiseLoadHandlersList;
+ info("Apps list loaded.");
+});
+
+async function selectStandardOptions(itemToUse) {
+ async function selectItemInPopup(item) {
+ let popupShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
+ // Synthesizing the mouse on the .actionsMenu menulist somehow just selects
+ // the top row. Probably something to do with the multiple layers of anon
+ // content - workaround by using the `.open` setter instead.
+ list.open = true;
+ await popupShown;
+ let popupHidden = BrowserTestUtils.waitForEvent(popup, "popuphidden");
+ if (typeof item == "function") {
+ item = item();
+ }
+ popup.activateItem(item);
+ await popupHidden;
+ return item;
+ }
+
+ let itemType = itemToUse.getAttribute("type");
+ // Center the item. Center rather than top so it doesn't get blocked by
+ // the search header.
+ itemToUse.scrollIntoView({ block: "center" });
+ itemToUse.closest("richlistbox").selectItem(itemToUse);
+ Assert.ok(itemToUse.selected, "Should be able to select our item.");
+ // Force reflow to make sure it's visible and the container dropdown isn't
+ // hidden.
+ itemToUse.getBoundingClientRect().top;
+ let list = itemToUse.querySelector(".actionsMenu");
+ let popup = list.menupopup;
+
+ // select one of our test cases:
+ let handlerItem = list.querySelector("menuitem[data-l10n-args*='Handler 1']");
+ await selectItemInPopup(handlerItem);
+ let { preferredAction, alwaysAskBeforeHandling } =
+ HandlerServiceTestUtils.getHandlerInfo(itemType);
+ Assert.notEqual(
+ preferredAction,
+ Ci.nsIHandlerInfo.alwaysAsk,
+ "Should have selected something other than 'always ask' (" + itemType + ")"
+ );
+ Assert.ok(
+ !alwaysAskBeforeHandling,
+ "Should have turned off asking before handling (" + itemType + ")"
+ );
+
+ // Test the alwaysAsk option
+ let alwaysAskItem = list.getElementsByAttribute(
+ "action",
+ Ci.nsIHandlerInfo.alwaysAsk
+ )[0];
+ await selectItemInPopup(alwaysAskItem);
+ Assert.equal(
+ list.selectedItem,
+ alwaysAskItem,
+ "Should have selected always ask item (" + itemType + ")"
+ );
+ alwaysAskBeforeHandling =
+ HandlerServiceTestUtils.getHandlerInfo(itemType).alwaysAskBeforeHandling;
+ Assert.ok(
+ alwaysAskBeforeHandling,
+ "Should have turned on asking before handling (" + itemType + ")"
+ );
+
+ let useDefaultItem = list.getElementsByAttribute(
+ "action",
+ Ci.nsIHandlerInfo.useSystemDefault
+ );
+ useDefaultItem = useDefaultItem && useDefaultItem[0];
+ if (useDefaultItem) {
+ await selectItemInPopup(useDefaultItem);
+ Assert.equal(
+ list.selectedItem,
+ useDefaultItem,
+ "Should have selected 'use default' item (" + itemType + ")"
+ );
+ preferredAction =
+ HandlerServiceTestUtils.getHandlerInfo(itemType).preferredAction;
+ Assert.equal(
+ preferredAction,
+ Ci.nsIHandlerInfo.useSystemDefault,
+ "Should have selected 'use default' (" + itemType + ")"
+ );
+ } else {
+ // Whether there's a "use default" item depends on the OS, so it's not
+ // possible to rely on it being the case or not.
+ info("No 'Use default' item, so not testing (" + itemType + ")");
+ }
+
+ // Select a web app item.
+ let webAppItems = Array.from(
+ popup.getElementsByAttribute("action", Ci.nsIHandlerInfo.useHelperApp)
+ );
+ webAppItems = webAppItems.filter(
+ item => item.handlerApp instanceof Ci.nsIWebHandlerApp
+ );
+ Assert.equal(
+ webAppItems.length,
+ 2,
+ "Should have 2 web application handler. (" + itemType + ")"
+ );
+ Assert.notEqual(
+ webAppItems[0].label,
+ webAppItems[1].label,
+ "Should have 2 different web app handlers"
+ );
+ let selectedItem = await selectItemInPopup(webAppItems[0]);
+
+ // Test that the selected item label is the same as the label
+ // of the menu item.
+ let win = gBrowser.selectedBrowser.contentWindow;
+ await win.document.l10n.translateFragment(selectedItem);
+ await win.document.l10n.translateFragment(itemToUse);
+ Assert.equal(
+ selectedItem.label,
+ itemToUse.querySelector(".actionContainer label").value,
+ "Should have selected correct item (" + itemType + ")"
+ );
+ let { preferredApplicationHandler } =
+ HandlerServiceTestUtils.getHandlerInfo(itemType);
+ preferredApplicationHandler.QueryInterface(Ci.nsIWebHandlerApp);
+ Assert.equal(
+ selectedItem.handlerApp.uriTemplate,
+ preferredApplicationHandler.uriTemplate,
+ "App should actually be selected in the backend. (" + itemType + ")"
+ );
+
+ // select the other web app item
+ selectedItem = await selectItemInPopup(webAppItems[1]);
+
+ // Test that the selected item label is the same as the label
+ // of the menu item
+ await win.document.l10n.translateFragment(selectedItem);
+ await win.document.l10n.translateFragment(itemToUse);
+ Assert.equal(
+ selectedItem.label,
+ itemToUse.querySelector(".actionContainer label").value,
+ "Should have selected correct item (" + itemType + ")"
+ );
+ preferredApplicationHandler =
+ HandlerServiceTestUtils.getHandlerInfo(
+ itemType
+ ).preferredApplicationHandler;
+ preferredApplicationHandler.QueryInterface(Ci.nsIWebHandlerApp);
+ Assert.equal(
+ selectedItem.handlerApp.uriTemplate,
+ preferredApplicationHandler.uriTemplate,
+ "App should actually be selected in the backend. (" + itemType + ")"
+ );
+}
+
+add_task(async function checkDropdownBehavior() {
+ let win = gBrowser.selectedBrowser.contentWindow;
+
+ let container = win.document.getElementById("handlersView");
+
+ // First check a protocol handler item.
+ let mailItem = container.querySelector("richlistitem[type='mailto']");
+ Assert.ok(mailItem, "mailItem is present in handlersView.");
+ await selectStandardOptions(mailItem);
+
+ // Then check a content menu item.
+ let pdfItem = container.querySelector("richlistitem[type='application/pdf']");
+ Assert.ok(pdfItem, "pdfItem is present in handlersView.");
+ await selectStandardOptions(pdfItem);
+});
+
+add_task(async function sortingCheck() {
+ let win = gBrowser.selectedBrowser.contentWindow;
+ const handlerView = win.document.getElementById("handlersView");
+ const typeColumn = win.document.getElementById("typeColumn");
+ Assert.ok(typeColumn, "typeColumn is present in handlersView.");
+
+ let expectedNumberOfItems =
+ handlerView.querySelectorAll("richlistitem").length;
+
+ // Test default sorting
+ assertSortByType("ascending");
+
+ const oldDir = typeColumn.getAttribute("sortDirection");
+
+ // click on an item and sort again:
+ let itemToUse = handlerView.querySelector("richlistitem[type=mailto]");
+ itemToUse.scrollIntoView({ block: "center" });
+ itemToUse.closest("richlistbox").selectItem(itemToUse);
+
+ // Test sorting on the type column
+ typeColumn.click();
+ assertSortByType("descending");
+ Assert.notEqual(
+ oldDir,
+ typeColumn.getAttribute("sortDirection"),
+ "Sort direction should change"
+ );
+
+ typeColumn.click();
+ assertSortByType("ascending");
+
+ const actionColumn = win.document.getElementById("actionColumn");
+ Assert.ok(actionColumn, "actionColumn is present in handlersView.");
+
+ // Test sorting on the action column
+ const oldActionDir = actionColumn.getAttribute("sortDirection");
+ actionColumn.click();
+ assertSortByAction("ascending");
+ Assert.notEqual(
+ oldActionDir,
+ actionColumn.getAttribute("sortDirection"),
+ "Sort direction should change"
+ );
+
+ actionColumn.click();
+ assertSortByAction("descending");
+
+ // Restore the default sort order
+ typeColumn.click();
+ assertSortByType("ascending");
+
+ function assertSortByAction(order) {
+ Assert.equal(
+ actionColumn.getAttribute("sortDirection"),
+ order,
+ `Sort direction should be ${order}`
+ );
+ let siteItems = handlerView.getElementsByTagName("richlistitem");
+ Assert.equal(
+ siteItems.length,
+ expectedNumberOfItems,
+ "Number of items should not change."
+ );
+ for (let i = 0; i < siteItems.length - 1; ++i) {
+ let aType = siteItems[i].getAttribute("actionDescription").toLowerCase();
+ let bType = siteItems[i + 1]
+ .getAttribute("actionDescription")
+ .toLowerCase();
+ let result = 0;
+ if (aType > bType) {
+ result = 1;
+ } else if (bType > aType) {
+ result = -1;
+ }
+ if (order == "ascending") {
+ Assert.lessOrEqual(
+ result,
+ 0,
+ "Should sort applications in the ascending order by action"
+ );
+ } else {
+ Assert.greaterOrEqual(
+ result,
+ 0,
+ "Should sort applications in the descending order by action"
+ );
+ }
+ }
+ }
+
+ function assertSortByType(order) {
+ Assert.equal(
+ typeColumn.getAttribute("sortDirection"),
+ order,
+ `Sort direction should be ${order}`
+ );
+
+ let siteItems = handlerView.getElementsByTagName("richlistitem");
+ Assert.equal(
+ siteItems.length,
+ expectedNumberOfItems,
+ "Number of items should not change."
+ );
+ for (let i = 0; i < siteItems.length - 1; ++i) {
+ let aType = siteItems[i].getAttribute("typeDescription").toLowerCase();
+ let bType = siteItems[i + 1]
+ .getAttribute("typeDescription")
+ .toLowerCase();
+ let result = 0;
+ if (aType > bType) {
+ result = 1;
+ } else if (bType > aType) {
+ result = -1;
+ }
+ if (order == "ascending") {
+ Assert.lessOrEqual(
+ result,
+ 0,
+ "Should sort applications in the ascending order by type"
+ );
+ } else {
+ Assert.greaterOrEqual(
+ result,
+ 0,
+ "Should sort applications in the descending order by type"
+ );
+ }
+ }
+ }
+});