Bug 1224453 - Add a test for WebRTC sharing indicators in frames.
MozReview-Commit-ID: H1tyfryNrm
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_in_frame.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_in_frame.js
@@ -203,15 +203,67 @@ var gTests = [
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();
}
-}
+},
+
+{
+ desc: "getUserMedia audio+video: streaming from a frame with a different origin is shown in the control center",
+ run: async function checkAudioVideo() {
+ let promise = promisePopupNotificationShown("webRTC-shareDevices");
+ await promiseRequestDevice(true, true, "frame3");
+ await promise;
+ await expectObserverCalled("getUserMedia:request");
+
+ is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
+ "webRTC-shareDevices-notification-icon", "anchored to device icon");
+ checkDeviceSelectors(true, true);
+ is(PopupNotifications.panel.firstChild.getAttribute("popupid"),
+ "webRTC-shareDevices", "panel using devices icon");
+
+ 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;
+ // First check the icon above the control center (i) icon.
+ let identityBox = document.getElementById("identity-box");
+ ok(identityBox.hasAttribute("sharing"), "sharing attribute is set");
+ let sharing = identityBox.getAttribute("sharing");
+ is(sharing, "camera", "showing camera icon on the control center icon");
+
+ // Then check the sharing indicators inside the control center panel.
+ let popupshown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
+ identityBox.click();
+ await popupshown;
+
+ let nestedPermissionsList = document.getElementById("identity-popup-nested-permission-list");
+ is(nestedPermissionsList.children.length, 1,
+ "Should have one subsection for nested frames with permissions.");
+
+ for (let id of ["microphone", "camera"]) {
+ let icon = nestedPermissionsList.querySelectorAll(
+ ".identity-popup-permission-icon." + id + "-icon");
+ 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");
+ }
+
+ gIdentityHandler._identityPopup.hidden = true;
+
+ await closeStream(false, "frame3");
+ }
+},
];
add_task(async function test() {
await runTests(gTests, { relativeURI: "get_user_media_in_frame.html" });
});
--- a/browser/base/content/test/webrtc/get_user_media_in_frame.html
+++ b/browser/base/content/test/webrtc/get_user_media_in_frame.html
@@ -20,17 +20,33 @@ try {
function message(m) {
// eslint-disable-next-line no-unsanitized/property
document.getElementById("message").innerHTML = m;
window.parent.postMessage(m, "*");
}
var gStreams = [];
-function requestDevice(aAudio, aVideo, aShare) {
+function requestDevice(aAudio, aVideo, aShare, aBadDevice = false, aFrameId) {
+ if (aFrameId) {
+ let frame = document.getElementById(aFrameId);
+ // Avoid cross-origin restrictions for our frame.
+ let win = SpecialPowers.wrap(frame).wrappedJSObject.contentWindow;
+ // FIXME: For some reason this intermittently fails with
+ // "global.requestDevice is not a function" without this hack.
+ (function checkRequestDevice() {
+ if (win.requestDevice) {
+ win.requestDevice(aAudio, aVideo, aShare, aBadDevice);
+ } else {
+ setTimeout(checkRequestDevice, 10);
+ }
+ })();
+ return;
+ }
+
var opts = {video: aVideo, audio: aAudio};
if (aShare) {
opts.video = {
mozMediaSource: aShare,
mediaSource: aShare
};
} else if (useFakeStreams) {
opts.fake = true;
@@ -39,23 +55,30 @@ function requestDevice(aAudio, aVideo, a
window.navigator.mediaDevices.getUserMedia(opts)
.then(stream => {
gStreams.push(stream);
message("ok");
}, err => message("error: " + err));
}
message("pending");
-function closeStream() {
+function closeStream(aFrameId) {
+ if (aFrameId) {
+ let frame = SpecialPowers.wrap(document.getElementById(aFrameId));
+ frame.wrappedJSObject.contentWindow.closeStream();
+ return;
+ }
+
for (let stream of gStreams) {
if (stream) {
stream.getTracks().forEach(t => t.stop());
stream = null;
}
}
gStreams = [];
message("closed");
}
</script>
<iframe id="frame1" src="get_user_media.html"></iframe>
<iframe id="frame2" src="get_user_media.html"></iframe>
+<iframe id="frame3" src="https://example.org/browser/browser/base/content/test/webrtc/get_user_media.html"></iframe>
</body>
</html>
--- a/browser/base/content/test/webrtc/head.js
+++ b/browser/base/content/test/webrtc/head.js
@@ -388,37 +388,32 @@ async function stopSharing(aType = "came
function promiseRequestDevice(aRequestAudio, aRequestVideo, aFrameId, aType,
aBrowser = gBrowser.selectedBrowser,
aBadDevice = false) {
info("requesting devices");
return ContentTask.spawn(aBrowser,
{aRequestAudio, aRequestVideo, aFrameId, aType, aBadDevice},
async function(args) {
let global = content.wrappedJSObject;
- if (args.aFrameId)
- global = global.document.getElementById(args.aFrameId).contentWindow;
- global.requestDevice(args.aRequestAudio, args.aRequestVideo, args.aType, args.aBadDevice);
+ global.requestDevice(args.aRequestAudio, args.aRequestVideo, args.aType, args.aBadDevice, args.aFrameId);
});
}
async function closeStream(aAlreadyClosed, aFrameId) {
await expectNoObserverCalled();
let promises;
if (!aAlreadyClosed) {
promises = [promiseObserverCalled("recording-device-events"),
promiseObserverCalled("recording-window-ended")];
}
info("closing the stream");
await ContentTask.spawn(gBrowser.selectedBrowser, aFrameId, async function(contentFrameId) {
- let global = content.wrappedJSObject;
- if (contentFrameId)
- global = global.document.getElementById(contentFrameId).contentWindow;
- global.closeStream();
+ content.wrappedJSObject.closeStream(contentFrameId);
});
if (promises)
await Promise.all(promises);
await assertWebRTCIndicatorStatus(null);
}
@@ -467,17 +462,20 @@ async function checkSharingUI(aExpected,
if (aExpected.screen)
is(sharing, "screen", "showing screen icon on the control center icon");
else if (aExpected.video)
is(sharing, "camera", "showing camera icon on the control center icon");
else if (aExpected.audio)
is(sharing, "microphone", "showing mic icon on the control center icon");
// Then check the sharing indicators inside the control center panel.
+ let popupshown = BrowserTestUtils.waitForEvent(aWin.gIdentityHandler._identityPopup, "popupshown");
identityBox.click();
+ await popupshown;
+
let permissions = doc.getElementById("identity-popup-permission-list");
for (let id of ["microphone", "camera", "screen"]) {
let convertId = idToConvert => {
if (idToConvert == "camera")
return "video";
if (idToConvert == "microphone")
return "audio";
return idToConvert;