browser_devices_get_user_media_screen.js (30942B)
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 // The rejection "The fetching process for the media resource was aborted by the 6 // user agent at the user's request." is left unhandled in some cases. This bug 7 // should be fixed, but for the moment this file allows a class of rejections. 8 // 9 // NOTE: Allowing a whole class of rejections should be avoided. Normally you 10 // should use "expectUncaughtRejection" to flag individual failures. 11 const { PromiseTestUtils } = ChromeUtils.importESModule( 12 "resource://testing-common/PromiseTestUtils.sys.mjs" 13 ); 14 PromiseTestUtils.allowMatchingRejectionsGlobally(/aborted by the user agent/); 15 16 const permissionError = 17 "error: NotAllowedError: The request is not allowed " + 18 "by the user agent or the platform in the current context."; 19 20 const notFoundError = "error: NotFoundError: The object can not be found here."; 21 22 const isHeadless = Services.env.get("MOZ_HEADLESS"); 23 24 function verifyTabSharingPopup(expectedItems) { 25 let event = new MouseEvent("popupshowing"); 26 let sharingMenu = document.getElementById("tabSharingMenuPopup"); 27 sharingMenu.dispatchEvent(event); 28 29 is( 30 sharingMenu.children.length, 31 expectedItems.length, 32 "correct number of items on tab sharing menu" 33 ); 34 for (let i = 0; i < expectedItems.length; i++) { 35 is( 36 JSON.parse(sharingMenu.children[i].getAttribute("data-l10n-args")) 37 .itemList, 38 expectedItems[i], 39 "label of item " + i + " + was correct" 40 ); 41 } 42 43 sharingMenu.dispatchEvent(new MouseEvent("popuphiding")); 44 } 45 46 var gTests = [ 47 { 48 desc: "getUserMedia window/screen picking screen", 49 run: async function checkWindowOrScreen() { 50 let observerPromise = expectObserverCalled("getUserMedia:request"); 51 let promise = promisePopupNotificationShown("webRTC-shareDevices"); 52 await promiseRequestDevice(false, true, null, "screen"); 53 await promise; 54 await observerPromise; 55 56 is( 57 PopupNotifications.getNotification("webRTC-shareDevices").anchorID, 58 "webRTC-shareScreen-notification-icon", 59 "anchored to device icon" 60 ); 61 checkDeviceSelectors(["screen"]); 62 let notification = PopupNotifications.panel.firstElementChild; 63 64 let menulist = document.getElementById("webRTC-selectWindow-menulist"); 65 let count = menulist.itemCount; 66 Assert.greaterOrEqual( 67 count, 68 4, 69 "There should be the 'Select Window or Screen' item, a separator and at least one window and one screen" 70 ); 71 72 let noWindowOrScreenItem = menulist.getItemAtIndex(0); 73 ok( 74 noWindowOrScreenItem.hasAttribute("selected"), 75 "the 'Select Window or Screen' item is selected" 76 ); 77 is( 78 menulist.selectedItem, 79 noWindowOrScreenItem, 80 "'Select Window or Screen' is the selected item" 81 ); 82 is(menulist.value, "-1", "no window or screen is selected by default"); 83 ok( 84 noWindowOrScreenItem.disabled, 85 "'Select Window or Screen' item is disabled" 86 ); 87 ok(notification.button.disabled, "Allow button is disabled"); 88 ok( 89 notification.hasAttribute("invalidselection"), 90 "Notification is marked as invalid" 91 ); 92 93 let separator = menulist.getItemAtIndex(1); 94 is( 95 separator.localName, 96 "menuseparator", 97 "the second item is a separator" 98 ); 99 100 ok( 101 document.getElementById("webRTC-all-windows-shared").hidden, 102 "the 'all windows will be shared' warning should be hidden while there's no selection" 103 ); 104 ok( 105 document.getElementById("webRTC-preview-section").hidden, 106 "the preview area is hidden" 107 ); 108 109 let scaryScreenIndex; 110 for (let i = 2; i < count; ++i) { 111 let item = menulist.getItemAtIndex(i); 112 is( 113 parseInt(item.getAttribute("value")), 114 i - 2, 115 "the window/screen item has the correct index" 116 ); 117 let type = item.getAttribute("devicetype"); 118 ok( 119 ["window", "screen"].includes(type), 120 "the devicetype attribute is set correctly" 121 ); 122 if (type == "screen") { 123 ok(item.scary, "the screen item is marked as scary"); 124 scaryScreenIndex = i; 125 } 126 } 127 Assert.equal( 128 typeof scaryScreenIndex, 129 "number", 130 "there's at least one scary screen, as as all screens are" 131 ); 132 133 // Select a screen, a preview with a scary warning should appear. 134 menulist.getItemAtIndex(scaryScreenIndex).doCommand(); 135 ok( 136 !document.getElementById("webRTC-all-windows-shared").hidden, 137 "the 'all windows will be shared' warning should now be visible" 138 ); 139 await TestUtils.waitForCondition( 140 () => !document.getElementById("webRTC-preview-section").hidden, 141 "preview unhide", 142 100, 143 100 144 ); 145 ok( 146 !document.getElementById("webRTC-preview-section").hidden, 147 "the preview area is visible" 148 ); 149 ok( 150 !document.getElementById("webRTC-previewWarningBox").hidden, 151 "the scary warning is visible" 152 ); 153 ok(!notification.button.disabled, "Allow button is enabled"); 154 155 // Select the 'Select Window or Screen' item again, the preview should be hidden. 156 menulist.getItemAtIndex(0).doCommand(); 157 ok( 158 document.getElementById("webRTC-all-windows-shared").hidden, 159 "the 'all windows will be shared' warning should now be hidden" 160 ); 161 ok( 162 document.getElementById("webRTC-preview-section").hidden, 163 "the preview area is hidden" 164 ); 165 166 // Select the scary screen again so that we can have a stream. 167 menulist.getItemAtIndex(scaryScreenIndex).doCommand(); 168 169 let indicator = promiseIndicatorWindow(); 170 let observerPromise1 = expectObserverCalled( 171 "getUserMedia:response:allow" 172 ); 173 let observerPromise2 = expectObserverCalled("recording-device-events"); 174 await promiseMessage("ok", () => { 175 PopupNotifications.panel.firstElementChild.button.click(); 176 }); 177 await observerPromise1; 178 await observerPromise2; 179 Assert.deepEqual( 180 await getMediaCaptureState(), 181 { screen: "Screen" }, 182 "expected screen to be shared" 183 ); 184 185 await indicator; 186 await checkSharingUI({ screen: "Screen" }); 187 verifyTabSharingPopup(["screen"]); 188 189 // we always show prompt for screen sharing. 190 promise = promisePopupNotificationShown("webRTC-shareDevices"); 191 observerPromise = expectObserverCalled("getUserMedia:request"); 192 await promiseRequestDevice(false, true, null, "screen"); 193 await promise; 194 await observerPromise; 195 196 is( 197 PopupNotifications.getNotification("webRTC-shareDevices").anchorID, 198 "webRTC-shareScreen-notification-icon", 199 "anchored to device icon" 200 ); 201 checkDeviceSelectors(["screen"]); 202 203 observerPromise = expectObserverCalled("getUserMedia:response:deny"); 204 await promiseMessage(permissionError, () => { 205 activateSecondaryAction(kActionDeny); 206 }); 207 208 await observerPromise; 209 SitePermissions.removeFromPrincipal( 210 null, 211 "screen", 212 gBrowser.selectedBrowser 213 ); 214 await closeStream(); 215 }, 216 }, 217 218 { 219 desc: "getUserMedia window/screen picking window", 220 run: async function checkWindowOrScreen() { 221 let observerPromise = expectObserverCalled("getUserMedia:request"); 222 let promise = promisePopupNotificationShown("webRTC-shareDevices"); 223 await promiseRequestDevice(false, true, null, "window"); 224 await promise; 225 await observerPromise; 226 227 is( 228 PopupNotifications.getNotification("webRTC-shareDevices").anchorID, 229 "webRTC-shareScreen-notification-icon", 230 "anchored to device icon" 231 ); 232 checkDeviceSelectors(["screen"]); 233 let notification = PopupNotifications.panel.firstElementChild; 234 235 let menulist = document.getElementById("webRTC-selectWindow-menulist"); 236 let count = menulist.itemCount; 237 Assert.greaterOrEqual( 238 count, 239 4, 240 "There should be the 'Select Window or Screen' item, a separator and at least one window and one screen" 241 ); 242 243 let noWindowOrScreenItem = menulist.getItemAtIndex(0); 244 ok( 245 noWindowOrScreenItem.hasAttribute("selected"), 246 "the 'Select Window or Screen' item is selected" 247 ); 248 is( 249 menulist.selectedItem, 250 noWindowOrScreenItem, 251 "'Select Window or Screen' is the selected item" 252 ); 253 is(menulist.value, "-1", "no window or screen is selected by default"); 254 ok( 255 noWindowOrScreenItem.disabled, 256 "'Select Window or Screen' item is disabled" 257 ); 258 ok(notification.button.disabled, "Allow button is disabled"); 259 ok( 260 notification.hasAttribute("invalidselection"), 261 "Notification is marked as invalid" 262 ); 263 264 let separator = menulist.getItemAtIndex(1); 265 is( 266 separator.localName, 267 "menuseparator", 268 "the second item is a separator" 269 ); 270 271 ok( 272 document.getElementById("webRTC-all-windows-shared").hidden, 273 "the 'all windows will be shared' warning should be hidden while there's no selection" 274 ); 275 ok( 276 document.getElementById("webRTC-preview-section").hidden, 277 "the preview area is hidden" 278 ); 279 280 let scaryWindowIndexes = [], 281 nonScaryWindowIndex, 282 scaryScreenIndex; 283 for (let i = 2; i < count; ++i) { 284 let item = menulist.getItemAtIndex(i); 285 is( 286 parseInt(item.getAttribute("value")), 287 i - 2, 288 "the window/screen item has the correct index" 289 ); 290 let type = item.getAttribute("devicetype"); 291 ok( 292 ["window", "screen"].includes(type), 293 "the devicetype attribute is set correctly" 294 ); 295 if (type == "screen") { 296 ok(item.scary, "the screen item is marked as scary"); 297 scaryScreenIndex = i; 298 } else if (item.scary) { 299 scaryWindowIndexes.push(i); 300 } else { 301 nonScaryWindowIndex = i; 302 } 303 } 304 if (isHeadless) { 305 is( 306 scaryWindowIndexes.length, 307 0, 308 "there are no scary Firefox windows in headless mode" 309 ); 310 } else { 311 ok( 312 scaryWindowIndexes.length, 313 "there's at least one scary window, as Firefox is running" 314 ); 315 } 316 Assert.equal( 317 typeof scaryScreenIndex, 318 "number", 319 "there's at least one scary screen, as all screens are" 320 ); 321 322 if (!isHeadless) { 323 // Select one scary window, a preview with a scary warning should appear. 324 let scaryWindowIndex; 325 for (scaryWindowIndex of scaryWindowIndexes) { 326 menulist.getItemAtIndex(scaryWindowIndex).doCommand(); 327 ok( 328 document.getElementById("webRTC-all-windows-shared").hidden, 329 "the 'all windows will be shared' warning should still be hidden" 330 ); 331 try { 332 await TestUtils.waitForCondition( 333 () => !document.getElementById("webRTC-preview-section").hidden, 334 "", 335 100, 336 100 337 ); 338 break; 339 } catch (e) { 340 // A "scary window" is Firefox. Multiple Firefox windows have been 341 // observed to come and go during try runs, so we won't know which one 342 // is ours. To avoid intermittents, we ignore preview failing due to 343 // these going away on us, provided it succeeds on one of them. 344 } 345 } 346 ok( 347 !document.getElementById("webRTC-preview-section").hidden, 348 "the preview area is visible" 349 ); 350 ok( 351 !document.getElementById("webRTC-previewWarningBox").hidden, 352 "the scary warning is visible" 353 ); 354 // Select the 'Select Window' item again, the preview should be hidden. 355 menulist.getItemAtIndex(0).doCommand(); 356 ok( 357 document.getElementById("webRTC-preview-section").hidden, 358 "the preview area is hidden" 359 ); 360 361 // Select the first window again so that we can have a stream. 362 menulist.getItemAtIndex(scaryWindowIndex).doCommand(); 363 } 364 365 let sharingNonScaryWindow = typeof nonScaryWindowIndex == "number"; 366 367 // If we have a non-scary window, select it and verify the warning isn't displayed. 368 // A non-scary window may not always exist on test machines. 369 if (sharingNonScaryWindow) { 370 menulist.getItemAtIndex(nonScaryWindowIndex).doCommand(); 371 ok( 372 document.getElementById("webRTC-all-windows-shared").hidden, 373 "the 'all windows will be shared' warning should still be hidden" 374 ); 375 await TestUtils.waitForCondition( 376 () => !document.getElementById("webRTC-preview-section").hidden, 377 "preview unhide", 378 100, 379 100 380 ); 381 ok( 382 !document.getElementById("webRTC-preview-section").hidden, 383 "the preview area is visible" 384 ); 385 ok( 386 document.getElementById("webRTC-previewWarningBox").hidden, 387 "the scary warning is hidden" 388 ); 389 } else { 390 info("no non-scary window available on this test machine"); 391 } 392 393 let indicator = promiseIndicatorWindow(); 394 let observerPromise1 = expectObserverCalled( 395 "getUserMedia:response:allow" 396 ); 397 let observerPromise2 = expectObserverCalled("recording-device-events"); 398 await promiseMessage("ok", () => { 399 PopupNotifications.panel.firstElementChild.button.click(); 400 }); 401 await observerPromise1; 402 await observerPromise2; 403 Assert.deepEqual( 404 await getMediaCaptureState(), 405 { window: true }, 406 "expected screen to be shared" 407 ); 408 409 await indicator; 410 if (sharingNonScaryWindow) { 411 await checkSharingUI({ screen: "Window" }); 412 } else { 413 await checkSharingUI({ screen: "Window", browserwindow: true }); 414 } 415 416 verifyTabSharingPopup(["window"]); 417 418 await closeStream(); 419 }, 420 }, 421 422 { 423 desc: "getUserMedia audio + window/screen", 424 run: async function checkAudioVideo() { 425 if (AppConstants.platform == "macosx") { 426 todo( 427 false, 428 "Bug 1323481 - On Mac on treeherder, but not locally, requesting microphone + screen never makes the permission prompt appear, and so causes the test to timeout" 429 ); 430 return; 431 } 432 433 let observerPromise = expectObserverCalled("getUserMedia:request"); 434 let promise = promisePopupNotificationShown("webRTC-shareDevices"); 435 await promiseRequestDevice(true, true, null, "window"); 436 await promise; 437 await observerPromise; 438 439 is( 440 PopupNotifications.getNotification("webRTC-shareDevices").anchorID, 441 "webRTC-shareScreen-notification-icon", 442 "anchored to device icon" 443 ); 444 checkDeviceSelectors(["microphone", "screen"]); 445 446 let menulist = document.getElementById("webRTC-selectWindow-menulist"); 447 let count = menulist.itemCount; 448 Assert.greaterOrEqual( 449 count, 450 4, 451 "There should be the 'Select Window or Screen' item, a separator and at least one window and one screen" 452 ); 453 454 // Select a screen, a preview with a scary warning should appear. 455 menulist.getItemAtIndex(count - 1).doCommand(); 456 ok( 457 !document.getElementById("webRTC-all-windows-shared").hidden, 458 "the 'all windows will be shared' warning should now be visible" 459 ); 460 await TestUtils.waitForCondition( 461 () => !document.getElementById("webRTC-preview-section").hidden, 462 "preview unhide", 463 100, 464 100 465 ); 466 ok( 467 !document.getElementById("webRTC-preview-section").hidden, 468 "the preview area is visible" 469 ); 470 ok( 471 !document.getElementById("webRTC-previewWarningBox").hidden, 472 "the scary warning is visible" 473 ); 474 475 let indicator = promiseIndicatorWindow(); 476 let observerPromise1 = expectObserverCalled( 477 "getUserMedia:response:allow" 478 ); 479 let observerPromise2 = expectObserverCalled("recording-device-events"); 480 await promiseMessage("ok", () => { 481 PopupNotifications.panel.firstElementChild.button.click(); 482 }); 483 await observerPromise1; 484 await observerPromise2; 485 Assert.deepEqual( 486 await getMediaCaptureState(), 487 { audio: true, screen: "Screen" }, 488 "expected screen and microphone to be shared" 489 ); 490 491 await indicator; 492 await checkSharingUI({ audio: true, screen: "Screen" }); 493 494 verifyTabSharingPopup(["microphone and screen"]); 495 496 await closeStream(); 497 }, 498 }, 499 500 { 501 desc: 'getUserMedia screen, user clicks "Don\'t Allow"', 502 run: async function checkDontShare() { 503 let observerPromise = expectObserverCalled("getUserMedia:request"); 504 let promise = promisePopupNotificationShown("webRTC-shareDevices"); 505 await promiseRequestDevice(false, true, null, "screen"); 506 await promise; 507 await observerPromise; 508 checkDeviceSelectors(["screen"]); 509 510 let observerPromise1 = expectObserverCalled("getUserMedia:response:deny"); 511 let observerPromise2 = expectObserverCalled("recording-window-ended"); 512 await promiseMessage(permissionError, () => { 513 activateSecondaryAction(kActionDeny); 514 }); 515 516 await observerPromise1; 517 await observerPromise2; 518 await checkNotSharing(); 519 SitePermissions.removeFromPrincipal( 520 null, 521 "screen", 522 gBrowser.selectedBrowser 523 ); 524 SitePermissions.removeFromPrincipal( 525 null, 526 "camera", 527 gBrowser.selectedBrowser 528 ); 529 }, 530 }, 531 532 { 533 desc: "getUserMedia audio + window/screen: stop sharing", 534 run: async function checkStopSharing() { 535 if (AppConstants.platform == "macosx") { 536 todo( 537 false, 538 "Bug 1323481 - On Mac on treeherder, but not locally, requesting microphone + screen never makes the permission prompt appear, and so causes the test to timeout" 539 ); 540 return; 541 } 542 543 async function share(deviceTypes) { 544 let promise = promisePopupNotificationShown("webRTC-shareDevices"); 545 let observerPromise = expectObserverCalled("getUserMedia:request"); 546 await promiseRequestDevice( 547 /* audio */ deviceTypes.includes("microphone"), 548 /* video */ deviceTypes.some(t => t == "screen" || t == "camera"), 549 null, 550 deviceTypes.includes("screen") && "window" 551 ); 552 await promise; 553 await observerPromise; 554 checkDeviceSelectors(deviceTypes); 555 if (screen) { 556 let menulist = document.getElementById( 557 "webRTC-selectWindow-menulist" 558 ); 559 menulist.getItemAtIndex(menulist.itemCount - 1).doCommand(); 560 } 561 let observerPromise1 = expectObserverCalled( 562 "getUserMedia:response:allow" 563 ); 564 let observerPromise2 = expectObserverCalled("recording-device-events"); 565 await promiseMessage("ok", () => { 566 PopupNotifications.panel.firstElementChild.button.click(); 567 }); 568 await observerPromise1; 569 await observerPromise2; 570 } 571 572 async function check(expected = {}, expectedSharingLabel) { 573 let shared = Object.keys(expected).join(" and "); 574 if (shared) { 575 Assert.deepEqual( 576 await getMediaCaptureState(), 577 expected, 578 "expected " + shared + " to be shared" 579 ); 580 await checkSharingUI(expected); 581 verifyTabSharingPopup([expectedSharingLabel]); 582 } else { 583 await checkNotSharing(); 584 verifyTabSharingPopup([""]); 585 } 586 } 587 588 info("Share screen and microphone"); 589 let indicator = promiseIndicatorWindow(); 590 await share(["microphone", "screen"]); 591 await indicator; 592 await check({ audio: true, screen: "Screen" }, "microphone and screen"); 593 594 info("Share camera"); 595 await share(["camera"]); 596 await check( 597 { video: true, audio: true, screen: "Screen" }, 598 "microphone, screen, and camera" 599 ); 600 601 info("Stop the screen share, mic+cam should continue"); 602 await stopSharing("screen", true); 603 await check({ video: true, audio: true }, "microphone and camera"); 604 605 info("Stop the camera, everything should stop."); 606 await stopSharing("camera"); 607 608 info("Now, share only the screen..."); 609 indicator = promiseIndicatorWindow(); 610 await share(["screen"]); 611 await indicator; 612 await check({ screen: "Screen" }, "screen"); 613 614 info("... and add camera and microphone in a second request."); 615 await share(["microphone", "camera"]); 616 await check( 617 { video: true, audio: true, screen: "Screen" }, 618 "screen, microphone, and camera" 619 ); 620 621 info("Stop the camera, this should stop everything."); 622 await stopSharing("camera"); 623 }, 624 }, 625 626 { 627 desc: "getUserMedia window/screen: reloading the page removes all gUM UI", 628 run: async function checkReloading() { 629 let observerPromise = expectObserverCalled("getUserMedia:request"); 630 let promise = promisePopupNotificationShown("webRTC-shareDevices"); 631 await promiseRequestDevice(false, true, null, "screen"); 632 await promise; 633 await observerPromise; 634 checkDeviceSelectors(["screen"]); 635 let menulist = document.getElementById("webRTC-selectWindow-menulist"); 636 menulist.getItemAtIndex(menulist.itemCount - 1).doCommand(); 637 638 let indicator = promiseIndicatorWindow(); 639 let observerPromise1 = expectObserverCalled( 640 "getUserMedia:response:allow" 641 ); 642 let observerPromise2 = expectObserverCalled("recording-device-events"); 643 await promiseMessage("ok", () => { 644 PopupNotifications.panel.firstElementChild.button.click(); 645 }); 646 await observerPromise1; 647 await observerPromise2; 648 Assert.deepEqual( 649 await getMediaCaptureState(), 650 { screen: "Screen" }, 651 "expected screen to be shared" 652 ); 653 654 await indicator; 655 await checkSharingUI({ screen: "Screen" }); 656 verifyTabSharingPopup(["screen"]); 657 658 await reloadAndAssertClosedStreams(); 659 }, 660 }, 661 662 { 663 desc: "Only persistent block is possible for screen sharing", 664 run: async function checkPersistentPermissions() { 665 // This test doesn't apply when the notification silencing 666 // feature is enabled, since the "Remember this decision" 667 // checkbox doesn't exist. 668 if (ALLOW_SILENCING_NOTIFICATIONS) { 669 return; 670 } 671 672 let browser = gBrowser.selectedBrowser; 673 let devicePerms = SitePermissions.getForPrincipal( 674 browser.contentPrincipal, 675 "screen", 676 browser 677 ); 678 is( 679 devicePerms.state, 680 SitePermissions.UNKNOWN, 681 "starting without screen persistent permissions" 682 ); 683 684 let observerPromise = expectObserverCalled("getUserMedia:request"); 685 let promise = promisePopupNotificationShown("webRTC-shareDevices"); 686 await promiseRequestDevice(false, true, null, "screen"); 687 await promise; 688 await observerPromise; 689 checkDeviceSelectors(["screen"]); 690 document 691 .getElementById("webRTC-selectWindow-menulist") 692 .getItemAtIndex(2) 693 .doCommand(); 694 695 // Ensure that checking the 'Remember this decision' checkbox disables 696 // 'Allow'. 697 let notification = PopupNotifications.panel.firstElementChild; 698 ok( 699 notification.hasAttribute("warninghidden"), 700 "warning message is hidden" 701 ); 702 let checkbox = notification.checkbox; 703 ok(!!checkbox, "checkbox is present"); 704 ok(!checkbox.checked, "checkbox is not checked"); 705 checkbox.click(); 706 ok(checkbox.checked, "checkbox now checked"); 707 ok(notification.button.disabled, "Allow button is disabled"); 708 ok( 709 !notification.hasAttribute("warninghidden"), 710 "warning message is shown" 711 ); 712 713 // Click "Don't Allow" to save a persistent block permission. 714 let observerPromise1 = expectObserverCalled("getUserMedia:response:deny"); 715 let observerPromise2 = expectObserverCalled("recording-window-ended"); 716 await promiseMessage(permissionError, () => { 717 activateSecondaryAction(kActionDeny); 718 }); 719 await observerPromise1; 720 await observerPromise2; 721 await checkNotSharing(); 722 723 let permission = SitePermissions.getForPrincipal( 724 browser.contentPrincipal, 725 "screen", 726 browser 727 ); 728 is(permission.state, SitePermissions.BLOCK, "screen sharing is blocked"); 729 is( 730 permission.scope, 731 SitePermissions.SCOPE_PERSISTENT, 732 "screen sharing is persistently blocked" 733 ); 734 735 // Request screensharing again, expect an immediate failure. 736 await Promise.all([ 737 expectObserverCalled("getUserMedia:request"), 738 expectObserverCalled("getUserMedia:response:deny"), 739 expectObserverCalled("recording-window-ended"), 740 promiseMessage(permissionError), 741 promiseRequestDevice(false, true, null, "screen"), 742 ]); 743 744 // Now set the permission to allow and expect a prompt. 745 SitePermissions.setForPrincipal( 746 browser.contentPrincipal, 747 "screen", 748 SitePermissions.ALLOW 749 ); 750 751 // Request devices and expect a prompt despite the saved 'Allow' permission. 752 observerPromise = expectObserverCalled("getUserMedia:request"); 753 promise = promisePopupNotificationShown("webRTC-shareDevices"); 754 await promiseRequestDevice(false, true, null, "screen"); 755 await promise; 756 await observerPromise; 757 758 // The 'remember' checkbox shouldn't be checked anymore. 759 notification = PopupNotifications.panel.firstElementChild; 760 ok( 761 notification.hasAttribute("warninghidden"), 762 "warning message is hidden" 763 ); 764 checkbox = notification.checkbox; 765 ok(!!checkbox, "checkbox is present"); 766 ok(!checkbox.checked, "checkbox is not checked"); 767 768 // Deny the request to cleanup... 769 observerPromise1 = expectObserverCalled("getUserMedia:response:deny"); 770 observerPromise2 = expectObserverCalled("recording-window-ended"); 771 await promiseMessage(permissionError, () => { 772 activateSecondaryAction(kActionDeny); 773 }); 774 await observerPromise1; 775 await observerPromise2; 776 SitePermissions.removeFromPrincipal( 777 browser.contentPrincipal, 778 "screen", 779 browser 780 ); 781 }, 782 }, 783 784 { 785 desc: "Switching between menu options maintains correct main action state while window sharing", 786 skipObserverVerification: true, 787 run: async function checkDoorhangerState() { 788 await enableObserverVerification(); 789 790 let win = await BrowserTestUtils.openNewBrowserWindow(); 791 await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:newtab"); 792 BrowserWindowTracker.orderedWindows[1].focus(); 793 794 let observerPromise = expectObserverCalled("getUserMedia:request"); 795 let promise = promisePopupNotificationShown("webRTC-shareDevices"); 796 await promiseRequestDevice(false, true, null, "window"); 797 await promise; 798 await observerPromise; 799 800 let menulist = document.getElementById("webRTC-selectWindow-menulist"); 801 let notification = PopupNotifications.panel.firstElementChild; 802 let checkbox = notification.checkbox; 803 804 menulist.getItemAtIndex(2).doCommand(); 805 checkbox.click(); 806 ok(checkbox.checked, "checkbox now checked"); 807 808 if (ALLOW_SILENCING_NOTIFICATIONS) { 809 // When the notification silencing feature is enabled, the checkbox 810 // controls that feature, and its state should not disable the 811 // "Allow" button. 812 ok(!notification.button.disabled, "Allow button is not disabled"); 813 } else { 814 ok(notification.button.disabled, "Allow button is disabled"); 815 ok( 816 !notification.hasAttribute("warninghidden"), 817 "warning message is shown" 818 ); 819 } 820 821 menulist.getItemAtIndex(3).doCommand(); 822 ok(checkbox.checked, "checkbox still checked"); 823 if (ALLOW_SILENCING_NOTIFICATIONS) { 824 // When the notification silencing feature is enabled, the checkbox 825 // controls that feature, and its state should not disable the 826 // "Allow" button. 827 ok(!notification.button.disabled, "Allow button remains not disabled"); 828 } else { 829 ok(notification.button.disabled, "Allow button remains disabled"); 830 ok( 831 !notification.hasAttribute("warninghidden"), 832 "warning message is still shown" 833 ); 834 } 835 836 await disableObserverVerification(); 837 838 observerPromise = expectObserverCalled("recording-window-ended"); 839 840 gBrowser.removeCurrentTab(); 841 win.close(); 842 843 await observerPromise; 844 845 await openNewTestTab(); 846 }, 847 }, 848 { 849 desc: "Switching between tabs does not bleed state into other prompts", 850 skipObserverVerification: true, 851 run: async function checkSwitchingTabs() { 852 // Open a new window in the background to have a choice in the menulist. 853 let win = await BrowserTestUtils.openNewBrowserWindow(); 854 await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:newtab"); 855 await enableObserverVerification(); 856 BrowserWindowTracker.orderedWindows[1].focus(); 857 858 let observerPromise = expectObserverCalled("getUserMedia:request"); 859 let promise = promisePopupNotificationShown("webRTC-shareDevices"); 860 await promiseRequestDevice(false, true, null, "window"); 861 await promise; 862 await observerPromise; 863 864 let notification = PopupNotifications.panel.firstElementChild; 865 ok(notification.button.disabled, "Allow button is disabled"); 866 await disableObserverVerification(); 867 868 await openNewTestTab("get_user_media_in_xorigin_frame.html"); 869 await enableObserverVerification(); 870 871 observerPromise = expectObserverCalled("getUserMedia:request"); 872 promise = promisePopupNotificationShown("webRTC-shareDevices"); 873 await promiseRequestDevice(true, true, "frame1"); 874 await promise; 875 await observerPromise; 876 877 notification = PopupNotifications.panel.firstElementChild; 878 ok(!notification.button.disabled, "Allow button is not disabled"); 879 880 await disableObserverVerification(); 881 882 gBrowser.removeCurrentTab(); 883 gBrowser.removeCurrentTab(); 884 win.close(); 885 886 await openNewTestTab(); 887 }, 888 }, 889 ]; 890 891 add_task(async function test() { 892 await runTests(gTests); 893 });