summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js')
-rw-r--r--browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js949
1 files changed, 949 insertions, 0 deletions
diff --git a/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js b/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
new file mode 100644
index 0000000000..d09d7f2c5f
--- /dev/null
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
@@ -0,0 +1,949 @@
+/* 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/. */
+
+// The rejection "The fetching process for the media resource was aborted by the
+// user agent at the user's request." is left unhandled in some cases. This bug
+// should be fixed, but for the moment this file allows a class of rejections.
+//
+// NOTE: Allowing a whole class of rejections should be avoided. Normally you
+// should use "expectUncaughtRejection" to flag individual failures.
+const { PromiseTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PromiseTestUtils.sys.mjs"
+);
+PromiseTestUtils.allowMatchingRejectionsGlobally(/aborted by the user agent/);
+
+const permissionError =
+ "error: NotAllowedError: The request is not allowed " +
+ "by the user agent or the platform in the current context.";
+
+const notFoundError = "error: NotFoundError: The object can not be found here.";
+
+const isHeadless = Services.env.get("MOZ_HEADLESS");
+
+function verifyTabSharingPopup(expectedItems) {
+ let event = new MouseEvent("popupshowing");
+ let sharingMenu = document.getElementById("tabSharingMenuPopup");
+ sharingMenu.dispatchEvent(event);
+
+ is(
+ sharingMenu.children.length,
+ expectedItems.length,
+ "correct number of items on tab sharing menu"
+ );
+ for (let i = 0; i < expectedItems.length; i++) {
+ is(
+ JSON.parse(sharingMenu.children[i].getAttribute("data-l10n-args"))
+ .itemList,
+ expectedItems[i],
+ "label of item " + i + " + was correct"
+ );
+ }
+
+ sharingMenu.dispatchEvent(new MouseEvent("popuphiding"));
+}
+
+var gTests = [
+ {
+ desc: "getUserMedia window/screen picking screen",
+ run: async function checkWindowOrScreen() {
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "screen");
+ await promise;
+ await observerPromise;
+
+ is(
+ PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
+ "webRTC-shareScreen-notification-icon",
+ "anchored to device icon"
+ );
+ checkDeviceSelectors(["screen"]);
+ let notification = PopupNotifications.panel.firstElementChild;
+
+ let menulist = document.getElementById("webRTC-selectWindow-menulist");
+ let count = menulist.itemCount;
+ ok(
+ count >= 4,
+ "There should be the 'Select Window or Screen' item, a separator and at least one window and one screen"
+ );
+
+ let noWindowOrScreenItem = menulist.getItemAtIndex(0);
+ ok(
+ noWindowOrScreenItem.hasAttribute("selected"),
+ "the 'Select Window or Screen' item is selected"
+ );
+ is(
+ menulist.selectedItem,
+ noWindowOrScreenItem,
+ "'Select Window or Screen' is the selected item"
+ );
+ is(menulist.value, "-1", "no window or screen is selected by default");
+ ok(
+ noWindowOrScreenItem.disabled,
+ "'Select Window or Screen' item is disabled"
+ );
+ ok(notification.button.disabled, "Allow button is disabled");
+ ok(
+ notification.hasAttribute("invalidselection"),
+ "Notification is marked as invalid"
+ );
+
+ let separator = menulist.getItemAtIndex(1);
+ is(
+ separator.localName,
+ "menuseparator",
+ "the second item is a separator"
+ );
+
+ ok(
+ document.getElementById("webRTC-all-windows-shared").hidden,
+ "the 'all windows will be shared' warning should be hidden while there's no selection"
+ );
+ ok(
+ document.getElementById("webRTC-preview").hidden,
+ "the preview area is hidden"
+ );
+
+ let scaryScreenIndex;
+ for (let i = 2; i < count; ++i) {
+ let item = menulist.getItemAtIndex(i);
+ is(
+ parseInt(item.getAttribute("value")),
+ i - 2,
+ "the window/screen item has the correct index"
+ );
+ let type = item.getAttribute("devicetype");
+ ok(
+ ["window", "screen"].includes(type),
+ "the devicetype attribute is set correctly"
+ );
+ if (type == "screen") {
+ ok(item.scary, "the screen item is marked as scary");
+ scaryScreenIndex = i;
+ }
+ }
+ ok(
+ typeof scaryScreenIndex == "number",
+ "there's at least one scary screen, as as all screens are"
+ );
+
+ // Select a screen, a preview with a scary warning should appear.
+ menulist.getItemAtIndex(scaryScreenIndex).doCommand();
+ ok(
+ !document.getElementById("webRTC-all-windows-shared").hidden,
+ "the 'all windows will be shared' warning should now be visible"
+ );
+ await TestUtils.waitForCondition(
+ () => !document.getElementById("webRTC-preview").hidden,
+ "preview unhide",
+ 100,
+ 100
+ );
+ ok(
+ !document.getElementById("webRTC-preview").hidden,
+ "the preview area is visible"
+ );
+ ok(
+ !document.getElementById("webRTC-previewWarningBox").hidden,
+ "the scary warning is visible"
+ );
+ ok(!notification.button.disabled, "Allow button is enabled");
+
+ // Select the 'Select Window or Screen' item again, the preview should be hidden.
+ menulist.getItemAtIndex(0).doCommand();
+ ok(
+ document.getElementById("webRTC-all-windows-shared").hidden,
+ "the 'all windows will be shared' warning should now be hidden"
+ );
+ ok(
+ document.getElementById("webRTC-preview").hidden,
+ "the preview area is hidden"
+ );
+
+ // Select the scary screen again so that we can have a stream.
+ menulist.getItemAtIndex(scaryScreenIndex).doCommand();
+
+ let indicator = promiseIndicatorWindow();
+ let observerPromise1 = expectObserverCalled(
+ "getUserMedia:response:allow"
+ );
+ let observerPromise2 = expectObserverCalled("recording-device-events");
+ await promiseMessage("ok", () => {
+ PopupNotifications.panel.firstElementChild.button.click();
+ });
+ await observerPromise1;
+ await observerPromise2;
+ Assert.deepEqual(
+ await getMediaCaptureState(),
+ { screen: "Screen" },
+ "expected screen to be shared"
+ );
+
+ await indicator;
+ await checkSharingUI({ screen: "Screen" });
+ verifyTabSharingPopup(["screen"]);
+
+ // we always show prompt for screen sharing.
+ promise = promisePopupNotificationShown("webRTC-shareDevices");
+ observerPromise = expectObserverCalled("getUserMedia:request");
+ await promiseRequestDevice(false, true, null, "screen");
+ await promise;
+ await observerPromise;
+
+ is(
+ PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
+ "webRTC-shareScreen-notification-icon",
+ "anchored to device icon"
+ );
+ checkDeviceSelectors(["screen"]);
+
+ observerPromise = expectObserverCalled("getUserMedia:response:deny");
+ await promiseMessage(permissionError, () => {
+ activateSecondaryAction(kActionDeny);
+ });
+
+ await observerPromise;
+ SitePermissions.removeFromPrincipal(
+ null,
+ "screen",
+ gBrowser.selectedBrowser
+ );
+ await closeStream();
+ },
+ },
+
+ {
+ desc: "getUserMedia window/screen picking window",
+ run: async function checkWindowOrScreen() {
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "window");
+ await promise;
+ await observerPromise;
+
+ is(
+ PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
+ "webRTC-shareScreen-notification-icon",
+ "anchored to device icon"
+ );
+ checkDeviceSelectors(["screen"]);
+ let notification = PopupNotifications.panel.firstElementChild;
+
+ let menulist = document.getElementById("webRTC-selectWindow-menulist");
+ let count = menulist.itemCount;
+ ok(
+ count >= 4,
+ "There should be the 'Select Window or Screen' item, a separator and at least one window and one screen"
+ );
+
+ let noWindowOrScreenItem = menulist.getItemAtIndex(0);
+ ok(
+ noWindowOrScreenItem.hasAttribute("selected"),
+ "the 'Select Window or Screen' item is selected"
+ );
+ is(
+ menulist.selectedItem,
+ noWindowOrScreenItem,
+ "'Select Window or Screen' is the selected item"
+ );
+ is(menulist.value, "-1", "no window or screen is selected by default");
+ ok(
+ noWindowOrScreenItem.disabled,
+ "'Select Window or Screen' item is disabled"
+ );
+ ok(notification.button.disabled, "Allow button is disabled");
+ ok(
+ notification.hasAttribute("invalidselection"),
+ "Notification is marked as invalid"
+ );
+
+ let separator = menulist.getItemAtIndex(1);
+ is(
+ separator.localName,
+ "menuseparator",
+ "the second item is a separator"
+ );
+
+ ok(
+ document.getElementById("webRTC-all-windows-shared").hidden,
+ "the 'all windows will be shared' warning should be hidden while there's no selection"
+ );
+ ok(
+ document.getElementById("webRTC-preview").hidden,
+ "the preview area is hidden"
+ );
+
+ let scaryWindowIndexes = [],
+ nonScaryWindowIndex,
+ scaryScreenIndex;
+ for (let i = 2; i < count; ++i) {
+ let item = menulist.getItemAtIndex(i);
+ is(
+ parseInt(item.getAttribute("value")),
+ i - 2,
+ "the window/screen item has the correct index"
+ );
+ let type = item.getAttribute("devicetype");
+ ok(
+ ["window", "screen"].includes(type),
+ "the devicetype attribute is set correctly"
+ );
+ if (type == "screen") {
+ ok(item.scary, "the screen item is marked as scary");
+ scaryScreenIndex = i;
+ } else if (item.scary) {
+ scaryWindowIndexes.push(i);
+ } else {
+ nonScaryWindowIndex = i;
+ }
+ }
+ if (isHeadless) {
+ is(
+ scaryWindowIndexes.length,
+ 0,
+ "there are no scary Firefox windows in headless mode"
+ );
+ } else {
+ ok(
+ scaryWindowIndexes.length,
+ "there's at least one scary window, as Firefox is running"
+ );
+ }
+ ok(
+ typeof scaryScreenIndex == "number",
+ "there's at least one scary screen, as all screens are"
+ );
+
+ if (!isHeadless) {
+ // Select one scary window, a preview with a scary warning should appear.
+ let scaryWindowIndex;
+ for (scaryWindowIndex of scaryWindowIndexes) {
+ menulist.getItemAtIndex(scaryWindowIndex).doCommand();
+ ok(
+ document.getElementById("webRTC-all-windows-shared").hidden,
+ "the 'all windows will be shared' warning should still be hidden"
+ );
+ try {
+ await TestUtils.waitForCondition(
+ () => !document.getElementById("webRTC-preview").hidden,
+ "",
+ 100,
+ 100
+ );
+ break;
+ } catch (e) {
+ // A "scary window" is Firefox. Multiple Firefox windows have been
+ // observed to come and go during try runs, so we won't know which one
+ // is ours. To avoid intermittents, we ignore preview failing due to
+ // these going away on us, provided it succeeds on one of them.
+ }
+ }
+ ok(
+ !document.getElementById("webRTC-preview").hidden,
+ "the preview area is visible"
+ );
+ ok(
+ !document.getElementById("webRTC-previewWarningBox").hidden,
+ "the scary warning is visible"
+ );
+ // Select the 'Select Window' item again, the preview should be hidden.
+ menulist.getItemAtIndex(0).doCommand();
+ ok(
+ document.getElementById("webRTC-preview").hidden,
+ "the preview area is hidden"
+ );
+
+ // Select the first window again so that we can have a stream.
+ menulist.getItemAtIndex(scaryWindowIndex).doCommand();
+ }
+
+ let sharingNonScaryWindow = typeof nonScaryWindowIndex == "number";
+
+ // If we have a non-scary window, select it and verify the warning isn't displayed.
+ // A non-scary window may not always exist on test machines.
+ if (sharingNonScaryWindow) {
+ menulist.getItemAtIndex(nonScaryWindowIndex).doCommand();
+ ok(
+ document.getElementById("webRTC-all-windows-shared").hidden,
+ "the 'all windows will be shared' warning should still be hidden"
+ );
+ await TestUtils.waitForCondition(
+ () => !document.getElementById("webRTC-preview").hidden,
+ "preview unhide",
+ 100,
+ 100
+ );
+ ok(
+ !document.getElementById("webRTC-preview").hidden,
+ "the preview area is visible"
+ );
+ ok(
+ document.getElementById("webRTC-previewWarningBox").hidden,
+ "the scary warning is hidden"
+ );
+ } else {
+ info("no non-scary window available on this test machine");
+ }
+
+ let indicator = promiseIndicatorWindow();
+ let observerPromise1 = expectObserverCalled(
+ "getUserMedia:response:allow"
+ );
+ let observerPromise2 = expectObserverCalled("recording-device-events");
+ await promiseMessage("ok", () => {
+ PopupNotifications.panel.firstElementChild.button.click();
+ });
+ await observerPromise1;
+ await observerPromise2;
+ Assert.deepEqual(
+ await getMediaCaptureState(),
+ { screen: "Window" },
+ "expected screen to be shared"
+ );
+
+ await indicator;
+ if (sharingNonScaryWindow) {
+ await checkSharingUI({ screen: "Window" });
+ } else {
+ await checkSharingUI({ screen: "Window", browserwindow: true });
+ }
+
+ verifyTabSharingPopup(["window"]);
+
+ await closeStream();
+ },
+ },
+
+ {
+ desc: "getUserMedia audio + window/screen",
+ run: async function checkAudioVideo() {
+ if (AppConstants.platform == "macosx") {
+ todo(
+ false,
+ "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"
+ );
+ return;
+ }
+
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(true, true, null, "window");
+ await promise;
+ await observerPromise;
+
+ is(
+ PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
+ "webRTC-shareScreen-notification-icon",
+ "anchored to device icon"
+ );
+ checkDeviceSelectors(["microphone", "screen"]);
+
+ let menulist = document.getElementById("webRTC-selectWindow-menulist");
+ let count = menulist.itemCount;
+ ok(
+ count >= 4,
+ "There should be the 'Select Window or Screen' item, a separator and at least one window and one screen"
+ );
+
+ // Select a screen, a preview with a scary warning should appear.
+ menulist.getItemAtIndex(count - 1).doCommand();
+ ok(
+ !document.getElementById("webRTC-all-windows-shared").hidden,
+ "the 'all windows will be shared' warning should now be visible"
+ );
+ await TestUtils.waitForCondition(
+ () => !document.getElementById("webRTC-preview").hidden,
+ "preview unhide",
+ 100,
+ 100
+ );
+ ok(
+ !document.getElementById("webRTC-preview").hidden,
+ "the preview area is visible"
+ );
+ ok(
+ !document.getElementById("webRTC-previewWarningBox").hidden,
+ "the scary warning is visible"
+ );
+
+ let indicator = promiseIndicatorWindow();
+ let observerPromise1 = expectObserverCalled(
+ "getUserMedia:response:allow"
+ );
+ let observerPromise2 = expectObserverCalled("recording-device-events");
+ await promiseMessage("ok", () => {
+ PopupNotifications.panel.firstElementChild.button.click();
+ });
+ await observerPromise1;
+ await observerPromise2;
+ Assert.deepEqual(
+ await getMediaCaptureState(),
+ { audio: true, screen: "Screen" },
+ "expected screen and microphone to be shared"
+ );
+
+ await indicator;
+ await checkSharingUI({ audio: true, screen: "Screen" });
+
+ verifyTabSharingPopup(["microphone and screen"]);
+
+ await closeStream();
+ },
+ },
+
+ {
+ desc: 'getUserMedia screen, user clicks "Don\'t Allow"',
+ run: async function checkDontShare() {
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "screen");
+ await promise;
+ await observerPromise;
+ checkDeviceSelectors(["screen"]);
+
+ let observerPromise1 = expectObserverCalled("getUserMedia:response:deny");
+ let observerPromise2 = expectObserverCalled("recording-window-ended");
+ await promiseMessage(permissionError, () => {
+ activateSecondaryAction(kActionDeny);
+ });
+
+ await observerPromise1;
+ await observerPromise2;
+ await checkNotSharing();
+ SitePermissions.removeFromPrincipal(
+ null,
+ "screen",
+ gBrowser.selectedBrowser
+ );
+ SitePermissions.removeFromPrincipal(
+ null,
+ "camera",
+ gBrowser.selectedBrowser
+ );
+ },
+ },
+
+ {
+ desc: "getUserMedia audio + window/screen: stop sharing",
+ run: async function checkStopSharing() {
+ if (AppConstants.platform == "macosx") {
+ todo(
+ false,
+ "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"
+ );
+ return;
+ }
+
+ async function share(deviceTypes) {
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ await promiseRequestDevice(
+ /* audio */ deviceTypes.includes("microphone"),
+ /* video */ deviceTypes.some(t => t == "screen" || t == "camera"),
+ null,
+ deviceTypes.includes("screen") && "window"
+ );
+ await promise;
+ await observerPromise;
+ checkDeviceSelectors(deviceTypes);
+ if (screen) {
+ let menulist = document.getElementById(
+ "webRTC-selectWindow-menulist"
+ );
+ menulist.getItemAtIndex(menulist.itemCount - 1).doCommand();
+ }
+ let observerPromise1 = expectObserverCalled(
+ "getUserMedia:response:allow"
+ );
+ let observerPromise2 = expectObserverCalled("recording-device-events");
+ await promiseMessage("ok", () => {
+ PopupNotifications.panel.firstElementChild.button.click();
+ });
+ await observerPromise1;
+ await observerPromise2;
+ }
+
+ async function check(expected = {}, expectedSharingLabel) {
+ let shared = Object.keys(expected).join(" and ");
+ if (shared) {
+ Assert.deepEqual(
+ await getMediaCaptureState(),
+ expected,
+ "expected " + shared + " to be shared"
+ );
+ await checkSharingUI(expected);
+ verifyTabSharingPopup([expectedSharingLabel]);
+ } else {
+ await checkNotSharing();
+ verifyTabSharingPopup([""]);
+ }
+ }
+
+ info("Share screen and microphone");
+ let indicator = promiseIndicatorWindow();
+ await share(["microphone", "screen"]);
+ await indicator;
+ await check({ audio: true, screen: "Screen" }, "microphone and screen");
+
+ info("Share camera");
+ await share(["camera"]);
+ await check(
+ { video: true, audio: true, screen: "Screen" },
+ "microphone, screen, and camera"
+ );
+
+ info("Stop the screen share, mic+cam should continue");
+ await stopSharing("screen", true);
+ await check({ video: true, audio: true }, "microphone and camera");
+
+ info("Stop the camera, everything should stop.");
+ await stopSharing("camera");
+
+ info("Now, share only the screen...");
+ indicator = promiseIndicatorWindow();
+ await share(["screen"]);
+ await indicator;
+ await check({ screen: "Screen" }, "screen");
+
+ info("... and add camera and microphone in a second request.");
+ await share(["microphone", "camera"]);
+ await check(
+ { video: true, audio: true, screen: "Screen" },
+ "screen, microphone, and camera"
+ );
+
+ info("Stop the camera, this should stop everything.");
+ await stopSharing("camera");
+ },
+ },
+
+ {
+ desc: "getUserMedia window/screen: reloading the page removes all gUM UI",
+ run: async function checkReloading() {
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "screen");
+ await promise;
+ await observerPromise;
+ checkDeviceSelectors(["screen"]);
+ let menulist = document.getElementById("webRTC-selectWindow-menulist");
+ menulist.getItemAtIndex(menulist.itemCount - 1).doCommand();
+
+ let indicator = promiseIndicatorWindow();
+ let observerPromise1 = expectObserverCalled(
+ "getUserMedia:response:allow"
+ );
+ let observerPromise2 = expectObserverCalled("recording-device-events");
+ await promiseMessage("ok", () => {
+ PopupNotifications.panel.firstElementChild.button.click();
+ });
+ await observerPromise1;
+ await observerPromise2;
+ Assert.deepEqual(
+ await getMediaCaptureState(),
+ { screen: "Screen" },
+ "expected screen to be shared"
+ );
+
+ await indicator;
+ await checkSharingUI({ screen: "Screen" });
+ verifyTabSharingPopup(["screen"]);
+
+ await reloadAndAssertClosedStreams();
+ },
+ },
+
+ {
+ desc: "test showControlCenter from screen icon",
+ run: async function checkShowControlCenter() {
+ if (!USING_LEGACY_INDICATOR) {
+ info(
+ "Skipping since this test doesn't apply to the new global sharing " +
+ "indicator."
+ );
+ return;
+ }
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "screen");
+ await promise;
+ await observerPromise;
+ checkDeviceSelectors(["screen"]);
+ let menulist = document.getElementById("webRTC-selectWindow-menulist");
+ menulist.getItemAtIndex(menulist.itemCount - 1).doCommand();
+
+ let observerPromise1 = expectObserverCalled(
+ "getUserMedia:response:allow"
+ );
+ let observerPromise2 = expectObserverCalled("recording-device-events");
+ let indicator = promiseIndicatorWindow();
+ await promiseMessage("ok", () => {
+ PopupNotifications.panel.firstElementChild.button.click();
+ });
+ await observerPromise1;
+ await observerPromise2;
+ Assert.deepEqual(
+ await getMediaCaptureState(),
+ { screen: "Screen" },
+ "expected screen to be shared"
+ );
+ await indicator;
+ await checkSharingUI({ screen: "Screen" });
+ verifyTabSharingPopup(["screen"]);
+
+ ok(permissionPopupHidden(), "control center should be hidden");
+ if (IS_MAC) {
+ let activeStreams = webrtcUI.getActiveStreams(false, false, true);
+ webrtcUI.showSharingDoorhanger(activeStreams[0]);
+ } else {
+ let win = Services.wm.getMostRecentWindow(
+ "Browser:WebRTCGlobalIndicator"
+ );
+ let elt = win.document.getElementById("screenShareButton");
+ EventUtils.synthesizeMouseAtCenter(elt, {}, win);
+ }
+ await TestUtils.waitForCondition(
+ () => !permissionPopupHidden(),
+ "wait for control center to open"
+ );
+ ok(!permissionPopupHidden(), "control center should be open");
+
+ gPermissionPanel._permissionPopup.hidePopup();
+
+ await closeStream();
+ },
+ },
+
+ {
+ desc: "Only persistent block is possible for screen sharing",
+ run: async function checkPersistentPermissions() {
+ // This test doesn't apply when the notification silencing
+ // feature is enabled, since the "Remember this decision"
+ // checkbox doesn't exist.
+ if (ALLOW_SILENCING_NOTIFICATIONS) {
+ return;
+ }
+
+ let browser = gBrowser.selectedBrowser;
+ let devicePerms = SitePermissions.getForPrincipal(
+ browser.contentPrincipal,
+ "screen",
+ browser
+ );
+ is(
+ devicePerms.state,
+ SitePermissions.UNKNOWN,
+ "starting without screen persistent permissions"
+ );
+
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "screen");
+ await promise;
+ await observerPromise;
+ checkDeviceSelectors(["screen"]);
+ document
+ .getElementById("webRTC-selectWindow-menulist")
+ .getItemAtIndex(2)
+ .doCommand();
+
+ // Ensure that checking the 'Remember this decision' checkbox disables
+ // 'Allow'.
+ let notification = PopupNotifications.panel.firstElementChild;
+ ok(
+ notification.hasAttribute("warninghidden"),
+ "warning message is hidden"
+ );
+ let checkbox = notification.checkbox;
+ ok(!!checkbox, "checkbox is present");
+ ok(!checkbox.checked, "checkbox is not checked");
+ checkbox.click();
+ ok(checkbox.checked, "checkbox now checked");
+ ok(notification.button.disabled, "Allow button is disabled");
+ ok(
+ !notification.hasAttribute("warninghidden"),
+ "warning message is shown"
+ );
+
+ // Click "Don't Allow" to save a persistent block permission.
+ let observerPromise1 = expectObserverCalled("getUserMedia:response:deny");
+ let observerPromise2 = expectObserverCalled("recording-window-ended");
+ await promiseMessage(permissionError, () => {
+ activateSecondaryAction(kActionDeny);
+ });
+ await observerPromise1;
+ await observerPromise2;
+ await checkNotSharing();
+
+ let permission = SitePermissions.getForPrincipal(
+ browser.contentPrincipal,
+ "screen",
+ browser
+ );
+ is(permission.state, SitePermissions.BLOCK, "screen sharing is blocked");
+ is(
+ permission.scope,
+ SitePermissions.SCOPE_PERSISTENT,
+ "screen sharing is persistently blocked"
+ );
+
+ // Request screensharing again, expect an immediate failure.
+ await Promise.all([
+ expectObserverCalled("getUserMedia:request"),
+ expectObserverCalled("getUserMedia:response:deny"),
+ expectObserverCalled("recording-window-ended"),
+ promiseMessage(permissionError),
+ promiseRequestDevice(false, true, null, "screen"),
+ ]);
+
+ // Now set the permission to allow and expect a prompt.
+ SitePermissions.setForPrincipal(
+ browser.contentPrincipal,
+ "screen",
+ SitePermissions.ALLOW
+ );
+
+ // Request devices and expect a prompt despite the saved 'Allow' permission.
+ observerPromise = expectObserverCalled("getUserMedia:request");
+ promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "screen");
+ await promise;
+ await observerPromise;
+
+ // The 'remember' checkbox shouldn't be checked anymore.
+ notification = PopupNotifications.panel.firstElementChild;
+ ok(
+ notification.hasAttribute("warninghidden"),
+ "warning message is hidden"
+ );
+ checkbox = notification.checkbox;
+ ok(!!checkbox, "checkbox is present");
+ ok(!checkbox.checked, "checkbox is not checked");
+
+ // Deny the request to cleanup...
+ observerPromise1 = expectObserverCalled("getUserMedia:response:deny");
+ observerPromise2 = expectObserverCalled("recording-window-ended");
+ await promiseMessage(permissionError, () => {
+ activateSecondaryAction(kActionDeny);
+ });
+ await observerPromise1;
+ await observerPromise2;
+ SitePermissions.removeFromPrincipal(
+ browser.contentPrincipal,
+ "screen",
+ browser
+ );
+ },
+ },
+
+ {
+ desc: "Switching between menu options maintains correct main action state while window sharing",
+ skipObserverVerification: true,
+ run: async function checkDoorhangerState() {
+ await enableObserverVerification();
+
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:newtab");
+ BrowserWindowTracker.orderedWindows[1].focus();
+
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "window");
+ await promise;
+ await observerPromise;
+
+ let menulist = document.getElementById("webRTC-selectWindow-menulist");
+ let notification = PopupNotifications.panel.firstElementChild;
+ let checkbox = notification.checkbox;
+
+ menulist.getItemAtIndex(2).doCommand();
+ checkbox.click();
+ ok(checkbox.checked, "checkbox now checked");
+
+ if (ALLOW_SILENCING_NOTIFICATIONS) {
+ // When the notification silencing feature is enabled, the checkbox
+ // controls that feature, and its state should not disable the
+ // "Allow" button.
+ ok(!notification.button.disabled, "Allow button is not disabled");
+ } else {
+ ok(notification.button.disabled, "Allow button is disabled");
+ ok(
+ !notification.hasAttribute("warninghidden"),
+ "warning message is shown"
+ );
+ }
+
+ menulist.getItemAtIndex(3).doCommand();
+ ok(checkbox.checked, "checkbox still checked");
+ if (ALLOW_SILENCING_NOTIFICATIONS) {
+ // When the notification silencing feature is enabled, the checkbox
+ // controls that feature, and its state should not disable the
+ // "Allow" button.
+ ok(!notification.button.disabled, "Allow button remains not disabled");
+ } else {
+ ok(notification.button.disabled, "Allow button remains disabled");
+ ok(
+ !notification.hasAttribute("warninghidden"),
+ "warning message is still shown"
+ );
+ }
+
+ await disableObserverVerification();
+
+ observerPromise = expectObserverCalled("recording-window-ended");
+
+ gBrowser.removeCurrentTab();
+ win.close();
+
+ await observerPromise;
+
+ await openNewTestTab();
+ },
+ },
+ {
+ desc: "Switching between tabs does not bleed state into other prompts",
+ skipObserverVerification: true,
+ run: async function checkSwitchingTabs() {
+ // Open a new window in the background to have a choice in the menulist.
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:newtab");
+ await enableObserverVerification();
+ BrowserWindowTracker.orderedWindows[1].focus();
+
+ let observerPromise = expectObserverCalled("getUserMedia:request");
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "window");
+ await promise;
+ await observerPromise;
+
+ let notification = PopupNotifications.panel.firstElementChild;
+ ok(notification.button.disabled, "Allow button is disabled");
+ await disableObserverVerification();
+
+ await openNewTestTab("get_user_media_in_xorigin_frame.html");
+ await enableObserverVerification();
+
+ observerPromise = expectObserverCalled("getUserMedia:request");
+ promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(true, true, "frame1");
+ await promise;
+ await observerPromise;
+
+ notification = PopupNotifications.panel.firstElementChild;
+ ok(!notification.button.disabled, "Allow button is not disabled");
+
+ await disableObserverVerification();
+
+ gBrowser.removeCurrentTab();
+ gBrowser.removeCurrentTab();
+ win.close();
+
+ await openNewTestTab();
+ },
+ },
+];
+
+add_task(async function test() {
+ await runTests(gTests);
+});