Bug 1297475 - Tests for PermissionUI.jsm. r?paolo draft
authorMike Conley <mconley@mozilla.com>
Mon, 29 Aug 2016 09:55:56 -0400
changeset 416139 ccc00fceefb0472a4f4d14266fc59324a21f4a55
parent 416138 d4497d095a0caab125b1e938f3f902e10feebe29
child 416140 af2a8fb265a74732ffabc30c1fa98fcf4061fc35
push id30036
push usermconley@mozilla.com
push dateWed, 21 Sep 2016 14:50:38 +0000
reviewerspaolo
bugs1297475
milestone51.0a1
Bug 1297475 - Tests for PermissionUI.jsm. r?paolo MozReview-Commit-ID: BXLkHhCF64n
browser/modules/test/browser.ini
browser/modules/test/browser_PermissionUI.js
--- a/browser/modules/test/browser.ini
+++ b/browser/modules/test/browser.ini
@@ -3,25 +3,26 @@ support-files =
   head.js
 
 [browser_BrowserUITelemetry_buckets.js]
 [browser_BrowserUITelemetry_defaults.js]
 [browser_BrowserUITelemetry_sidebar.js]
 [browser_BrowserUITelemetry_syncedtabs.js]
 [browser_CaptivePortalWatcher.js]
 skip-if = os == "linux" || os == "win" || (os == "mac" && debug && e10s) # Bug 1279491, Bug 1287714 for OS X debug e10s
-[browser_ProcessHangNotifications.js]
-skip-if = !e10s
 [browser_ContentSearch.js]
 support-files =
   contentSearch.js
   contentSearchBadImage.xml
   contentSearchSuggestions.sjs
   contentSearchSuggestions.xml
 [browser_NetworkPrioritizer.js]
+[browser_PermissionUI.js]
+[browser_ProcessHangNotifications.js]
+skip-if = !e10s
 [browser_SelfSupportBackend.js]
 support-files =
   ../../components/uitour/test/uitour.html
   ../../components/uitour/UITour-lib.js
 [browser_taskbar_preview.js]
 skip-if = os != "win"
 [browser_UnsubmittedCrashHandler.js]
 run-if = crashreporter
