michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: function test() { michael@0: waitForExplicitFinish(); michael@0: michael@0: ok(PopupNotifications, "PopupNotifications object exists"); michael@0: ok(PopupNotifications.panel, "PopupNotifications panel exists"); michael@0: michael@0: // Disable transitions as they slow the test down and we want to click the michael@0: // mouse buttons in a predictable location. michael@0: PopupNotifications.transitionsEnabled = false; michael@0: michael@0: registerCleanupFunction(cleanUp); michael@0: michael@0: runNextTest(); michael@0: } michael@0: michael@0: function cleanUp() { michael@0: for (var topic in gActiveObservers) michael@0: Services.obs.removeObserver(gActiveObservers[topic], topic); michael@0: for (var eventName in gActiveListeners) michael@0: PopupNotifications.panel.removeEventListener(eventName, gActiveListeners[eventName], false); michael@0: PopupNotifications.buttonDelay = PREF_SECURITY_DELAY_INITIAL; michael@0: PopupNotifications.transitionsEnabled = true; michael@0: } michael@0: michael@0: const PREF_SECURITY_DELAY_INITIAL = Services.prefs.getIntPref("security.notification_enable_delay"); michael@0: michael@0: var gActiveListeners = {}; michael@0: var gActiveObservers = {}; michael@0: var gShownState = {}; michael@0: michael@0: function goNext() { michael@0: if (++gTestIndex == tests.length) michael@0: executeSoon(finish); michael@0: else michael@0: executeSoon(runNextTest); michael@0: } michael@0: michael@0: function runNextTest() { michael@0: let nextTest = tests[gTestIndex]; michael@0: michael@0: function addObserver(topic) { michael@0: function observer() { michael@0: Services.obs.removeObserver(observer, "PopupNotifications-" + topic); michael@0: delete gActiveObservers["PopupNotifications-" + topic]; michael@0: michael@0: info("[Test #" + gTestIndex + "] observer for " + topic + " called"); michael@0: nextTest[topic](); michael@0: goNext(); michael@0: } michael@0: Services.obs.addObserver(observer, "PopupNotifications-" + topic, false); michael@0: gActiveObservers["PopupNotifications-" + topic] = observer; michael@0: } michael@0: michael@0: if (nextTest.backgroundShow) { michael@0: addObserver("backgroundShow"); michael@0: } else if (nextTest.updateNotShowing) { michael@0: addObserver("updateNotShowing"); michael@0: } else if (nextTest.onShown) { michael@0: doOnPopupEvent("popupshowing", function () { michael@0: info("[Test #" + gTestIndex + "] popup showing"); michael@0: }); michael@0: doOnPopupEvent("popupshown", function () { michael@0: gShownState[gTestIndex] = true; michael@0: info("[Test #" + gTestIndex + "] popup shown"); michael@0: nextTest.onShown(this); michael@0: }); michael@0: michael@0: // We allow multiple onHidden functions to be defined in an array. They're michael@0: // called in the order they appear. michael@0: let onHiddenArray = nextTest.onHidden instanceof Array ? michael@0: nextTest.onHidden : michael@0: [nextTest.onHidden]; michael@0: doOnPopupEvent("popuphidden", function () { michael@0: if (!gShownState[gTestIndex]) { michael@0: // This is expected to happen for test 9, so let's not treat it as a failure. michael@0: info("Popup from test " + gTestIndex + " was hidden before its popupshown fired"); michael@0: } michael@0: michael@0: let onHidden = onHiddenArray.shift(); michael@0: info("[Test #" + gTestIndex + "] popup hidden (" + onHiddenArray.length + " hides remaining)"); michael@0: executeSoon(function () { michael@0: onHidden.call(nextTest, this); michael@0: if (!onHiddenArray.length) michael@0: goNext(); michael@0: }.bind(this)); michael@0: }, onHiddenArray.length); michael@0: info("[Test #" + gTestIndex + "] added listeners; panel state: " + PopupNotifications.isPanelOpen); michael@0: } michael@0: michael@0: info("[Test #" + gTestIndex + "] running test"); michael@0: nextTest.run(); michael@0: } michael@0: michael@0: function doOnPopupEvent(eventName, callback, numExpected) { michael@0: gActiveListeners[eventName] = function (event) { michael@0: if (event.target != PopupNotifications.panel) michael@0: return; michael@0: if (typeof(numExpected) === "number") michael@0: numExpected--; michael@0: if (!numExpected) { michael@0: PopupNotifications.panel.removeEventListener(eventName, gActiveListeners[eventName], false); michael@0: delete gActiveListeners[eventName]; michael@0: } michael@0: michael@0: callback.call(PopupNotifications.panel); michael@0: } michael@0: PopupNotifications.panel.addEventListener(eventName, gActiveListeners[eventName], false); michael@0: } michael@0: michael@0: var gTestIndex = 0; michael@0: var gNewTab; michael@0: michael@0: function basicNotification() { michael@0: var self = this; michael@0: this.browser = gBrowser.selectedBrowser; michael@0: this.id = "test-notification-" + gTestIndex; michael@0: this.message = "This is popup notification " + this.id + " from test " + gTestIndex; michael@0: this.anchorID = null; michael@0: this.mainAction = { michael@0: label: "Main Action", michael@0: accessKey: "M", michael@0: callback: function () { michael@0: self.mainActionClicked = true; michael@0: } michael@0: }; michael@0: this.secondaryActions = [ michael@0: { michael@0: label: "Secondary Action", michael@0: accessKey: "S", michael@0: callback: function () { michael@0: self.secondaryActionClicked = true; michael@0: } michael@0: } michael@0: ]; michael@0: this.options = { michael@0: eventCallback: function (eventName) { michael@0: switch (eventName) { michael@0: case "dismissed": michael@0: self.dismissalCallbackTriggered = true; michael@0: break; michael@0: case "showing": michael@0: self.showingCallbackTriggered = true; michael@0: break; michael@0: case "shown": michael@0: self.shownCallbackTriggered = true; michael@0: break; michael@0: case "removed": michael@0: self.removedCallbackTriggered = true; michael@0: break; michael@0: case "swapping": michael@0: self.swappingCallbackTriggered = true; michael@0: break; michael@0: } michael@0: } michael@0: }; michael@0: } michael@0: michael@0: basicNotification.prototype.addOptions = function(options) { michael@0: for (let [name, value] in Iterator(options)) michael@0: this.options[name] = value; michael@0: }; michael@0: michael@0: function errorNotification() { michael@0: var self = this; michael@0: this.mainAction.callback = function () { michael@0: self.mainActionClicked = true; michael@0: throw new Error("Oops!"); michael@0: }; michael@0: this.secondaryActions[0].callback = function () { michael@0: self.secondaryActionClicked = true; michael@0: throw new Error("Oops!"); michael@0: }; michael@0: } michael@0: michael@0: errorNotification.prototype = new basicNotification(); michael@0: errorNotification.prototype.constructor = errorNotification; michael@0: michael@0: var wrongBrowserNotificationObject = new basicNotification(); michael@0: var wrongBrowserNotification; michael@0: michael@0: var tests = [ michael@0: { // Test #0 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: triggerMainCommand(popup); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.notifyObj.mainActionClicked, "mainAction was clicked"); michael@0: ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered"); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: }, michael@0: { // Test #1 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: triggerSecondaryCommand(popup, 0); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.notifyObj.secondaryActionClicked, "secondaryAction was clicked"); michael@0: ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered"); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: }, michael@0: { // Test #2 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: this.notification = showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered"); michael@0: this.notification.remove(); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: }, michael@0: // test opening a notification for a background browser michael@0: { // Test #3 michael@0: run: function () { michael@0: gNewTab = gBrowser.addTab("about:blank"); michael@0: isnot(gBrowser.selectedTab, gNewTab, "new tab isn't selected"); michael@0: wrongBrowserNotificationObject.browser = gBrowser.getBrowserForTab(gNewTab); michael@0: wrongBrowserNotification = showNotification(wrongBrowserNotificationObject); michael@0: }, michael@0: backgroundShow: function () { michael@0: is(PopupNotifications.isPanelOpen, false, "panel isn't open"); michael@0: ok(!wrongBrowserNotificationObject.mainActionClicked, "main action wasn't clicked"); michael@0: ok(!wrongBrowserNotificationObject.secondaryActionClicked, "secondary action wasn't clicked"); michael@0: ok(!wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback wasn't called"); michael@0: } michael@0: }, michael@0: // now select that browser and test to see that the notification appeared michael@0: { // Test #4 michael@0: run: function () { michael@0: this.oldSelectedTab = gBrowser.selectedTab; michael@0: gBrowser.selectedTab = gNewTab; michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, wrongBrowserNotificationObject); michael@0: is(PopupNotifications.isPanelOpen, true, "isPanelOpen getter doesn't lie"); michael@0: michael@0: // switch back to the old browser michael@0: gBrowser.selectedTab = this.oldSelectedTab; michael@0: }, michael@0: onHidden: function (popup) { michael@0: // actually remove the notification to prevent it from reappearing michael@0: ok(wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback triggered due to tab switch"); michael@0: wrongBrowserNotification.remove(); michael@0: ok(wrongBrowserNotificationObject.removedCallbackTriggered, "removed callback triggered"); michael@0: wrongBrowserNotification = null; michael@0: } michael@0: }, michael@0: // test that the removed notification isn't shown on browser re-select michael@0: { // Test #5 michael@0: run: function () { michael@0: gBrowser.selectedTab = gNewTab; michael@0: }, michael@0: updateNotShowing: function () { michael@0: is(PopupNotifications.isPanelOpen, false, "panel isn't open"); michael@0: gBrowser.removeTab(gNewTab); michael@0: } michael@0: }, michael@0: // Test that two notifications with the same ID result in a single displayed michael@0: // notification. michael@0: { // Test #6 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: // Show the same notification twice michael@0: this.notification1 = showNotification(this.notifyObj); michael@0: this.notification2 = showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: this.notification2.remove(); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered"); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: }, michael@0: // Test that two notifications with different IDs are displayed michael@0: { // Test #7 michael@0: run: function () { michael@0: this.testNotif1 = new basicNotification(); michael@0: this.testNotif1.message += " 1"; michael@0: showNotification(this.testNotif1); michael@0: this.testNotif2 = new basicNotification(); michael@0: this.testNotif2.message += " 2"; michael@0: this.testNotif2.id += "-2"; michael@0: showNotification(this.testNotif2); michael@0: }, michael@0: onShown: function (popup) { michael@0: is(popup.childNodes.length, 2, "two notifications are shown"); michael@0: // Trigger the main command for the first notification, and the secondary michael@0: // for the second. Need to do mainCommand first since the secondaryCommand michael@0: // triggering is async. michael@0: triggerMainCommand(popup); michael@0: is(popup.childNodes.length, 1, "only one notification left"); michael@0: triggerSecondaryCommand(popup, 0); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.testNotif1.mainActionClicked, "main action #1 was clicked"); michael@0: ok(!this.testNotif1.secondaryActionClicked, "secondary action #1 wasn't clicked"); michael@0: ok(!this.testNotif1.dismissalCallbackTriggered, "dismissal callback #1 wasn't called"); michael@0: michael@0: ok(!this.testNotif2.mainActionClicked, "main action #2 wasn't clicked"); michael@0: ok(this.testNotif2.secondaryActionClicked, "secondary action #2 was clicked"); michael@0: ok(!this.testNotif2.dismissalCallbackTriggered, "dismissal callback #2 wasn't called"); michael@0: } michael@0: }, michael@0: // Test notification without mainAction michael@0: { // Test #8 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: this.notifyObj.mainAction = null; michael@0: this.notification = showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: function (popup) { michael@0: this.notification.remove(); michael@0: } michael@0: }, michael@0: // Test two notifications with different anchors michael@0: { // Test #9 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: this.firstNotification = showNotification(this.notifyObj); michael@0: this.notifyObj2 = new basicNotification(); michael@0: this.notifyObj2.id += "-2"; michael@0: this.notifyObj2.anchorID = "addons-notification-icon"; michael@0: // Second showNotification() overrides the first michael@0: this.secondNotification = showNotification(this.notifyObj2); michael@0: }, michael@0: onShown: function (popup) { michael@0: // This also checks that only one element is shown. michael@0: checkPopup(popup, this.notifyObj2); michael@0: is(document.getElementById("geo-notification-icon").boxObject.width, 0, michael@0: "geo anchor shouldn't be visible"); michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: [ michael@0: // The second showing triggers a popuphidden event that we should ignore. michael@0: function (popup) {}, michael@0: function (popup) { michael@0: // Remove the notifications michael@0: this.firstNotification.remove(); michael@0: this.secondNotification.remove(); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: ] michael@0: }, michael@0: // Test optional params michael@0: { // Test #10 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: this.notifyObj.secondaryActions = undefined; michael@0: this.notification = showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered"); michael@0: this.notification.remove(); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: }, michael@0: // Test that icons appear michael@0: { // Test #11 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: this.notifyObj.id = "geolocation"; michael@0: this.notifyObj.anchorID = "geo-notification-icon"; michael@0: this.notification = showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: isnot(document.getElementById("geo-notification-icon").boxObject.width, 0, michael@0: "geo anchor should be visible"); michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: function (popup) { michael@0: let icon = document.getElementById("geo-notification-icon"); michael@0: isnot(icon.boxObject.width, 0, michael@0: "geo anchor should be visible after dismissal"); michael@0: this.notification.remove(); michael@0: is(icon.boxObject.width, 0, michael@0: "geo anchor should not be visible after removal"); michael@0: } michael@0: }, michael@0: // Test that persistence allows the notification to persist across reloads michael@0: { // Test #12 michael@0: run: function () { michael@0: this.oldSelectedTab = gBrowser.selectedTab; michael@0: gBrowser.selectedTab = gBrowser.addTab("about:blank"); michael@0: michael@0: let self = this; michael@0: loadURI("http://example.com/", function() { michael@0: self.notifyObj = new basicNotification(); michael@0: self.notifyObj.addOptions({ michael@0: persistence: 2 michael@0: }); michael@0: self.notification = showNotification(self.notifyObj); michael@0: }); michael@0: }, michael@0: onShown: function (popup) { michael@0: this.complete = false; michael@0: michael@0: let self = this; michael@0: loadURI("http://example.org/", function() { michael@0: loadURI("http://example.com/", function() { michael@0: michael@0: // Next load will remove the notification michael@0: self.complete = true; michael@0: michael@0: loadURI("http://example.org/"); michael@0: }); michael@0: }); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.complete, "Should only have hidden the notification after 3 page loads"); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removal callback triggered"); michael@0: gBrowser.removeTab(gBrowser.selectedTab); michael@0: gBrowser.selectedTab = this.oldSelectedTab; michael@0: } michael@0: }, michael@0: // Test that a timeout allows the notification to persist across reloads michael@0: { // Test #13 michael@0: run: function () { michael@0: this.oldSelectedTab = gBrowser.selectedTab; michael@0: gBrowser.selectedTab = gBrowser.addTab("about:blank"); michael@0: michael@0: let self = this; michael@0: loadURI("http://example.com/", function() { michael@0: self.notifyObj = new basicNotification(); michael@0: // Set a timeout of 10 minutes that should never be hit michael@0: self.notifyObj.addOptions({ michael@0: timeout: Date.now() + 600000 michael@0: }); michael@0: self.notification = showNotification(self.notifyObj); michael@0: }); michael@0: }, michael@0: onShown: function (popup) { michael@0: this.complete = false; michael@0: michael@0: let self = this; michael@0: loadURI("http://example.org/", function() { michael@0: loadURI("http://example.com/", function() { michael@0: michael@0: // Next load will hide the notification michael@0: self.notification.options.timeout = Date.now() - 1; michael@0: self.complete = true; michael@0: michael@0: loadURI("http://example.org/"); michael@0: }); michael@0: }); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.complete, "Should only have hidden the notification after the timeout was passed"); michael@0: this.notification.remove(); michael@0: gBrowser.removeTab(gBrowser.selectedTab); michael@0: gBrowser.selectedTab = this.oldSelectedTab; michael@0: } michael@0: }, michael@0: // Test that setting persistWhileVisible allows a visible notification to michael@0: // persist across location changes michael@0: { // Test #14 michael@0: run: function () { michael@0: this.oldSelectedTab = gBrowser.selectedTab; michael@0: gBrowser.selectedTab = gBrowser.addTab("about:blank"); michael@0: michael@0: let self = this; michael@0: loadURI("http://example.com/", function() { michael@0: self.notifyObj = new basicNotification(); michael@0: self.notifyObj.addOptions({ michael@0: persistWhileVisible: true michael@0: }); michael@0: self.notification = showNotification(self.notifyObj); michael@0: }); michael@0: }, michael@0: onShown: function (popup) { michael@0: this.complete = false; michael@0: michael@0: let self = this; michael@0: loadURI("http://example.org/", function() { michael@0: loadURI("http://example.com/", function() { michael@0: michael@0: // Notification should persist across location changes michael@0: self.complete = true; michael@0: dismissNotification(popup); michael@0: }); michael@0: }); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.complete, "Should only have hidden the notification after it was dismissed"); michael@0: this.notification.remove(); michael@0: gBrowser.removeTab(gBrowser.selectedTab); michael@0: gBrowser.selectedTab = this.oldSelectedTab; michael@0: } michael@0: }, michael@0: // Test that nested icon nodes correctly activate popups michael@0: { // Test #15 michael@0: run: function() { michael@0: // Add a temporary box as the anchor with a button michael@0: this.box = document.createElement("box"); michael@0: PopupNotifications.iconBox.appendChild(this.box); michael@0: michael@0: let button = document.createElement("button"); michael@0: button.setAttribute("label", "Please click me!"); michael@0: this.box.appendChild(button); michael@0: michael@0: // The notification should open up on the box michael@0: this.notifyObj = new basicNotification(); michael@0: this.notifyObj.anchorID = this.box.id = "nested-box"; michael@0: this.notifyObj.addOptions({dismissed: true}); michael@0: this.notification = showNotification(this.notifyObj); michael@0: michael@0: // This test places a normal button in the notification area, which has michael@0: // standard GTK styling and dimensions. Due to the clip-path, this button michael@0: // gets clipped off, which makes it necessary to synthesize the mouse click michael@0: // a little bit downward. To be safe, I adjusted the x-offset with the same michael@0: // amount. michael@0: EventUtils.synthesizeMouse(button, 4, 4, {}); michael@0: }, michael@0: onShown: function(popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: function(popup) { michael@0: this.notification.remove(); michael@0: this.box.parentNode.removeChild(this.box); michael@0: } michael@0: }, michael@0: // Test that popupnotifications without popups have anchor icons shown michael@0: { // Test #16 michael@0: run: function() { michael@0: let notifyObj = new basicNotification(); michael@0: notifyObj.anchorID = "geo-notification-icon"; michael@0: notifyObj.addOptions({neverShow: true}); michael@0: showNotification(notifyObj); michael@0: }, michael@0: updateNotShowing: function() { michael@0: isnot(document.getElementById("geo-notification-icon").boxObject.width, 0, michael@0: "geo anchor should be visible"); michael@0: } michael@0: }, michael@0: // Test notification "Not Now" menu item michael@0: { // Test #17 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: this.notification = showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: triggerSecondaryCommand(popup, 1); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered"); michael@0: this.notification.remove(); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: }, michael@0: // Test notification close button michael@0: { // Test #18 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: this.notification = showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: let notification = popup.childNodes[0]; michael@0: EventUtils.synthesizeMouseAtCenter(notification.closebutton, {}); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered"); michael@0: this.notification.remove(); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: }, michael@0: // Test notification when chrome is hidden michael@0: { // Test #19 michael@0: run: function () { michael@0: window.locationbar.visible = false; michael@0: this.notifyObj = new basicNotification(); michael@0: this.notification = showNotification(this.notifyObj); michael@0: window.locationbar.visible = true; michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: is(popup.anchorNode.className, "tabbrowser-tab", "notification anchored to tab"); michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered"); michael@0: this.notification.remove(); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: }, michael@0: // Test notification is removed when dismissed if removeOnDismissal is true michael@0: { // Test #20 michael@0: run: function () { michael@0: this.notifyObj = new basicNotification(); michael@0: this.notifyObj.addOptions({ michael@0: removeOnDismissal: true michael@0: }); michael@0: this.notification = showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered"); michael@0: ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: }, michael@0: // Test multiple notification icons are shown michael@0: { // Test #21 michael@0: run: function () { michael@0: this.notifyObj1 = new basicNotification(); michael@0: this.notifyObj1.id += "_1"; michael@0: this.notifyObj1.anchorID = "default-notification-icon"; michael@0: this.notification1 = showNotification(this.notifyObj1); michael@0: michael@0: this.notifyObj2 = new basicNotification(); michael@0: this.notifyObj2.id += "_2"; michael@0: this.notifyObj2.anchorID = "geo-notification-icon"; michael@0: this.notification2 = showNotification(this.notifyObj2); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj2); michael@0: michael@0: // check notifyObj1 anchor icon is showing michael@0: isnot(document.getElementById("default-notification-icon").boxObject.width, 0, michael@0: "default anchor should be visible"); michael@0: // check notifyObj2 anchor icon is showing michael@0: isnot(document.getElementById("geo-notification-icon").boxObject.width, 0, michael@0: "geo anchor should be visible"); michael@0: michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: [ michael@0: function (popup) { michael@0: }, michael@0: function (popup) { michael@0: this.notification1.remove(); michael@0: ok(this.notifyObj1.removedCallbackTriggered, "removed callback triggered"); michael@0: michael@0: this.notification2.remove(); michael@0: ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered"); michael@0: } michael@0: ] michael@0: }, michael@0: // Test that multiple notification icons are removed when switching tabs michael@0: { // Test #22 michael@0: run: function () { michael@0: // show the notification on old tab. michael@0: this.notifyObjOld = new basicNotification(); michael@0: this.notifyObjOld.anchorID = "default-notification-icon"; michael@0: this.notificationOld = showNotification(this.notifyObjOld); michael@0: michael@0: // switch tab michael@0: this.oldSelectedTab = gBrowser.selectedTab; michael@0: gBrowser.selectedTab = gBrowser.addTab("about:blank"); michael@0: michael@0: // show the notification on new tab. michael@0: this.notifyObjNew = new basicNotification(); michael@0: this.notifyObjNew.anchorID = "geo-notification-icon"; michael@0: this.notificationNew = showNotification(this.notifyObjNew); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObjNew); michael@0: michael@0: // check notifyObjOld anchor icon is removed michael@0: is(document.getElementById("default-notification-icon").boxObject.width, 0, michael@0: "default anchor shouldn't be visible"); michael@0: // check notifyObjNew anchor icon is showing michael@0: isnot(document.getElementById("geo-notification-icon").boxObject.width, 0, michael@0: "geo anchor should be visible"); michael@0: michael@0: dismissNotification(popup); michael@0: }, michael@0: onHidden: [ michael@0: function (popup) { michael@0: }, michael@0: function (popup) { michael@0: this.notificationNew.remove(); michael@0: gBrowser.removeTab(gBrowser.selectedTab); michael@0: michael@0: gBrowser.selectedTab = this.oldSelectedTab; michael@0: this.notificationOld.remove(); michael@0: } michael@0: ] michael@0: }, michael@0: { // Test #23 - test security delay - too early michael@0: run: function () { michael@0: // Set the security delay to 100s michael@0: PopupNotifications.buttonDelay = 100000; michael@0: michael@0: this.notifyObj = new basicNotification(); michael@0: showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: triggerMainCommand(popup); michael@0: michael@0: // Wait to see if the main command worked michael@0: executeSoon(function delayedDismissal() { michael@0: dismissNotification(popup); michael@0: }); michael@0: michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(!this.notifyObj.mainActionClicked, "mainAction was not clicked because it was too soon"); michael@0: ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback was triggered"); michael@0: } michael@0: }, michael@0: { // Test #24 - test security delay - after delay michael@0: run: function () { michael@0: // Set the security delay to 10ms michael@0: PopupNotifications.buttonDelay = 10; michael@0: michael@0: this.notifyObj = new basicNotification(); michael@0: showNotification(this.notifyObj); michael@0: }, michael@0: onShown: function (popup) { michael@0: checkPopup(popup, this.notifyObj); michael@0: michael@0: // Wait until after the delay to trigger the main action michael@0: setTimeout(function delayedDismissal() { michael@0: triggerMainCommand(popup); michael@0: }, 500); michael@0: michael@0: }, michael@0: onHidden: function (popup) { michael@0: ok(this.notifyObj.mainActionClicked, "mainAction was clicked after the delay"); michael@0: ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback was not triggered"); michael@0: PopupNotifications.buttonDelay = PREF_SECURITY_DELAY_INITIAL; michael@0: } michael@0: }, michael@0: { // Test #25 - reload removes notification michael@0: run: function () { michael@0: loadURI("http://example.com/", function() { michael@0: let notifyObj = new basicNotification(); michael@0: notifyObj.options.eventCallback = function (eventName) { michael@0: if (eventName == "removed") { michael@0: ok(true, "Notification removed in background tab after reloading"); michael@0: executeSoon(function () { michael@0: goNext(); michael@0: }); michael@0: } michael@0: }; michael@0: showNotification(notifyObj); michael@0: executeSoon(function () { michael@0: gBrowser.selectedBrowser.reload(); michael@0: }); michael@0: }); michael@0: } michael@0: }, michael@0: { // Test #26 - location change in background tab removes notification michael@0: run: function () { michael@0: let oldSelectedTab = gBrowser.selectedTab; michael@0: let newTab = gBrowser.addTab("about:blank"); michael@0: gBrowser.selectedTab = newTab; michael@0: michael@0: loadURI("http://example.com/", function() { michael@0: gBrowser.selectedTab = oldSelectedTab; michael@0: let browser = gBrowser.getBrowserForTab(newTab); michael@0: michael@0: let notifyObj = new basicNotification(); michael@0: notifyObj.browser = browser; michael@0: notifyObj.options.eventCallback = function (eventName) { michael@0: if (eventName == "removed") { michael@0: ok(true, "Notification removed in background tab after reloading"); michael@0: executeSoon(function () { michael@0: gBrowser.removeTab(newTab); michael@0: goNext(); michael@0: }); michael@0: } michael@0: }; michael@0: showNotification(notifyObj); michael@0: executeSoon(function () { michael@0: browser.reload(); michael@0: }); michael@0: }); michael@0: } michael@0: }, michael@0: { // Test #27 - Popup notification anchor shouldn't disappear when a notification with the same ID is re-added in a background tab michael@0: run: function () { michael@0: loadURI("http://example.com/", function () { michael@0: let originalTab = gBrowser.selectedTab; michael@0: let bgTab = gBrowser.addTab("about:blank"); michael@0: gBrowser.selectedTab = bgTab; michael@0: loadURI("http://example.com/", function () { michael@0: let anchor = document.createElement("box"); michael@0: anchor.id = "test26-anchor"; michael@0: anchor.className = "notification-anchor-icon"; michael@0: PopupNotifications.iconBox.appendChild(anchor); michael@0: michael@0: gBrowser.selectedTab = originalTab; michael@0: michael@0: let fgNotifyObj = new basicNotification(); michael@0: fgNotifyObj.anchorID = anchor.id; michael@0: fgNotifyObj.options.dismissed = true; michael@0: let fgNotification = showNotification(fgNotifyObj); michael@0: michael@0: let bgNotifyObj = new basicNotification(); michael@0: bgNotifyObj.anchorID = anchor.id; michael@0: bgNotifyObj.browser = gBrowser.getBrowserForTab(bgTab); michael@0: // show the notification in the background tab ... michael@0: let bgNotification = showNotification(bgNotifyObj); michael@0: // ... and re-show it michael@0: bgNotification = showNotification(bgNotifyObj); michael@0: michael@0: ok(fgNotification.id, "notification has id"); michael@0: is(fgNotification.id, bgNotification.id, "notification ids are the same"); michael@0: is(anchor.getAttribute("showing"), "true", "anchor still showing"); michael@0: michael@0: fgNotification.remove(); michael@0: gBrowser.removeTab(bgTab); michael@0: goNext(); michael@0: }); michael@0: }); michael@0: } michael@0: }, michael@0: { // Test #28 - location change in an embedded frame should not remove a notification michael@0: run: function () { michael@0: loadURI("data:text/html;charset=utf8,