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