From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/webrtc/browser_devices_get_user_media.js | 949 +++++++++++++++++++++ 1 file changed, 949 insertions(+) create mode 100644 browser/base/content/test/webrtc/browser_devices_get_user_media.js (limited to 'browser/base/content/test/webrtc/browser_devices_get_user_media.js') diff --git a/browser/base/content/test/webrtc/browser_devices_get_user_media.js b/browser/base/content/test/webrtc/browser_devices_get_user_media.js new file mode 100644 index 0000000000..3ef88b976d --- /dev/null +++ b/browser/base/content/test/webrtc/browser_devices_get_user_media.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/. */ + +requestLongerTimeout(2); + +const permissionError = + "error: NotAllowedError: The request is not allowed " + + "by the user agent or the platform in the current context."; + +var gTests = [ + { + desc: "getUserMedia audio+video", + run: async function checkAudioVideo() { + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + let observerPromise = expectObserverCalled("getUserMedia:request"); + await promiseRequestDevice(true, true); + await promise; + await observerPromise; + + is( + PopupNotifications.getNotification("webRTC-shareDevices").anchorID, + "webRTC-shareDevices-notification-icon", + "anchored to device icon" + ); + checkDeviceSelectors(["microphone", "camera"]); + + let indicator = promiseIndicatorWindow(); + let observerPromise1 = expectObserverCalled( + "getUserMedia:response:allow" + ); + let observerPromise2 = expectObserverCalled("recording-device-events"); + + promise = promiseMessage("ok", () => { + PopupNotifications.panel.firstElementChild.button.click(); + }); + await observerPromise1; + await observerPromise2; + await promise; + + Assert.deepEqual( + await getMediaCaptureState(), + { audio: true, video: true }, + "expected camera and microphone to be shared" + ); + + await indicator; + await checkSharingUI({ audio: true, video: true }); + await closeStream(); + }, + }, + + { + desc: "getUserMedia audio only", + run: async function checkAudioOnly() { + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(true); + await promise; + await observerPromise; + + is( + PopupNotifications.getNotification("webRTC-shareDevices").anchorID, + "webRTC-shareMicrophone-notification-icon", + "anchored to mic icon" + ); + checkDeviceSelectors(["microphone"]); + + let indicator = promiseIndicatorWindow(); + let observerPromise1 = expectObserverCalled( + "getUserMedia:response:allow" + ); + let observerPromise2 = expectObserverCalled("recording-device-events"); + + promise = promiseMessage("ok", () => { + PopupNotifications.panel.firstElementChild.button.click(); + }); + await observerPromise1; + await observerPromise2; + await promise; + Assert.deepEqual( + await getMediaCaptureState(), + { audio: true }, + "expected microphone to be shared" + ); + + await indicator; + await checkSharingUI({ audio: true }); + await closeStream(); + }, + }, + + { + desc: "getUserMedia video only", + run: async function checkVideoOnly() { + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(false, true); + await promise; + await observerPromise; + + is( + PopupNotifications.getNotification("webRTC-shareDevices").anchorID, + "webRTC-shareDevices-notification-icon", + "anchored to device icon" + ); + checkDeviceSelectors(["camera"]); + + 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(), + { video: true }, + "expected camera to be shared" + ); + + await indicator; + await checkSharingUI({ video: true }); + await closeStream(); + }, + }, + + { + desc: 'getUserMedia audio+video, user clicks "Don\'t Share"', + run: async function checkDontShare() { + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(true, true); + await promise; + await observerPromise; + checkDeviceSelectors(["microphone", "camera"]); + + let observerPromise1 = expectObserverCalled("getUserMedia:response:deny"); + let observerPromise2 = expectObserverCalled("recording-window-ended"); + await promiseMessage(permissionError, () => { + activateSecondaryAction(kActionDeny); + }); + await observerPromise1; + await observerPromise2; + + await checkNotSharing(); + + // Verify that we set 'Temporarily blocked' permissions. + let browser = gBrowser.selectedBrowser; + let blockedPerms = document.getElementById( + "blocked-permissions-container" + ); + + let { state, scope } = SitePermissions.getForPrincipal( + null, + "camera", + browser + ); + Assert.equal(state, SitePermissions.BLOCK); + Assert.equal(scope, SitePermissions.SCOPE_TEMPORARY); + ok( + blockedPerms.querySelector( + ".blocked-permission-icon.camera-icon[showing=true]" + ), + "the blocked camera icon is shown" + ); + + ({ state, scope } = SitePermissions.getForPrincipal( + null, + "microphone", + browser + )); + Assert.equal(state, SitePermissions.BLOCK); + Assert.equal(scope, SitePermissions.SCOPE_TEMPORARY); + ok( + blockedPerms.querySelector( + ".blocked-permission-icon.microphone-icon[showing=true]" + ), + "the blocked microphone icon is shown" + ); + + info("requesting devices again to check temporarily blocked permissions"); + promise = promiseMessage(permissionError); + observerPromise1 = expectObserverCalled("getUserMedia:request"); + observerPromise2 = expectObserverCalled("getUserMedia:response:deny"); + let observerPromise3 = expectObserverCalled("recording-window-ended"); + await promiseRequestDevice(true, true); + await promise; + await observerPromise1; + await observerPromise2; + await observerPromise3; + await checkNotSharing(); + + SitePermissions.removeFromPrincipal( + browser.contentPrincipal, + "camera", + browser + ); + SitePermissions.removeFromPrincipal( + browser.contentPrincipal, + "microphone", + browser + ); + }, + }, + + { + desc: "getUserMedia audio+video: stop sharing", + run: async function checkStopSharing() { + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(true, true); + await promise; + await observerPromise; + checkDeviceSelectors(["microphone", "camera"]); + + 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, video: true }, + "expected camera and microphone to be shared" + ); + + await indicator; + await checkSharingUI({ video: true, audio: true }); + + await stopSharing(); + + // the stream is already closed, but this will do some cleanup anyway + await closeStream(true); + + // After stop sharing, gUM(audio+camera) causes a prompt. + observerPromise = expectObserverCalled("getUserMedia:request"); + promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(true, true); + await promise; + await observerPromise; + checkDeviceSelectors(["microphone", "camera"]); + + observerPromise1 = expectObserverCalled("getUserMedia:response:deny"); + 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 + ); + SitePermissions.removeFromPrincipal( + null, + "microphone", + gBrowser.selectedBrowser + ); + }, + }, + + { + desc: "getUserMedia audio+video: reloading the page removes all gUM UI", + run: async function checkReloading() { + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(true, true); + await promise; + await observerPromise; + checkDeviceSelectors(["microphone", "camera"]); + + 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, video: true }, + "expected camera and microphone to be shared" + ); + + await indicator; + await checkSharingUI({ video: true, audio: true }); + + await reloadAndAssertClosedStreams(); + + observerPromise = expectObserverCalled("getUserMedia:request"); + // After the reload, gUM(audio+camera) causes a prompt. + promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(true, true); + await promise; + await observerPromise; + checkDeviceSelectors(["microphone", "camera"]); + + observerPromise1 = expectObserverCalled("getUserMedia:response:deny"); + 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 + ); + SitePermissions.removeFromPrincipal( + null, + "microphone", + gBrowser.selectedBrowser + ); + }, + }, + + { + desc: "getUserMedia prompt: Always/Never Share", + run: async function checkRememberCheckbox() { + let elt = id => document.getElementById(id); + + async function checkPerm( + aRequestAudio, + aRequestVideo, + aExpectedAudioPerm, + aExpectedVideoPerm, + aNever + ) { + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(aRequestAudio, aRequestVideo); + await promise; + await observerPromise; + + is( + elt("webRTC-selectMicrophone").hidden, + !aRequestAudio, + "microphone selector expected to be " + + (aRequestAudio ? "visible" : "hidden") + ); + + is( + elt("webRTC-selectCamera").hidden, + !aRequestVideo, + "camera selector expected to be " + + (aRequestVideo ? "visible" : "hidden") + ); + + let expected = {}; + let observerPromises = []; + let expectedMessage = aNever ? permissionError : "ok"; + if (expectedMessage == "ok") { + observerPromises.push( + expectObserverCalled("getUserMedia:response:allow") + ); + observerPromises.push( + expectObserverCalled("recording-device-events") + ); + if (aRequestVideo) { + expected.video = true; + } + if (aRequestAudio) { + expected.audio = true; + } + } else { + observerPromises.push( + expectObserverCalled("getUserMedia:response:deny") + ); + observerPromises.push(expectObserverCalled("recording-window-ended")); + } + await promiseMessage(expectedMessage, () => { + activateSecondaryAction(aNever ? kActionNever : kActionAlways); + }); + await Promise.all(observerPromises); + Assert.deepEqual( + await getMediaCaptureState(), + expected, + "expected " + Object.keys(expected).join(" and ") + " to be shared" + ); + + function checkDevicePermissions(aDevice, aExpected) { + let uri = gBrowser.selectedBrowser.documentURI; + let devicePerms = PermissionTestUtils.testExactPermission( + uri, + aDevice + ); + if (aExpected === undefined) { + is( + devicePerms, + Services.perms.UNKNOWN_ACTION, + "no " + aDevice + " persistent permissions" + ); + } else { + is( + devicePerms, + aExpected + ? Services.perms.ALLOW_ACTION + : Services.perms.DENY_ACTION, + aDevice + " persistently " + (aExpected ? "allowed" : "denied") + ); + } + PermissionTestUtils.remove(uri, aDevice); + } + checkDevicePermissions("microphone", aExpectedAudioPerm); + checkDevicePermissions("camera", aExpectedVideoPerm); + + if (expectedMessage == "ok") { + await closeStream(); + } + } + + // 3 cases where the user accepts the device prompt. + info("audio+video, user grants, expect both Services.perms set to allow"); + await checkPerm(true, true, true, true); + info( + "audio only, user grants, check audio perm set to allow, video perm not set" + ); + await checkPerm(true, false, true, undefined); + info( + "video only, user grants, check video perm set to allow, audio perm not set" + ); + await checkPerm(false, true, undefined, true); + + // 3 cases where the user rejects the device request by using 'Never Share'. + info( + "audio only, user denies, expect audio perm set to deny, video not set" + ); + await checkPerm(true, false, false, undefined, true); + info( + "video only, user denies, expect video perm set to deny, audio perm not set" + ); + await checkPerm(false, true, undefined, false, true); + info("audio+video, user denies, expect both Services.perms set to deny"); + await checkPerm(true, true, false, false, true); + }, + }, + + { + desc: "getUserMedia without prompt: use persistent permissions", + run: async function checkUsePersistentPermissions() { + async function usePerm( + aAllowAudio, + aAllowVideo, + aRequestAudio, + aRequestVideo, + aExpectStream + ) { + let uri = gBrowser.selectedBrowser.documentURI; + + if (aAllowAudio !== undefined) { + PermissionTestUtils.add( + uri, + "microphone", + aAllowAudio + ? Services.perms.ALLOW_ACTION + : Services.perms.DENY_ACTION + ); + } + if (aAllowVideo !== undefined) { + PermissionTestUtils.add( + uri, + "camera", + aAllowVideo + ? Services.perms.ALLOW_ACTION + : Services.perms.DENY_ACTION + ); + } + + if (aExpectStream === undefined) { + // Check that we get a prompt. + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(aRequestAudio, aRequestVideo); + await promise; + await observerPromise; + + // Deny the request to cleanup... + let observerPromise1 = expectObserverCalled( + "getUserMedia:response:deny" + ); + let observerPromise2 = expectObserverCalled("recording-window-ended"); + await promiseMessage(permissionError, () => { + activateSecondaryAction(kActionDeny); + }); + await observerPromise1; + await observerPromise2; + + let browser = gBrowser.selectedBrowser; + SitePermissions.removeFromPrincipal(null, "camera", browser); + SitePermissions.removeFromPrincipal(null, "microphone", browser); + } else { + let expectedMessage = aExpectStream ? "ok" : permissionError; + + let observerPromises = [expectObserverCalled("getUserMedia:request")]; + if (expectedMessage == "ok") { + observerPromises.push( + expectObserverCalled("getUserMedia:response:allow"), + expectObserverCalled("recording-device-events") + ); + } else { + observerPromises.push( + expectObserverCalled("getUserMedia:response:deny"), + expectObserverCalled("recording-window-ended") + ); + } + + let promise = promiseMessage(expectedMessage); + await promiseRequestDevice(aRequestAudio, aRequestVideo); + await promise; + await Promise.all(observerPromises); + + if (expectedMessage == "ok") { + await promiseNoPopupNotification("webRTC-shareDevices"); + + // Check what's actually shared. + let expected = {}; + if (aAllowVideo && aRequestVideo) { + expected.video = true; + } + if (aAllowAudio && aRequestAudio) { + expected.audio = true; + } + Assert.deepEqual( + await getMediaCaptureState(), + expected, + "expected " + + Object.keys(expected).join(" and ") + + " to be shared" + ); + + await closeStream(); + } + } + + PermissionTestUtils.remove(uri, "camera"); + PermissionTestUtils.remove(uri, "microphone"); + } + + // Set both permissions identically + info("allow audio+video, request audio+video, expect ok (audio+video)"); + await usePerm(true, true, true, true, true); + info("deny audio+video, request audio+video, expect denied"); + await usePerm(false, false, true, true, false); + + // Allow audio, deny video. + info("allow audio, deny video, request audio+video, expect denied"); + await usePerm(true, false, true, true, false); + info("allow audio, deny video, request audio, expect ok (audio)"); + await usePerm(true, false, true, false, true); + info("allow audio, deny video, request video, expect denied"); + await usePerm(true, false, false, true, false); + + // Deny audio, allow video. + info("deny audio, allow video, request audio+video, expect denied"); + await usePerm(false, true, true, true, false); + info("deny audio, allow video, request audio, expect denied"); + await usePerm(false, true, true, false, false); + info("deny audio, allow video, request video, expect ok (video)"); + await usePerm(false, true, false, true, true); + + // Allow audio, video not set. + info("allow audio, request audio+video, expect prompt"); + await usePerm(true, undefined, true, true, undefined); + info("allow audio, request audio, expect ok (audio)"); + await usePerm(true, undefined, true, false, true); + info("allow audio, request video, expect prompt"); + await usePerm(true, undefined, false, true, undefined); + + // Deny audio, video not set. + info("deny audio, request audio+video, expect denied"); + await usePerm(false, undefined, true, true, false); + info("deny audio, request audio, expect denied"); + await usePerm(false, undefined, true, false, false); + info("deny audio, request video, expect prompt"); + await usePerm(false, undefined, false, true, undefined); + + // Allow video, audio not set. + info("allow video, request audio+video, expect prompt"); + await usePerm(undefined, true, true, true, undefined); + info("allow video, request audio, expect prompt"); + await usePerm(undefined, true, true, false, undefined); + info("allow video, request video, expect ok (video)"); + await usePerm(undefined, true, false, true, true); + + // Deny video, audio not set. + info("deny video, request audio+video, expect denied"); + await usePerm(undefined, false, true, true, false); + info("deny video, request audio, expect prompt"); + await usePerm(undefined, false, true, false, undefined); + info("deny video, request video, expect denied"); + await usePerm(undefined, false, false, true, false); + }, + }, + + { + desc: "Stop Sharing removes permissions", + run: async function checkStopSharingRemovesPermissions() { + async function stopAndCheckPerm( + aRequestAudio, + aRequestVideo, + aStopAudio = aRequestAudio, + aStopVideo = aRequestVideo + ) { + let uri = gBrowser.selectedBrowser.documentURI; + + // Initially set both permissions to 'allow'. + PermissionTestUtils.add(uri, "microphone", Services.perms.ALLOW_ACTION); + PermissionTestUtils.add(uri, "camera", Services.perms.ALLOW_ACTION); + // Also set device-specific temporary allows. + SitePermissions.setForPrincipal( + gBrowser.contentPrincipal, + "microphone^myDevice", + SitePermissions.ALLOW, + SitePermissions.SCOPE_TEMPORARY, + gBrowser.selectedBrowser, + 10000000 + ); + SitePermissions.setForPrincipal( + gBrowser.contentPrincipal, + "camera^myDevice2", + SitePermissions.ALLOW, + SitePermissions.SCOPE_TEMPORARY, + gBrowser.selectedBrowser, + 10000000 + ); + + if (aRequestAudio || aRequestVideo) { + let indicator = promiseIndicatorWindow(); + let observerPromise1 = expectObserverCalled("getUserMedia:request"); + let observerPromise2 = expectObserverCalled( + "getUserMedia:response:allow" + ); + let observerPromise3 = expectObserverCalled( + "recording-device-events" + ); + // Start sharing what's been requested. + let promise = promiseMessage("ok"); + await promiseRequestDevice(aRequestAudio, aRequestVideo); + await promise; + await observerPromise1; + await observerPromise2; + await observerPromise3; + + await indicator; + await checkSharingUI( + { video: aRequestVideo, audio: aRequestAudio }, + undefined, + undefined, + { + video: { scope: SitePermissions.SCOPE_PERSISTENT }, + audio: { scope: SitePermissions.SCOPE_PERSISTENT }, + } + ); + await stopSharing(aStopVideo ? "camera" : "microphone"); + } else { + await revokePermission(aStopVideo ? "camera" : "microphone"); + } + + // Check that permissions have been removed as expected. + let audioPerm = SitePermissions.getForPrincipal( + gBrowser.contentPrincipal, + "microphone", + gBrowser.selectedBrowser + ); + let audioPermDevice = SitePermissions.getForPrincipal( + gBrowser.contentPrincipal, + "microphone^myDevice", + gBrowser.selectedBrowser + ); + + if ( + aRequestAudio || + aRequestVideo || + aStopAudio || + (aStopVideo && aRequestAudio) + ) { + Assert.deepEqual( + audioPerm, + { + state: SitePermissions.UNKNOWN, + scope: SitePermissions.SCOPE_PERSISTENT, + }, + "microphone permissions removed" + ); + Assert.deepEqual( + audioPermDevice, + { + state: SitePermissions.UNKNOWN, + scope: SitePermissions.SCOPE_PERSISTENT, + }, + "microphone device-specific permissions removed" + ); + } else { + Assert.deepEqual( + audioPerm, + { + state: SitePermissions.ALLOW, + scope: SitePermissions.SCOPE_PERSISTENT, + }, + "microphone permissions untouched" + ); + Assert.deepEqual( + audioPermDevice, + { + state: SitePermissions.ALLOW, + scope: SitePermissions.SCOPE_TEMPORARY, + }, + "microphone device-specific permissions untouched" + ); + } + + let videoPerm = SitePermissions.getForPrincipal( + gBrowser.contentPrincipal, + "camera", + gBrowser.selectedBrowser + ); + let videoPermDevice = SitePermissions.getForPrincipal( + gBrowser.contentPrincipal, + "camera^myDevice2", + gBrowser.selectedBrowser + ); + if ( + aRequestAudio || + aRequestVideo || + aStopVideo || + (aStopAudio && aRequestVideo) + ) { + Assert.deepEqual( + videoPerm, + { + state: SitePermissions.UNKNOWN, + scope: SitePermissions.SCOPE_PERSISTENT, + }, + "camera permissions removed" + ); + Assert.deepEqual( + videoPermDevice, + { + state: SitePermissions.UNKNOWN, + scope: SitePermissions.SCOPE_PERSISTENT, + }, + "camera device-specific permissions removed" + ); + } else { + Assert.deepEqual( + videoPerm, + { + state: SitePermissions.ALLOW, + scope: SitePermissions.SCOPE_PERSISTENT, + }, + "camera permissions untouched" + ); + Assert.deepEqual( + videoPermDevice, + { + state: SitePermissions.ALLOW, + scope: SitePermissions.SCOPE_TEMPORARY, + }, + "camera device-specific permissions untouched" + ); + } + await checkNotSharing(); + + // Cleanup. + await closeStream(true); + + SitePermissions.removeFromPrincipal( + gBrowser.contentPrincipal, + "camera", + gBrowser.selectedBrowser + ); + SitePermissions.removeFromPrincipal( + gBrowser.contentPrincipal, + "microphone", + gBrowser.selectedBrowser + ); + } + + info("request audio+video, stop sharing video resets both"); + await stopAndCheckPerm(true, true); + info("request audio only, stop sharing audio resets both"); + await stopAndCheckPerm(true, false); + info("request video only, stop sharing video resets both"); + await stopAndCheckPerm(false, true); + info("request audio only, stop sharing video resets both"); + await stopAndCheckPerm(true, false, false, true); + info("request video only, stop sharing audio resets both"); + await stopAndCheckPerm(false, true, true, false); + info("request neither, stop audio affects audio only"); + await stopAndCheckPerm(false, false, true, false); + info("request neither, stop video affects video only"); + await stopAndCheckPerm(false, false, false, true); + }, + }, + + { + desc: "test showPermissionPanel", + run: async function checkShowPermissionPanel() { + if (!USING_LEGACY_INDICATOR) { + // The indicator only links to the permission panel for the + // legacy indicator. + return; + } + + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(false, true); + await promise; + await observerPromise; + checkDeviceSelectors(["camera"]); + + 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(), + { video: true }, + "expected camera to be shared" + ); + + await indicator; + await checkSharingUI({ video: true }); + + ok(permissionPopupHidden(), "permission panel should be hidden"); + if (IS_MAC) { + let activeStreams = webrtcUI.getActiveStreams(true, false, false); + webrtcUI.showSharingDoorhanger(activeStreams[0]); + } else { + let win = Services.wm.getMostRecentWindow( + "Browser:WebRTCGlobalIndicator" + ); + + let elt = win.document.getElementById("audioVideoButton"); + EventUtils.synthesizeMouseAtCenter(elt, {}, win); + } + + await TestUtils.waitForCondition( + () => !permissionPopupHidden(), + "wait for permission panel to open" + ); + ok(!permissionPopupHidden(), "permission panel should be open"); + + gPermissionPanel._permissionPopup.hidePopup(); + + await closeStream(); + }, + }, + + { + desc: "'Always Allow' disabled on http pages", + run: async function checkNoAlwaysOnHttp() { + // Load an http page instead of the https version. + await SpecialPowers.pushPrefEnv({ + set: [ + ["media.devices.insecure.enabled", true], + ["media.getusermedia.insecure.enabled", true], + // explicitly testing an http page, setting + // https-first to false. + ["dom.security.https_first", false], + ], + }); + + // Disable while loading a new page + await disableObserverVerification(); + + let browser = gBrowser.selectedBrowser; + BrowserTestUtils.loadURIString( + browser, + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + browser.documentURI.spec.replace("https://", "http://") + ); + await BrowserTestUtils.browserLoaded(browser); + + await enableObserverVerification(); + + // Initially set both permissions to 'allow'. + let uri = browser.documentURI; + PermissionTestUtils.add(uri, "microphone", Services.perms.ALLOW_ACTION); + PermissionTestUtils.add(uri, "camera", Services.perms.ALLOW_ACTION); + + // Request devices and expect a prompt despite the saved 'Allow' permission, + // because the connection isn't secure. + let observerPromise = expectObserverCalled("getUserMedia:request"); + let promise = promisePopupNotificationShown("webRTC-shareDevices"); + await promiseRequestDevice(true, true); + await promise; + await observerPromise; + + // Ensure that checking the 'Remember this decision' checkbox disables + // 'Allow'. + let notification = PopupNotifications.panel.firstElementChild; + 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" + ); + + // Cleanup. + await closeStream(true); + PermissionTestUtils.remove(uri, "camera"); + PermissionTestUtils.remove(uri, "microphone"); + }, + }, +]; + +add_task(async function test() { + await runTests(gTests); +}); -- cgit v1.2.3