Bug 1333468 - Part 2 - Add tests for paused/disabled sharing state indicators. r=florian
MozReview-Commit-ID: G1CTAefOPNB
--- a/browser/base/content/test/webrtc/browser.ini
+++ b/browser/base/content/test/webrtc/browser.ini
@@ -7,16 +7,17 @@ support-files =
[browser_devices_get_user_media.js]
skip-if = (os == "linux" && debug) # linux: bug 976544
[browser_devices_get_user_media_anim.js]
[browser_devices_get_user_media_in_frame.js]
skip-if = debug # bug 1369731
[browser_devices_get_user_media_multi_process.js]
skip-if = debug && (os == "win" || os == "mac") # bug 1393761
+[browser_devices_get_user_media_paused.js]
[browser_devices_get_user_media_screen.js]
skip-if = (os == "win" && ccov) # bug 1421724
[browser_devices_get_user_media_tear_off_tab.js]
[browser_devices_get_user_media_unprompted_access.js]
[browser_devices_get_user_media_unprompted_access_in_frame.js]
[browser_devices_get_user_media_unprompted_access_tear_off_tab.js]
skip-if = (os == "win" && bits == 64) # win8: bug 1334752
[browser_devices_get_user_media_unprompted_access_queue_request.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_paused.js
@@ -0,0 +1,155 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function setTrackEnabled(audio, video) {
+ return ContentTask.spawn(gBrowser.selectedBrowser, {audio, video}, function(args) {
+ let stream = content.wrappedJSObject.gStreams[0];
+ if (args.audio != null) {
+ stream.getAudioTracks()[0].enabled = args.audio;
+ }
+ if (args.video != null) {
+ stream.getVideoTracks()[0].enabled = args.video;
+ }
+ });
+}
+
+var gTests = [
+{
+ desc: "getUserMedia audio+video: disabling the stream shows the paused indicator",
+ run: async function checkPaused() {
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(true, true);
+ await promise;
+ await expectObserverCalled("getUserMedia:request");
+ checkDeviceSelectors(true, true);
+
+ let indicator = promiseIndicatorWindow();
+ await promiseMessage("ok", () => {
+ PopupNotifications.panel.firstChild.button.click();
+ });
+ await expectObserverCalled("getUserMedia:response:allow");
+ await expectObserverCalled("recording-device-events");
+ Assert.deepEqual((await getMediaCaptureState()), {audio: true, video: true},
+ "expected camera and microphone to be shared");
+ await indicator;
+ await checkSharingUI({
+ video: STATE_CAPTURE_ENABLED,
+ audio: STATE_CAPTURE_ENABLED,
+ });
+
+ // Disable both audio and video.
+ await setTrackEnabled(false, false);
+
+ // It sometimes takes a bit longer before the change propagates to the UI,
+ // wait for it to avoid intermittents.
+ await BrowserTestUtils.waitForCondition(
+ () => window.gIdentityHandler._sharingState.camera == STATE_CAPTURE_DISABLED,
+ "video should be disabled"
+ );
+
+ await expectObserverCalled("recording-device-events", 2);
+
+ // The identity UI should show both as disabled.
+ await checkSharingUI({
+ video: STATE_CAPTURE_DISABLED,
+ audio: STATE_CAPTURE_DISABLED,
+ });
+
+ // Enable only audio again.
+ await setTrackEnabled(true);
+
+ await BrowserTestUtils.waitForCondition(
+ () => window.gIdentityHandler._sharingState.microphone == STATE_CAPTURE_ENABLED,
+ "audio should be enabled"
+ );
+
+ await expectObserverCalled("recording-device-events");
+
+ // The identity UI should show only video as disabled.
+ await checkSharingUI({
+ video: STATE_CAPTURE_DISABLED,
+ audio: STATE_CAPTURE_ENABLED,
+ });
+
+ // Enable video again.
+ await setTrackEnabled(null, true);
+
+ await BrowserTestUtils.waitForCondition(
+ () => window.gIdentityHandler._sharingState.camera == STATE_CAPTURE_ENABLED,
+ "video should be enabled"
+ );
+
+ await expectObserverCalled("recording-device-events");
+
+ // Both streams should show as running.
+ await checkSharingUI({
+ video: STATE_CAPTURE_ENABLED,
+ audio: STATE_CAPTURE_ENABLED,
+ });
+ await closeStream();
+ }
+},
+
+{
+ desc: "getUserMedia screen: disabling the stream shows the paused indicator",
+ run: async function checkScreenPaused() {
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(false, true, null, "screen");
+ await promise;
+ await expectObserverCalled("getUserMedia:request");
+
+ is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
+ "webRTC-shareScreen-notification-icon", "anchored to device icon");
+ checkDeviceSelectors(false, false, true);
+ let notification = PopupNotifications.panel.firstChild;
+ let iconclass = notification.getAttribute("iconclass");
+ ok(iconclass.includes("screen-icon"), "panel using screen icon");
+
+ let menulist =
+ document.getElementById("webRTC-selectWindow-menulist");
+ menulist.getItemAtIndex(2).doCommand();
+
+ let indicator = promiseIndicatorWindow();
+ await promiseMessage("ok", () => {
+ PopupNotifications.panel.firstChild.button.click();
+ });
+ await expectObserverCalled("getUserMedia:response:allow");
+ await expectObserverCalled("recording-device-events");
+ Assert.deepEqual((await getMediaCaptureState()), {screen: "Screen"},
+ "expected screen to be shared");
+
+ await indicator;
+ await checkSharingUI({screen: "Screen"});
+
+ await setTrackEnabled(null, false);
+
+ // It sometimes takes a bit longer before the change propagates to the UI,
+ // wait for it to avoid intermittents.
+ await BrowserTestUtils.waitForCondition(
+ () => window.gIdentityHandler._sharingState.screen == "ScreenPaused",
+ "screen should be disabled"
+ );
+ await expectObserverCalled("recording-device-events");
+ await checkSharingUI({screen: "ScreenPaused"}, window, {screen: "Screen"});
+
+ await setTrackEnabled(null, true);
+
+ await BrowserTestUtils.waitForCondition(
+ () => window.gIdentityHandler._sharingState.screen == "Screen",
+ "screen should be enabled"
+ );
+ await expectObserverCalled("recording-device-events");
+ await checkSharingUI({screen: "Screen"});
+ }
+},
+];
+
+add_task(async function test() {
+ await SpecialPowers.pushPrefEnv({"set": [
+ ["media.getusermedia.camera.off_while_disabled.delay_ms", 0],
+ ["media.getusermedia.microphone.off_while_disabled.delay_ms", 0],
+ ]});
+
+ SimpleTest.requestCompleteLog();
+ await runTests(gTests);
+});
--- a/browser/base/content/test/webrtc/head.js
+++ b/browser/base/content/test/webrtc/head.js
@@ -1,15 +1,17 @@
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource:///modules/SitePermissions.jsm");
-
const PREF_PERMISSION_FAKE = "media.navigator.permission.fake";
const CONTENT_SCRIPT_HELPER = getRootDirectory(gTestPath) + "get_user_media_content_script.js";
+const STATE_CAPTURE_ENABLED = Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED;
+const STATE_CAPTURE_DISABLED = Ci.nsIMediaManagerService.STATE_CAPTURE_DISABLED;
+
function waitForCondition(condition, nextTest, errorMsg, retryTimes) {
retryTimes = typeof retryTimes !== "undefined" ? retryTimes : 30;
var tries = 0;
var interval = setInterval(function() {
if (tries >= retryTimes) {
ok(false, errorMsg);
moveOn();
}
@@ -454,27 +456,38 @@ function checkDeviceSelectors(aAudio, aV
ok(!screenSelector.hidden, "screen selector visible");
else
ok(screenSelector.hidden, "screen selector hidden");
}
// aExpected is for the current tab,
// aExpectedGlobal is for all tabs.
async function checkSharingUI(aExpected, aWin = window, aExpectedGlobal = null) {
+ function isPaused(streamState) {
+ if (typeof streamState == "string") {
+ return streamState.includes("Paused");
+ }
+ return streamState == STATE_CAPTURE_DISABLED;
+ }
+
let doc = aWin.document;
// First check the icon above the control center (i) icon.
let identityBox = doc.getElementById("identity-box");
ok(identityBox.hasAttribute("sharing"), "sharing attribute is set");
let sharing = identityBox.getAttribute("sharing");
if (aExpected.screen)
- is(sharing, "screen", "showing screen icon on the control center icon");
+ is(sharing, "screen", "showing screen icon in the identity block");
else if (aExpected.video)
- is(sharing, "camera", "showing camera icon on the control center icon");
+ is(sharing, "camera", "showing camera icon in the identity block");
else if (aExpected.audio)
- is(sharing, "microphone", "showing mic icon on the control center icon");
+ is(sharing, "microphone", "showing mic icon in the identity block");
+
+ let allStreamsPaused = Object.values(aExpected).every(isPaused);
+ is(identityBox.hasAttribute("paused"), allStreamsPaused,
+ "sharing icon(s) should be in paused state when paused");
// Then check the sharing indicators inside the control center panel.
identityBox.click();
let permissions = doc.getElementById("identity-popup-permission-list");
for (let id of ["microphone", "camera", "screen"]) {
let convertId = idToConvert => {
if (idToConvert == "camera")
return "video";
@@ -484,17 +497,18 @@ async function checkSharingUI(aExpected,
};
let expected = aExpected[convertId(id)];
is(!!aWin.gIdentityHandler._sharingState[id], !!expected,
"sharing state for " + id + " as expected");
let icon = permissions.querySelectorAll(
".identity-popup-permission-icon." + id + "-icon");
if (expected) {
is(icon.length, 1, "should show " + id + " icon in control center panel");
- ok(icon[0].classList.contains("in-use"), "icon should have the in-use class");
+ is(icon[0].classList.contains("in-use"), expected && !isPaused(expected),
+ "icon should have the in-use class, unless paused");
} else if (!icon.length) {
ok(true, "should not show " + id + " icon in the control center panel");
} else {
// This will happen if there are persistent permissions set.
ok(!icon[0].classList.contains("in-use"),
"if shown, the " + id + " icon should not have the in-use class");
is(icon.length, 1, "should not show more than 1 " + id + " icon");
}
--- a/browser/components/extensions/test/browser/browser_ext_tabs_sharingState.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_sharingState.js
@@ -4,17 +4,22 @@ add_task(async function test_tabs_mediaI
await SpecialPowers.pushPrefEnv({
set: [["extensions.webextensions.tabhide.enabled", true]],
});
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
// setBrowserSharing is called when a request for media icons occurs. We're
// just testing that extension tabs get the info and are updated when it is
// called.
- gBrowser.setBrowserSharing(tab.linkedBrowser, {screen: "Window", microphone: true, camera: true});
+ gBrowser.setBrowserSharing(tab.linkedBrowser, {
+ sharing: "screen",
+ screen: "Window",
+ microphone: Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED,
+ camera: Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED,
+ });
async function background() {
let tabs = await browser.tabs.query({microphone: true});
let testTab = tabs[0];
let state = testTab.sharingState;
browser.test.assertTrue(state.camera, "sharing camera was turned on");
browser.test.assertTrue(state.microphone, "sharing mic was turned on");