new file mode 100644
--- /dev/null
+++ b/browser/modules/test/browser_PermissionUI.js
@@ -0,0 +1,396 @@
+/**
+ * These tests test the ability for the PermissionUI module to open
+ * permission prompts to the user. It also tests to ensure that
+ * add-ons can introduce their own permission prompts.
+ */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Integration.jsm", this);
+Cu.import("resource:///modules/PermissionUI.jsm", this);
+
+/**
+ * Given a <xul:browser> at some non-internal web page,
+ * return something that resembles an nsIContentPermissionRequest,
+ * using the browsers currently loaded document to get a principal.
+ *
+ * @param browser (<xul:browser>)
+ *        The browser that we'll create a nsIContentPermissionRequest
+ *        for.
+ * @returns A nsIContentPermissionRequest-ish object.
+ */
+function makeMockPermissionRequest(browser) {
+  let result = {
+    types: null,
+    principal: browser.contentPrincipal,
+    requester: null,
+    _cancelled: false,
+    cancel() {
+      this._cancelled = true;
+    },
+    _allowed: false,
+    allow() {
+      this._allowed = true;
+    },
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
+  };
+
+  // In the e10s-case, nsIContentPermissionRequest will have
+  // element defined. window is defined otherwise.
+  if (browser.isRemoteBrowser) {
+    result.element = browser;
+  } else {
+    result.window = browser.contentWindow;
+  }
+
+  return result;
+}
+
+/**
+ * For an opened PopupNotification, clicks on the main action,
+ * and waits for the panel to fully close.
+ *
+ * @return {Promise}
+ *         Resolves once the panel has fired the "popuphidden"
+ *         event.
+ */
+function clickMainAction() {
+  let removePromise =
+    BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+  let popupNotification = getPopupNotificationNode();
+  popupNotification.button.click();
+  return removePromise;
+}
+
+/**
+ * For an opened PopupNotification, clicks on a secondary action,
+ * and waits for the panel to fully close.
+ *
+ * @param {int} index
+ *        The 0-indexed index of the secondary menuitem to choose.
+ * @return {Promise}
+ *         Resolves once the panel has fired the "popuphidden"
+ *         event.
+ */
+function clickSecondaryAction(index) {
+  let removePromise =
+    BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+  let popupNotification = getPopupNotificationNode();
+  let menuitems = popupNotification.children;
+  menuitems[index].click();
+  return removePromise;
+}
+
+/**
+ * Makes sure that 1 (and only 1) <xul:popupnotification> is being displayed
+ * by PopupNotification, and then returns that <xul:popupnotification>.
+ *
+ * @return {<xul:popupnotification>}
+ */
+function getPopupNotificationNode() {
+  // PopupNotification is a bit overloaded here, so to be
+  // clear, popupNotifications is a list of <xul:popupnotification>
+  // nodes.
+  let popupNotifications = PopupNotifications.panel.childNodes;
+  Assert.equal(popupNotifications.length, 1,
+               "Should be showing a <xul:popupnotification>");
+  return popupNotifications[0];
+}
+
+/**
+ * Tests the PermissionPromptForRequest prototype to ensure that a prompt
+ * can be displayed. Does not test permission handling.
+ */
+add_task(function* test_permission_prompt_for_request() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "http://example.com/",
+  }, function*(browser) {
+    const kTestNotificationID = "test-notification";
+    const kTestMessage = "Test message";
+    let mainAction = {
+      label: "Main",
+      accessKey: "M",
+    };
+    let secondaryAction = {
+      label: "Secondary",
+      accessKey: "S",
+    };
+
+    let mockRequest = makeMockPermissionRequest(browser);
+    let TestPrompt = {
+      __proto__: PermissionUI.PermissionPromptForRequestPrototype,
+      request: mockRequest,
+      notificationID: kTestNotificationID,
+      message: kTestMessage,
+      promptActions: [mainAction, secondaryAction],
+    };
+
+    let shownPromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    TestPrompt.prompt();
+    yield shownPromise;
+    let notification =
+      PopupNotifications.getNotification(kTestNotificationID, browser);
+    Assert.ok(notification, "Should have gotten the notification");
+
+    Assert.equal(notification.message, kTestMessage,
+                 "Should be showing the right message");
+    Assert.equal(notification.mainAction.label, mainAction.label,
+                 "The main action should have the right label");
+    Assert.equal(notification.mainAction.accessKey, mainAction.accessKey,
+                 "The main action should have the right access key");
+    Assert.equal(notification.secondaryActions.length, 1,
+                 "There should only be 1 secondary action");
+    Assert.equal(notification.secondaryActions[0].label, secondaryAction.label,
+                 "The secondary action should have the right label");
+    Assert.equal(notification.secondaryActions[0].accessKey,
+                 secondaryAction.accessKey,
+                 "The secondary action should have the right access key");
+    Assert.ok(notification.options.displayURI.equals(mockRequest.principal.URI),
+              "Should be showing the URI of the requesting page");
+
+    let removePromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+    notification.remove();
+    yield removePromise;
+  });
+});
+
+/**
+ * Tests that if the PermissionPrompt has the permissionKey
+ * set that permissions can be set properly by the user. Also
+ * ensures that callbacks for promptActions are properly fired.
+ */
+add_task(function* test_with_permission_key() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "http://example.com",
+  }, function*(browser) {
+    const kTestNotificationID = "test-notification";
+    const kTestMessage = "Test message";
+    const kTestPermissionKey = "test-permission-key";
+
+    let allowed = false;
+    let mainAction = {
+      label: "Allow",
+      accessKey: "M",
+      action: Ci.nsIPermissionManager.ALLOW_ACTION,
+      expiryType: Ci.nsIPermissionManager.EXPIRE_SESSION,
+      callback: function() {
+        allowed = true;
+      }
+    };
+
+    let denied = false;
+    let secondaryAction = {
+      label: "Deny",
+      accessKey: "D",
+      action: Ci.nsIPermissionManager.DENY_ACTION,
+      expiryType: Ci.nsIPermissionManager.EXPIRE_SESSION,
+      callback: function() {
+        denied = true;
+      }
+    };
+
+    let mockRequest = makeMockPermissionRequest(browser);
+    let principal = mockRequest.principal;
+    registerCleanupFunction(function() {
+      Services.perms.removeFromPrincipal(principal, kTestPermissionKey);
+    });
+
+    let TestPrompt = {
+      __proto__: PermissionUI.PermissionPromptForRequestPrototype,
+      request: mockRequest,
+      notificationID: kTestNotificationID,
+      permissionKey: kTestPermissionKey,
+      message: kTestMessage,
+      promptActions: [mainAction, secondaryAction],
+    };
+
+    let shownPromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    TestPrompt.prompt();
+    yield shownPromise;
+    let notification =
+      PopupNotifications.getNotification(kTestNotificationID, browser);
+    Assert.ok(notification, "Should have gotten the notification");
+
+    let curPerm =
+      Services.perms.testPermissionFromPrincipal(principal,
+                                                 kTestPermissionKey);
+    Assert.equal(curPerm, Ci.nsIPermissionManager.UNKNOWN_ACTION,
+                 "Should be no permission set to begin with.");
+
+    // First test denying the permission request.
+    Assert.equal(notification.secondaryActions.length, 1,
+                 "There should only be 1 secondary action");
+    yield clickSecondaryAction(0);
+    curPerm = Services.perms.testPermissionFromPrincipal(principal,
+                                                         kTestPermissionKey);
+    Assert.equal(curPerm, Ci.nsIPermissionManager.DENY_ACTION,
+                 "Should have denied the action");
+    Assert.ok(denied, "The secondaryAction callback should have fired");
+    Assert.ok(!allowed, "The mainAction callback should not have fired");
+    Assert.ok(mockRequest._cancelled,
+              "The request should have been cancelled");
+    Assert.ok(!mockRequest._allowed,
+              "The request should not have been allowed");
+
+    // Clear the permission and pretend we never denied
+    Services.perms.removeFromPrincipal(principal, kTestPermissionKey);
+    denied = false;
+    mockRequest._cancelled = false;
+
+    // Bring the PopupNotification back up now...
+    shownPromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    TestPrompt.prompt();
+    yield shownPromise;
+
+    // Next test allowing the permission request.
+    yield clickMainAction();
+    curPerm = Services.perms.testPermissionFromPrincipal(principal,
+                                                         kTestPermissionKey);
+    Assert.equal(curPerm, Ci.nsIPermissionManager.ALLOW_ACTION,
+                 "Should have allowed the action");
+    Assert.ok(!denied, "The secondaryAction callback should not have fired");
+    Assert.ok(allowed, "The mainAction callback should have fired");
+    Assert.ok(!mockRequest._cancelled,
+              "The request should not have been cancelled");
+    Assert.ok(mockRequest._allowed,
+              "The request should have been allowed");
+  });
+});
+
+/**
+ * Tests that the onBeforeShow method will be called before
+ * the popup appears.
+ */
+add_task(function* test_on_before_show() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "http://example.com",
+  }, function*(browser) {
+    const kTestNotificationID = "test-notification";
+    const kTestMessage = "Test message";
+
+    let mainAction = {
+      label: "Test action",
+      accessKey: "T",
+    };
+
+    let mockRequest = makeMockPermissionRequest(browser);
+    let beforeShown = false;
+
+    let TestPrompt = {
+      __proto__: PermissionUI.PermissionPromptForRequestPrototype,
+      request: mockRequest,
+      notificationID: kTestNotificationID,
+      message: kTestMessage,
+      promptActions: [mainAction],
+      onBeforeShow() {
+        beforeShown = true;
+      }
+    };
+
+    let shownPromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    TestPrompt.prompt();
+    Assert.ok(beforeShown, "Should have called onBeforeShown");
+    yield shownPromise;
+    let notification =
+      PopupNotifications.getNotification(kTestNotificationID, browser);
+
+    let removePromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+    notification.remove();
+    yield removePromise;
+  });
+});
+
+/**
+ * Tests that we can open a PermissionPrompt without wrapping a
+ * nsIContentPermissionRequest.
+ */
+add_task(function* test_no_request() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "http://example.com",
+  }, function*(browser) {
+    const kTestNotificationID = "test-notification";
+    let allowed = false;
+    let mainAction = {
+      label: "Allow",
+      accessKey: "M",
+      callback: function() {
+        allowed = true;
+      }
+    };
+
+    let denied = false;
+    let secondaryAction = {
+      label: "Deny",
+      accessKey: "D",
+      callback: function() {
+        denied = true;
+      }
+    };
+
+    const kTestMessage = "Test message with no request";
+    let principal = browser.contentPrincipal;
+    let beforeShown = false;
+
+    let TestPrompt = {
+      __proto__: PermissionUI.PermissionPromptPrototype,
+      notificationID: kTestNotificationID,
+      principal,
+      browser,
+      message: kTestMessage,
+      promptActions: [mainAction, secondaryAction],
+      onBeforeShow() {
+        beforeShown = true;
+      }
+    };
+
+    let shownPromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    TestPrompt.prompt();
+    Assert.ok(beforeShown, "Should have called onBeforeShown");
+    yield shownPromise;
+    let notification =
+      PopupNotifications.getNotification(kTestNotificationID, browser);
+
+    Assert.equal(notification.message, kTestMessage,
+                 "Should be showing the right message");
+    Assert.equal(notification.mainAction.label, mainAction.label,
+                 "The main action should have the right label");
+    Assert.equal(notification.mainAction.accessKey, mainAction.accessKey,
+                 "The main action should have the right access key");
+    Assert.equal(notification.secondaryActions.length, 1,
+                 "There should only be 1 secondary action");
+    Assert.equal(notification.secondaryActions[0].label, secondaryAction.label,
+                 "The secondary action should have the right label");
+    Assert.equal(notification.secondaryActions[0].accessKey,
+                 secondaryAction.accessKey,
+                 "The secondary action should have the right access key");
+    Assert.ok(notification.options.displayURI.equals(principal.URI),
+              "Should be showing the URI of the requesting page");
+
+    // First test denying the permission request.
+    Assert.equal(notification.secondaryActions.length, 1,
+                 "There should only be 1 secondary action");
+    yield clickSecondaryAction(0);
+    Assert.ok(denied, "The secondaryAction callback should have fired");
+    Assert.ok(!allowed, "The mainAction callback should not have fired");
+
+    shownPromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    TestPrompt.prompt();
+    yield shownPromise;
+
+    // Next test allowing the permission request.
+    yield clickMainAction();
+    Assert.ok(allowed, "The mainAction callback should have fired");
+  });
+});