browser_popupNotification_5.js (16913B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 function test() { 6 waitForExplicitFinish(); 7 8 ok(PopupNotifications, "PopupNotifications object exists"); 9 ok(PopupNotifications.panel, "PopupNotifications panel exists"); 10 11 setup(); 12 } 13 14 var gNotification; 15 16 var tests = [ 17 // panel updates should fire the showing and shown callbacks again. 18 { 19 id: "Test#1", 20 run() { 21 this.notifyObj = new BasicNotification(this.id); 22 this.notification = showNotification(this.notifyObj); 23 }, 24 onShown(popup) { 25 checkPopup(popup, this.notifyObj); 26 27 this.notifyObj.showingCallbackTriggered = false; 28 this.notifyObj.shownCallbackTriggered = false; 29 30 // Force an update of the panel. This is typically called 31 // automatically when receiving 'activate' or 'TabSelect' events, 32 // but from a setTimeout, which is inconvenient for the test. 33 PopupNotifications._update(); 34 35 checkPopup(popup, this.notifyObj); 36 37 this.notification.remove(); 38 }, 39 onHidden() {}, 40 }, 41 // A first dismissed notification shouldn't stop _update from showing a second notification 42 { 43 id: "Test#2", 44 run() { 45 this.notifyObj1 = new BasicNotification(this.id); 46 this.notifyObj1.id += "_1"; 47 this.notifyObj1.anchorID = "default-notification-icon"; 48 this.notifyObj1.options.dismissed = true; 49 this.notification1 = showNotification(this.notifyObj1); 50 51 this.notifyObj2 = new BasicNotification(this.id); 52 this.notifyObj2.id += "_2"; 53 this.notifyObj2.anchorID = "geo-notification-icon"; 54 this.notifyObj2.options.dismissed = true; 55 this.notification2 = showNotification(this.notifyObj2); 56 57 this.notification2.dismissed = false; 58 PopupNotifications._update(); 59 }, 60 onShown(popup) { 61 checkPopup(popup, this.notifyObj2); 62 this.notification1.remove(); 63 this.notification2.remove(); 64 }, 65 onHidden() {}, 66 }, 67 // The anchor icon should be shown for notifications in background windows. 68 { 69 id: "Test#3", 70 async run() { 71 let notifyObj = new BasicNotification(this.id); 72 notifyObj.options.dismissed = true; 73 74 let win = await BrowserTestUtils.openNewBrowserWindow(); 75 76 // Open the notification in the original window, now in the background. 77 let notification = showNotification(notifyObj); 78 let anchor = document.getElementById("default-notification-icon"); 79 is(anchor.getAttribute("showing"), "true", "the anchor is shown"); 80 notification.remove(); 81 82 await BrowserTestUtils.closeWindow(win); 83 await waitForWindowReadyForPopupNotifications(window); 84 85 goNext(); 86 }, 87 }, 88 // Test that persistent doesn't allow the notification to persist after 89 // navigation. 90 { 91 id: "Test#4", 92 async run() { 93 this.oldSelectedTab = gBrowser.selectedTab; 94 await BrowserTestUtils.openNewForegroundTab( 95 gBrowser, 96 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 97 "http://example.com/" 98 ); 99 this.notifyObj = new BasicNotification(this.id); 100 this.notifyObj.addOptions({ 101 persistent: true, 102 }); 103 this.notification = showNotification(this.notifyObj); 104 }, 105 async onShown(popup) { 106 this.complete = false; 107 108 await BrowserTestUtils.loadURIString({ 109 browser: gBrowser.selectedTab.linkedBrowser, 110 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 111 uriString: "http://example.org/", 112 }); 113 await BrowserTestUtils.loadURIString({ 114 browser: gBrowser.selectedTab.linkedBrowser, 115 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 116 uriString: "http://example.com/", 117 }); 118 119 // This code should not be executed. 120 ok(false, "Should have removed the notification after navigation"); 121 // Properly dismiss and cleanup in case the unthinkable happens. 122 this.complete = true; 123 triggerSecondaryCommand(popup, 0); 124 }, 125 onHidden() { 126 ok( 127 !this.complete, 128 "Should have hidden the notification after navigation" 129 ); 130 this.notification.remove(); 131 gBrowser.removeTab(gBrowser.selectedTab); 132 gBrowser.selectedTab = this.oldSelectedTab; 133 }, 134 }, 135 // Test that persistent allows the notification to persist until explicitly 136 // dismissed. 137 { 138 id: "Test#5", 139 async run() { 140 this.oldSelectedTab = gBrowser.selectedTab; 141 await BrowserTestUtils.openNewForegroundTab( 142 gBrowser, 143 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 144 "http://example.com/" 145 ); 146 this.notifyObj = new BasicNotification(this.id); 147 this.notifyObj.addOptions({ 148 persistent: true, 149 }); 150 this.notification = showNotification(this.notifyObj); 151 }, 152 async onShown(popup) { 153 this.complete = false; 154 155 // Notification should persist after attempt to dismiss by clicking on the 156 // content area. 157 let browser = gBrowser.selectedBrowser; 158 await BrowserTestUtils.synthesizeMouseAtCenter("body", {}, browser); 159 160 // Notification should be hidden after dismissal via Don't Allow. 161 this.complete = true; 162 triggerSecondaryCommand(popup, 0); 163 }, 164 onHidden() { 165 ok( 166 this.complete, 167 "Should have hidden the notification after clicking Not Now" 168 ); 169 this.notification.remove(); 170 gBrowser.removeTab(gBrowser.selectedTab); 171 gBrowser.selectedTab = this.oldSelectedTab; 172 }, 173 }, 174 // Test that persistent panels are still open after switching to another tab 175 // and back. 176 { 177 id: "Test#6a", 178 run() { 179 this.notifyObj = new BasicNotification(this.id); 180 this.notifyObj.options.persistent = true; 181 gNotification = showNotification(this.notifyObj); 182 }, 183 async onShown() { 184 this.oldSelectedTab = gBrowser.selectedTab; 185 await BrowserTestUtils.openNewForegroundTab( 186 gBrowser, 187 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 188 "http://example.com/" 189 ); 190 }, 191 onHidden() { 192 ok(true, "Should have hidden the notification after tab switch"); 193 gBrowser.removeTab(gBrowser.selectedTab); 194 gBrowser.selectedTab = this.oldSelectedTab; 195 }, 196 }, 197 // Second part of the previous test that compensates for the limitation in 198 // runNextTest that expects a single onShown/onHidden invocation per test. 199 { 200 id: "Test#6b", 201 run() { 202 let id = 203 PopupNotifications.panel.firstElementChild.getAttribute("popupid"); 204 ok( 205 id.endsWith("Test#6a"), 206 "Should have found the notification from Test6a" 207 ); 208 ok( 209 PopupNotifications.isPanelOpen, 210 "Should have shown the popup again after getting back to the tab" 211 ); 212 gNotification.remove(); 213 gNotification = null; 214 goNext(); 215 }, 216 }, 217 // Test that persistent panels are still open after switching to another 218 // window and back. 219 { 220 id: "Test#7", 221 async run() { 222 this.oldSelectedTab = gBrowser.selectedTab; 223 await BrowserTestUtils.openNewForegroundTab( 224 gBrowser, 225 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 226 "http://example.com/" 227 ); 228 let firstTab = gBrowser.selectedTab; 229 230 await BrowserTestUtils.openNewForegroundTab( 231 gBrowser, 232 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 233 "http://example.com/" 234 ); 235 236 let shown = waitForNotificationPanel(); 237 let notifyObj = new BasicNotification(this.id); 238 notifyObj.options.persistent = true; 239 this.notification = showNotification(notifyObj); 240 await shown; 241 242 ok( 243 notifyObj.shownCallbackTriggered, 244 "Should have triggered the shown event" 245 ); 246 ok( 247 notifyObj.showingCallbackTriggered, 248 "Should have triggered the showing event" 249 ); 250 // Reset to false so that we can ensure these are not fired a second time. 251 notifyObj.shownCallbackTriggered = false; 252 notifyObj.showingCallbackTriggered = false; 253 let timeShown = this.notification.timeShown; 254 255 let promiseWin = BrowserTestUtils.waitForNewWindow(); 256 gBrowser.replaceTabWithWindow(firstTab); 257 let win = await promiseWin; 258 259 let anchor = win.document.getElementById("default-notification-icon"); 260 win.PopupNotifications._reshowNotifications(anchor); 261 ok( 262 !win.PopupNotifications.panel.children.length, 263 "no notification displayed in new window" 264 ); 265 266 await BrowserTestUtils.closeWindow(win); 267 await waitForWindowReadyForPopupNotifications(window); 268 269 let id = 270 PopupNotifications.panel.firstElementChild.getAttribute("popupid"); 271 ok( 272 id.endsWith("Test#7"), 273 "Should have found the notification from Test7" 274 ); 275 ok( 276 PopupNotifications.isPanelOpen, 277 "Should have kept the popup on the first window" 278 ); 279 ok( 280 !notifyObj.dismissalCallbackTriggered, 281 "Should not have triggered a dismissed event" 282 ); 283 ok( 284 !notifyObj.shownCallbackTriggered, 285 "Should not have triggered a second shown event" 286 ); 287 ok( 288 !notifyObj.showingCallbackTriggered, 289 "Should not have triggered a second showing event" 290 ); 291 Assert.greater( 292 this.notification.timeShown, 293 timeShown, 294 "should have updated timeShown to restart the security delay" 295 ); 296 297 this.notification.remove(); 298 gBrowser.removeTab(gBrowser.selectedTab); 299 gBrowser.selectedTab = this.oldSelectedTab; 300 301 goNext(); 302 }, 303 }, 304 // Test that only the first persistent notification is shown on update 305 { 306 id: "Test#8", 307 run() { 308 this.notifyObj1 = new BasicNotification(this.id); 309 this.notifyObj1.id += "_1"; 310 this.notifyObj1.anchorID = "default-notification-icon"; 311 this.notifyObj1.options.persistent = true; 312 this.notification1 = showNotification(this.notifyObj1); 313 314 this.notifyObj2 = new BasicNotification(this.id); 315 this.notifyObj2.id += "_2"; 316 this.notifyObj2.anchorID = "geo-notification-icon"; 317 this.notifyObj2.options.persistent = true; 318 this.notification2 = showNotification(this.notifyObj2); 319 320 PopupNotifications._update(); 321 }, 322 onShown(popup) { 323 checkPopup(popup, this.notifyObj1); 324 this.notification1.remove(); 325 this.notification2.remove(); 326 }, 327 onHidden() {}, 328 }, 329 // Test that persistent notifications are shown stacked by anchor on update 330 { 331 id: "Test#9", 332 run() { 333 this.notifyObj1 = new BasicNotification(this.id); 334 this.notifyObj1.id += "_1"; 335 this.notifyObj1.anchorID = "default-notification-icon"; 336 this.notifyObj1.options.persistent = true; 337 this.notification1 = showNotification(this.notifyObj1); 338 339 this.notifyObj2 = new BasicNotification(this.id); 340 this.notifyObj2.id += "_2"; 341 this.notifyObj2.anchorID = "geo-notification-icon"; 342 this.notifyObj2.options.persistent = true; 343 this.notification2 = showNotification(this.notifyObj2); 344 345 this.notifyObj3 = new BasicNotification(this.id); 346 this.notifyObj3.id += "_3"; 347 this.notifyObj3.anchorID = "default-notification-icon"; 348 this.notifyObj3.options.persistent = true; 349 this.notification3 = showNotification(this.notifyObj3); 350 351 PopupNotifications._update(); 352 }, 353 onShown(popup) { 354 let notifications = popup.children; 355 is(notifications.length, 2, "two notifications displayed"); 356 let [notification1, notification2] = notifications; 357 is( 358 notification1.id, 359 this.notifyObj1.id + "-notification", 360 "id 1 matches" 361 ); 362 is( 363 notification2.id, 364 this.notifyObj3.id + "-notification", 365 "id 2 matches" 366 ); 367 368 this.notification1.remove(); 369 this.notification2.remove(); 370 this.notification3.remove(); 371 }, 372 onHidden() {}, 373 }, 374 // Test that on closebutton click, only the persistent notification 375 // that contained the closebutton loses its persistent status. 376 { 377 id: "Test#10", 378 run() { 379 this.notifyObj1 = new BasicNotification(this.id); 380 this.notifyObj1.id += "_1"; 381 this.notifyObj1.anchorID = "geo-notification-icon"; 382 this.notifyObj1.options.persistent = true; 383 this.notifyObj1.options.hideClose = false; 384 this.notification1 = showNotification(this.notifyObj1); 385 386 this.notifyObj2 = new BasicNotification(this.id); 387 this.notifyObj2.id += "_2"; 388 this.notifyObj2.anchorID = "geo-notification-icon"; 389 this.notifyObj2.options.persistent = true; 390 this.notifyObj2.options.hideClose = false; 391 this.notification2 = showNotification(this.notifyObj2); 392 393 this.notifyObj3 = new BasicNotification(this.id); 394 this.notifyObj3.id += "_3"; 395 this.notifyObj3.anchorID = "geo-notification-icon"; 396 this.notifyObj3.options.persistent = true; 397 this.notifyObj3.options.hideClose = false; 398 this.notification3 = showNotification(this.notifyObj3); 399 400 PopupNotifications._update(); 401 }, 402 onShown(popup) { 403 let notifications = popup.children; 404 is(notifications.length, 3, "three notifications displayed"); 405 EventUtils.synthesizeMouseAtCenter(notifications[1].closebutton, {}); 406 }, 407 onHidden(popup) { 408 let notifications = popup.children; 409 is(notifications.length, 2, "two notifications displayed"); 410 411 ok(this.notification1.options.persistent, "notification 1 is persistent"); 412 ok( 413 !this.notification2.options.persistent, 414 "notification 2 is not persistent" 415 ); 416 ok(this.notification3.options.persistent, "notification 3 is persistent"); 417 418 this.notification1.remove(); 419 this.notification2.remove(); 420 this.notification3.remove(); 421 }, 422 }, 423 // Test clicking the anchor icon. 424 // Clicking the anchor of an already visible persistent notification should 425 // focus the main action button, but not cause additional showing/shown event 426 // callback calls. 427 // Clicking the anchor of a dismissed notification should show it, even when 428 // the currently displayed notification is a persistent one. 429 { 430 id: "Test#11", 431 async run() { 432 await SpecialPowers.pushPrefEnv({ set: [["accessibility.tabfocus", 7]] }); 433 434 function clickAnchor(notifyObj) { 435 let anchor = document.getElementById(notifyObj.anchorID); 436 EventUtils.synthesizeMouseAtCenter(anchor, {}); 437 } 438 439 let popup = PopupNotifications.panel; 440 441 let notifyObj1 = new BasicNotification(this.id); 442 notifyObj1.id += "_1"; 443 notifyObj1.anchorID = "default-notification-icon"; 444 notifyObj1.options.persistent = true; 445 let shown = waitForNotificationPanel(); 446 let notification1 = showNotification(notifyObj1); 447 await shown; 448 checkPopup(popup, notifyObj1); 449 ok( 450 !notifyObj1.dismissalCallbackTriggered, 451 "Should not have dismissed the notification" 452 ); 453 notifyObj1.shownCallbackTriggered = false; 454 notifyObj1.showingCallbackTriggered = false; 455 456 // Click the anchor. This should focus the closebutton 457 // (because it's the first focusable element), but not 458 // call event callbacks on the notification object. 459 clickAnchor(notifyObj1); 460 is(document.activeElement, popup.children[0].closebutton); 461 ok( 462 !notifyObj1.dismissalCallbackTriggered, 463 "Should not have dismissed the notification" 464 ); 465 ok( 466 !notifyObj1.shownCallbackTriggered, 467 "Should have triggered the shown event again" 468 ); 469 ok( 470 !notifyObj1.showingCallbackTriggered, 471 "Should have triggered the showing event again" 472 ); 473 474 // Add another notification. 475 let notifyObj2 = new BasicNotification(this.id); 476 notifyObj2.id += "_2"; 477 notifyObj2.anchorID = "geo-notification-icon"; 478 notifyObj2.options.dismissed = true; 479 let notification2 = showNotification(notifyObj2); 480 481 // Click the anchor of the second notification, this should dismiss the 482 // first notification. 483 shown = waitForNotificationPanel(); 484 clickAnchor(notifyObj2); 485 await shown; 486 checkPopup(popup, notifyObj2); 487 ok( 488 notifyObj1.dismissalCallbackTriggered, 489 "Should have dismissed the first notification" 490 ); 491 492 // Click the anchor of the first notification, it should be shown again. 493 shown = waitForNotificationPanel(); 494 clickAnchor(notifyObj1); 495 await shown; 496 checkPopup(popup, notifyObj1); 497 ok( 498 notifyObj2.dismissalCallbackTriggered, 499 "Should have dismissed the second notification" 500 ); 501 502 // Cleanup. 503 notification1.remove(); 504 notification2.remove(); 505 goNext(); 506 }, 507 }, 508 ];