Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | const kObservedTopics = [ |
michael@0 | 6 | "getUserMedia:response:allow", |
michael@0 | 7 | "getUserMedia:revoke", |
michael@0 | 8 | "getUserMedia:response:deny", |
michael@0 | 9 | "getUserMedia:request", |
michael@0 | 10 | "recording-device-events", |
michael@0 | 11 | "recording-window-ended" |
michael@0 | 12 | ]; |
michael@0 | 13 | |
michael@0 | 14 | const PREF_PERMISSION_FAKE = "media.navigator.permission.fake"; |
michael@0 | 15 | |
michael@0 | 16 | Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
michael@0 | 17 | XPCOMUtils.defineLazyServiceGetter(this, "MediaManagerService", |
michael@0 | 18 | "@mozilla.org/mediaManagerService;1", |
michael@0 | 19 | "nsIMediaManagerService"); |
michael@0 | 20 | |
michael@0 | 21 | var gObservedTopics = {}; |
michael@0 | 22 | function observer(aSubject, aTopic, aData) { |
michael@0 | 23 | if (!(aTopic in gObservedTopics)) |
michael@0 | 24 | gObservedTopics[aTopic] = 1; |
michael@0 | 25 | else |
michael@0 | 26 | ++gObservedTopics[aTopic]; |
michael@0 | 27 | } |
michael@0 | 28 | |
michael@0 | 29 | function promiseObserverCalled(aTopic, aAction) { |
michael@0 | 30 | let deferred = Promise.defer(); |
michael@0 | 31 | |
michael@0 | 32 | Services.obs.addObserver(function observer() { |
michael@0 | 33 | ok(true, "got " + aTopic + " notification"); |
michael@0 | 34 | Services.obs.removeObserver(observer, aTopic); |
michael@0 | 35 | |
michael@0 | 36 | if (kObservedTopics.indexOf(aTopic) != -1) { |
michael@0 | 37 | if (!(aTopic in gObservedTopics)) |
michael@0 | 38 | gObservedTopics[aTopic] = -1; |
michael@0 | 39 | else |
michael@0 | 40 | --gObservedTopics[aTopic]; |
michael@0 | 41 | } |
michael@0 | 42 | |
michael@0 | 43 | deferred.resolve(); |
michael@0 | 44 | }, aTopic, false); |
michael@0 | 45 | |
michael@0 | 46 | if (aAction) |
michael@0 | 47 | aAction(); |
michael@0 | 48 | |
michael@0 | 49 | return deferred.promise; |
michael@0 | 50 | } |
michael@0 | 51 | |
michael@0 | 52 | function expectObserverCalled(aTopic) { |
michael@0 | 53 | is(gObservedTopics[aTopic], 1, "expected notification " + aTopic); |
michael@0 | 54 | if (aTopic in gObservedTopics) |
michael@0 | 55 | --gObservedTopics[aTopic]; |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | function expectNoObserverCalled() { |
michael@0 | 59 | for (let topic in gObservedTopics) { |
michael@0 | 60 | if (gObservedTopics[topic]) |
michael@0 | 61 | is(gObservedTopics[topic], 0, topic + " notification unexpected"); |
michael@0 | 62 | } |
michael@0 | 63 | gObservedTopics = {} |
michael@0 | 64 | } |
michael@0 | 65 | |
michael@0 | 66 | function promiseMessage(aMessage, aAction) { |
michael@0 | 67 | let deferred = Promise.defer(); |
michael@0 | 68 | |
michael@0 | 69 | content.addEventListener("message", function messageListener(event) { |
michael@0 | 70 | content.removeEventListener("message", messageListener); |
michael@0 | 71 | is(event.data, aMessage, "received " + aMessage); |
michael@0 | 72 | if (event.data == aMessage) |
michael@0 | 73 | deferred.resolve(); |
michael@0 | 74 | else |
michael@0 | 75 | deferred.reject(); |
michael@0 | 76 | }); |
michael@0 | 77 | |
michael@0 | 78 | if (aAction) |
michael@0 | 79 | aAction(); |
michael@0 | 80 | |
michael@0 | 81 | return deferred.promise; |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | function promisePopupNotificationShown(aName, aAction) { |
michael@0 | 85 | let deferred = Promise.defer(); |
michael@0 | 86 | |
michael@0 | 87 | PopupNotifications.panel.addEventListener("popupshown", function popupNotifShown() { |
michael@0 | 88 | PopupNotifications.panel.removeEventListener("popupshown", popupNotifShown); |
michael@0 | 89 | |
michael@0 | 90 | ok(!!PopupNotifications.getNotification(aName), aName + " notification shown"); |
michael@0 | 91 | ok(PopupNotifications.isPanelOpen, "notification panel open"); |
michael@0 | 92 | ok(!!PopupNotifications.panel.firstChild, "notification panel populated"); |
michael@0 | 93 | |
michael@0 | 94 | deferred.resolve(); |
michael@0 | 95 | }); |
michael@0 | 96 | |
michael@0 | 97 | if (aAction) |
michael@0 | 98 | aAction(); |
michael@0 | 99 | |
michael@0 | 100 | return deferred.promise; |
michael@0 | 101 | } |
michael@0 | 102 | |
michael@0 | 103 | function promisePopupNotification(aName) { |
michael@0 | 104 | let deferred = Promise.defer(); |
michael@0 | 105 | |
michael@0 | 106 | waitForCondition(() => PopupNotifications.getNotification(aName), |
michael@0 | 107 | () => { |
michael@0 | 108 | ok(!!PopupNotifications.getNotification(aName), |
michael@0 | 109 | aName + " notification appeared"); |
michael@0 | 110 | |
michael@0 | 111 | deferred.resolve(); |
michael@0 | 112 | }, "timeout waiting for popup notification " + aName); |
michael@0 | 113 | |
michael@0 | 114 | return deferred.promise; |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | function promiseNoPopupNotification(aName) { |
michael@0 | 118 | let deferred = Promise.defer(); |
michael@0 | 119 | |
michael@0 | 120 | waitForCondition(() => !PopupNotifications.getNotification(aName), |
michael@0 | 121 | () => { |
michael@0 | 122 | ok(!PopupNotifications.getNotification(aName), |
michael@0 | 123 | aName + " notification removed"); |
michael@0 | 124 | deferred.resolve(); |
michael@0 | 125 | }, "timeout waiting for popup notification " + aName + " to disappear"); |
michael@0 | 126 | |
michael@0 | 127 | return deferred.promise; |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | const kActionAlways = 1; |
michael@0 | 131 | const kActionDeny = 2; |
michael@0 | 132 | const kActionNever = 3; |
michael@0 | 133 | |
michael@0 | 134 | function activateSecondaryAction(aAction) { |
michael@0 | 135 | let notification = PopupNotifications.panel.firstChild; |
michael@0 | 136 | notification.button.focus(); |
michael@0 | 137 | let popup = notification.menupopup; |
michael@0 | 138 | popup.addEventListener("popupshown", function () { |
michael@0 | 139 | popup.removeEventListener("popupshown", arguments.callee, false); |
michael@0 | 140 | |
michael@0 | 141 | // Press 'down' as many time as needed to select the requested action. |
michael@0 | 142 | while (aAction--) |
michael@0 | 143 | EventUtils.synthesizeKey("VK_DOWN", {}); |
michael@0 | 144 | |
michael@0 | 145 | // Activate |
michael@0 | 146 | EventUtils.synthesizeKey("VK_RETURN", {}); |
michael@0 | 147 | }, false); |
michael@0 | 148 | |
michael@0 | 149 | // One down event to open the popup |
michael@0 | 150 | EventUtils.synthesizeKey("VK_DOWN", |
michael@0 | 151 | { altKey: !navigator.platform.contains("Mac") }); |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 154 | registerCleanupFunction(function() { |
michael@0 | 155 | gBrowser.removeCurrentTab(); |
michael@0 | 156 | kObservedTopics.forEach(topic => { |
michael@0 | 157 | Services.obs.removeObserver(observer, topic); |
michael@0 | 158 | }); |
michael@0 | 159 | Services.prefs.clearUserPref(PREF_PERMISSION_FAKE); |
michael@0 | 160 | }); |
michael@0 | 161 | |
michael@0 | 162 | function getMediaCaptureState() { |
michael@0 | 163 | let hasVideo = {}; |
michael@0 | 164 | let hasAudio = {}; |
michael@0 | 165 | MediaManagerService.mediaCaptureWindowState(content, hasVideo, hasAudio); |
michael@0 | 166 | if (hasVideo.value && hasAudio.value) |
michael@0 | 167 | return "CameraAndMicrophone"; |
michael@0 | 168 | if (hasVideo.value) |
michael@0 | 169 | return "Camera"; |
michael@0 | 170 | if (hasAudio.value) |
michael@0 | 171 | return "Microphone"; |
michael@0 | 172 | return "none"; |
michael@0 | 173 | } |
michael@0 | 174 | |
michael@0 | 175 | function closeStream(aAlreadyClosed) { |
michael@0 | 176 | expectNoObserverCalled(); |
michael@0 | 177 | |
michael@0 | 178 | info("closing the stream"); |
michael@0 | 179 | content.wrappedJSObject.closeStream(); |
michael@0 | 180 | |
michael@0 | 181 | if (!aAlreadyClosed) |
michael@0 | 182 | yield promiseObserverCalled("recording-device-events"); |
michael@0 | 183 | |
michael@0 | 184 | yield promiseNoPopupNotification("webRTC-sharingDevices"); |
michael@0 | 185 | if (!aAlreadyClosed) |
michael@0 | 186 | expectObserverCalled("recording-window-ended"); |
michael@0 | 187 | |
michael@0 | 188 | let statusButton = document.getElementById("webrtc-status-button"); |
michael@0 | 189 | ok(statusButton.hidden, "WebRTC status button hidden"); |
michael@0 | 190 | } |
michael@0 | 191 | |
michael@0 | 192 | function checkDeviceSelectors(aAudio, aVideo) { |
michael@0 | 193 | let micSelector = document.getElementById("webRTC-selectMicrophone"); |
michael@0 | 194 | if (aAudio) |
michael@0 | 195 | ok(!micSelector.hidden, "microphone selector visible"); |
michael@0 | 196 | else |
michael@0 | 197 | ok(micSelector.hidden, "microphone selector hidden"); |
michael@0 | 198 | |
michael@0 | 199 | let cameraSelector = document.getElementById("webRTC-selectCamera"); |
michael@0 | 200 | if (aVideo) |
michael@0 | 201 | ok(!cameraSelector.hidden, "camera selector visible"); |
michael@0 | 202 | else |
michael@0 | 203 | ok(cameraSelector.hidden, "camera selector hidden"); |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | function checkSharingUI() { |
michael@0 | 207 | yield promisePopupNotification("webRTC-sharingDevices"); |
michael@0 | 208 | let statusButton = document.getElementById("webrtc-status-button"); |
michael@0 | 209 | ok(!statusButton.hidden, "WebRTC status button visible"); |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | function checkNotSharing() { |
michael@0 | 213 | is(getMediaCaptureState(), "none", "expected nothing to be shared"); |
michael@0 | 214 | |
michael@0 | 215 | ok(!PopupNotifications.getNotification("webRTC-sharingDevices"), |
michael@0 | 216 | "no webRTC-sharingDevices popup notification"); |
michael@0 | 217 | |
michael@0 | 218 | let statusButton = document.getElementById("webrtc-status-button"); |
michael@0 | 219 | ok(statusButton.hidden, "WebRTC status button hidden"); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | let gTests = [ |
michael@0 | 223 | |
michael@0 | 224 | { |
michael@0 | 225 | desc: "getUserMedia audio+video", |
michael@0 | 226 | run: function checkAudioVideo() { |
michael@0 | 227 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 228 | info("requesting devices"); |
michael@0 | 229 | content.wrappedJSObject.requestDevice(true, true); |
michael@0 | 230 | }); |
michael@0 | 231 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 232 | |
michael@0 | 233 | is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID, |
michael@0 | 234 | "webRTC-shareDevices-notification-icon", "anchored to device icon"); |
michael@0 | 235 | checkDeviceSelectors(true, true); |
michael@0 | 236 | is(PopupNotifications.panel.firstChild.getAttribute("popupid"), |
michael@0 | 237 | "webRTC-shareDevices", "panel using devices icon"); |
michael@0 | 238 | |
michael@0 | 239 | yield promiseMessage("ok", () => { |
michael@0 | 240 | PopupNotifications.panel.firstChild.button.click(); |
michael@0 | 241 | }); |
michael@0 | 242 | expectObserverCalled("getUserMedia:response:allow"); |
michael@0 | 243 | expectObserverCalled("recording-device-events"); |
michael@0 | 244 | is(getMediaCaptureState(), "CameraAndMicrophone", |
michael@0 | 245 | "expected camera and microphone to be shared"); |
michael@0 | 246 | |
michael@0 | 247 | yield checkSharingUI(); |
michael@0 | 248 | yield closeStream(); |
michael@0 | 249 | } |
michael@0 | 250 | }, |
michael@0 | 251 | |
michael@0 | 252 | { |
michael@0 | 253 | desc: "getUserMedia audio only", |
michael@0 | 254 | run: function checkAudioOnly() { |
michael@0 | 255 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 256 | info("requesting devices"); |
michael@0 | 257 | content.wrappedJSObject.requestDevice(true); |
michael@0 | 258 | }); |
michael@0 | 259 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 260 | |
michael@0 | 261 | is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID, |
michael@0 | 262 | "webRTC-shareMicrophone-notification-icon", "anchored to mic icon"); |
michael@0 | 263 | checkDeviceSelectors(true); |
michael@0 | 264 | is(PopupNotifications.panel.firstChild.getAttribute("popupid"), |
michael@0 | 265 | "webRTC-shareMicrophone", "panel using microphone icon"); |
michael@0 | 266 | |
michael@0 | 267 | yield promiseMessage("ok", () => { |
michael@0 | 268 | PopupNotifications.panel.firstChild.button.click(); |
michael@0 | 269 | }); |
michael@0 | 270 | expectObserverCalled("getUserMedia:response:allow"); |
michael@0 | 271 | expectObserverCalled("recording-device-events"); |
michael@0 | 272 | is(getMediaCaptureState(), "Microphone", "expected microphone to be shared"); |
michael@0 | 273 | |
michael@0 | 274 | yield checkSharingUI(); |
michael@0 | 275 | yield closeStream(); |
michael@0 | 276 | } |
michael@0 | 277 | }, |
michael@0 | 278 | |
michael@0 | 279 | { |
michael@0 | 280 | desc: "getUserMedia video only", |
michael@0 | 281 | run: function checkVideoOnly() { |
michael@0 | 282 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 283 | info("requesting devices"); |
michael@0 | 284 | content.wrappedJSObject.requestDevice(false, true); |
michael@0 | 285 | }); |
michael@0 | 286 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 287 | |
michael@0 | 288 | is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID, |
michael@0 | 289 | "webRTC-shareDevices-notification-icon", "anchored to device icon"); |
michael@0 | 290 | checkDeviceSelectors(false, true); |
michael@0 | 291 | is(PopupNotifications.panel.firstChild.getAttribute("popupid"), |
michael@0 | 292 | "webRTC-shareDevices", "panel using devices icon"); |
michael@0 | 293 | |
michael@0 | 294 | yield promiseMessage("ok", () => { |
michael@0 | 295 | PopupNotifications.panel.firstChild.button.click(); |
michael@0 | 296 | }); |
michael@0 | 297 | expectObserverCalled("getUserMedia:response:allow"); |
michael@0 | 298 | expectObserverCalled("recording-device-events"); |
michael@0 | 299 | is(getMediaCaptureState(), "Camera", "expected camera to be shared"); |
michael@0 | 300 | |
michael@0 | 301 | yield checkSharingUI(); |
michael@0 | 302 | yield closeStream(); |
michael@0 | 303 | } |
michael@0 | 304 | }, |
michael@0 | 305 | |
michael@0 | 306 | { |
michael@0 | 307 | desc: "getUserMedia audio+video, user disables video", |
michael@0 | 308 | run: function checkDisableVideo() { |
michael@0 | 309 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 310 | info("requesting devices"); |
michael@0 | 311 | content.wrappedJSObject.requestDevice(true, true); |
michael@0 | 312 | }); |
michael@0 | 313 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 314 | checkDeviceSelectors(true, true); |
michael@0 | 315 | |
michael@0 | 316 | // disable the camera |
michael@0 | 317 | document.getElementById("webRTC-selectCamera-menulist").value = -1; |
michael@0 | 318 | |
michael@0 | 319 | yield promiseMessage("ok", () => { |
michael@0 | 320 | PopupNotifications.panel.firstChild.button.click(); |
michael@0 | 321 | }); |
michael@0 | 322 | |
michael@0 | 323 | // reset the menuitem to have no impact on the following tests. |
michael@0 | 324 | document.getElementById("webRTC-selectCamera-menulist").value = 0; |
michael@0 | 325 | |
michael@0 | 326 | expectObserverCalled("getUserMedia:response:allow"); |
michael@0 | 327 | expectObserverCalled("recording-device-events"); |
michael@0 | 328 | is(getMediaCaptureState(), "Microphone", |
michael@0 | 329 | "expected microphone to be shared"); |
michael@0 | 330 | |
michael@0 | 331 | yield checkSharingUI(); |
michael@0 | 332 | yield closeStream(); |
michael@0 | 333 | } |
michael@0 | 334 | }, |
michael@0 | 335 | |
michael@0 | 336 | { |
michael@0 | 337 | desc: "getUserMedia audio+video, user disables audio", |
michael@0 | 338 | run: function checkDisableAudio() { |
michael@0 | 339 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 340 | info("requesting devices"); |
michael@0 | 341 | content.wrappedJSObject.requestDevice(true, true); |
michael@0 | 342 | }); |
michael@0 | 343 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 344 | checkDeviceSelectors(true, true); |
michael@0 | 345 | |
michael@0 | 346 | // disable the microphone |
michael@0 | 347 | document.getElementById("webRTC-selectMicrophone-menulist").value = -1; |
michael@0 | 348 | |
michael@0 | 349 | yield promiseMessage("ok", () => { |
michael@0 | 350 | PopupNotifications.panel.firstChild.button.click(); |
michael@0 | 351 | }); |
michael@0 | 352 | |
michael@0 | 353 | // reset the menuitem to have no impact on the following tests. |
michael@0 | 354 | document.getElementById("webRTC-selectMicrophone-menulist").value = 0; |
michael@0 | 355 | |
michael@0 | 356 | expectObserverCalled("getUserMedia:response:allow"); |
michael@0 | 357 | expectObserverCalled("recording-device-events"); |
michael@0 | 358 | is(getMediaCaptureState(), "Camera", |
michael@0 | 359 | "expected microphone to be shared"); |
michael@0 | 360 | |
michael@0 | 361 | yield checkSharingUI(); |
michael@0 | 362 | yield closeStream(); |
michael@0 | 363 | } |
michael@0 | 364 | }, |
michael@0 | 365 | |
michael@0 | 366 | { |
michael@0 | 367 | desc: "getUserMedia audio+video, user disables both audio and video", |
michael@0 | 368 | run: function checkDisableAudioVideo() { |
michael@0 | 369 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 370 | info("requesting devices"); |
michael@0 | 371 | content.wrappedJSObject.requestDevice(true, true); |
michael@0 | 372 | }); |
michael@0 | 373 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 374 | checkDeviceSelectors(true, true); |
michael@0 | 375 | |
michael@0 | 376 | // disable the camera and microphone |
michael@0 | 377 | document.getElementById("webRTC-selectCamera-menulist").value = -1; |
michael@0 | 378 | document.getElementById("webRTC-selectMicrophone-menulist").value = -1; |
michael@0 | 379 | |
michael@0 | 380 | yield promiseMessage("error: PERMISSION_DENIED", () => { |
michael@0 | 381 | PopupNotifications.panel.firstChild.button.click(); |
michael@0 | 382 | }); |
michael@0 | 383 | |
michael@0 | 384 | // reset the menuitems to have no impact on the following tests. |
michael@0 | 385 | document.getElementById("webRTC-selectCamera-menulist").value = 0; |
michael@0 | 386 | document.getElementById("webRTC-selectMicrophone-menulist").value = 0; |
michael@0 | 387 | |
michael@0 | 388 | expectObserverCalled("getUserMedia:response:deny"); |
michael@0 | 389 | expectObserverCalled("recording-window-ended"); |
michael@0 | 390 | checkNotSharing(); |
michael@0 | 391 | } |
michael@0 | 392 | }, |
michael@0 | 393 | |
michael@0 | 394 | { |
michael@0 | 395 | desc: "getUserMedia audio+video, user clicks \"Don't Share\"", |
michael@0 | 396 | run: function checkDontShare() { |
michael@0 | 397 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 398 | info("requesting devices"); |
michael@0 | 399 | content.wrappedJSObject.requestDevice(true, true); |
michael@0 | 400 | }); |
michael@0 | 401 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 402 | checkDeviceSelectors(true, true); |
michael@0 | 403 | |
michael@0 | 404 | yield promiseMessage("error: PERMISSION_DENIED", () => { |
michael@0 | 405 | activateSecondaryAction(kActionDeny); |
michael@0 | 406 | }); |
michael@0 | 407 | |
michael@0 | 408 | expectObserverCalled("getUserMedia:response:deny"); |
michael@0 | 409 | expectObserverCalled("recording-window-ended"); |
michael@0 | 410 | checkNotSharing(); |
michael@0 | 411 | } |
michael@0 | 412 | }, |
michael@0 | 413 | |
michael@0 | 414 | { |
michael@0 | 415 | desc: "getUserMedia audio+video: stop sharing", |
michael@0 | 416 | run: function checkStopSharing() { |
michael@0 | 417 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 418 | info("requesting devices"); |
michael@0 | 419 | content.wrappedJSObject.requestDevice(true, true); |
michael@0 | 420 | }); |
michael@0 | 421 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 422 | checkDeviceSelectors(true, true); |
michael@0 | 423 | |
michael@0 | 424 | yield promiseMessage("ok", () => { |
michael@0 | 425 | PopupNotifications.panel.firstChild.button.click(); |
michael@0 | 426 | }); |
michael@0 | 427 | expectObserverCalled("getUserMedia:response:allow"); |
michael@0 | 428 | expectObserverCalled("recording-device-events"); |
michael@0 | 429 | is(getMediaCaptureState(), "CameraAndMicrophone", |
michael@0 | 430 | "expected camera and microphone to be shared"); |
michael@0 | 431 | |
michael@0 | 432 | yield checkSharingUI(); |
michael@0 | 433 | |
michael@0 | 434 | PopupNotifications.getNotification("webRTC-sharingDevices").reshow(); |
michael@0 | 435 | activateSecondaryAction(kActionDeny); |
michael@0 | 436 | |
michael@0 | 437 | yield promiseObserverCalled("recording-device-events"); |
michael@0 | 438 | expectObserverCalled("getUserMedia:revoke"); |
michael@0 | 439 | |
michael@0 | 440 | yield promiseNoPopupNotification("webRTC-sharingDevices"); |
michael@0 | 441 | |
michael@0 | 442 | if (gObservedTopics["recording-device-events"] == 1) { |
michael@0 | 443 | todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719"); |
michael@0 | 444 | gObservedTopics["recording-device-events"] = 0; |
michael@0 | 445 | } |
michael@0 | 446 | |
michael@0 | 447 | expectNoObserverCalled(); |
michael@0 | 448 | checkNotSharing(); |
michael@0 | 449 | |
michael@0 | 450 | // the stream is already closed, but this will do some cleanup anyway |
michael@0 | 451 | yield closeStream(true); |
michael@0 | 452 | } |
michael@0 | 453 | }, |
michael@0 | 454 | |
michael@0 | 455 | { |
michael@0 | 456 | desc: "getUserMedia prompt: Always/Never Share", |
michael@0 | 457 | run: function checkRememberCheckbox() { |
michael@0 | 458 | let elt = id => document.getElementById(id); |
michael@0 | 459 | |
michael@0 | 460 | function checkPerm(aRequestAudio, aRequestVideo, aAllowAudio, aAllowVideo, |
michael@0 | 461 | aExpectedAudioPerm, aExpectedVideoPerm, aNever) { |
michael@0 | 462 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 463 | content.wrappedJSObject.requestDevice(aRequestAudio, aRequestVideo); |
michael@0 | 464 | }); |
michael@0 | 465 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 466 | |
michael@0 | 467 | let noAudio = aAllowAudio === undefined; |
michael@0 | 468 | is(elt("webRTC-selectMicrophone").hidden, noAudio, |
michael@0 | 469 | "microphone selector expected to be " + (noAudio ? "hidden" : "visible")); |
michael@0 | 470 | if (!noAudio) |
michael@0 | 471 | elt("webRTC-selectMicrophone-menulist").value = (aAllowAudio || aNever) ? 0 : -1; |
michael@0 | 472 | |
michael@0 | 473 | let noVideo = aAllowVideo === undefined; |
michael@0 | 474 | is(elt("webRTC-selectCamera").hidden, noVideo, |
michael@0 | 475 | "camera selector expected to be " + (noVideo ? "hidden" : "visible")); |
michael@0 | 476 | if (!noVideo) |
michael@0 | 477 | elt("webRTC-selectCamera-menulist").value = (aAllowVideo || aNever) ? 0 : -1; |
michael@0 | 478 | |
michael@0 | 479 | let expectedMessage = |
michael@0 | 480 | (aAllowVideo || aAllowAudio) ? "ok" : "error: PERMISSION_DENIED"; |
michael@0 | 481 | yield promiseMessage(expectedMessage, () => { |
michael@0 | 482 | activateSecondaryAction(aNever ? kActionNever : kActionAlways); |
michael@0 | 483 | }); |
michael@0 | 484 | let expected = []; |
michael@0 | 485 | if (expectedMessage == "ok") { |
michael@0 | 486 | expectObserverCalled("getUserMedia:response:allow"); |
michael@0 | 487 | expectObserverCalled("recording-device-events"); |
michael@0 | 488 | if (aAllowVideo) |
michael@0 | 489 | expected.push("Camera"); |
michael@0 | 490 | if (aAllowAudio) |
michael@0 | 491 | expected.push("Microphone"); |
michael@0 | 492 | expected = expected.join("And"); |
michael@0 | 493 | } |
michael@0 | 494 | else { |
michael@0 | 495 | expectObserverCalled("getUserMedia:response:deny"); |
michael@0 | 496 | expectObserverCalled("recording-window-ended"); |
michael@0 | 497 | expected = "none"; |
michael@0 | 498 | } |
michael@0 | 499 | is(getMediaCaptureState(), expected, |
michael@0 | 500 | "expected " + expected + " to be shared"); |
michael@0 | 501 | |
michael@0 | 502 | function checkDevicePermissions(aDevice, aExpected) { |
michael@0 | 503 | let Perms = Services.perms; |
michael@0 | 504 | let uri = content.document.documentURIObject; |
michael@0 | 505 | let devicePerms = Perms.testExactPermission(uri, aDevice); |
michael@0 | 506 | if (aExpected === undefined) |
michael@0 | 507 | is(devicePerms, Perms.UNKNOWN_ACTION, "no " + aDevice + " persistent permissions"); |
michael@0 | 508 | else { |
michael@0 | 509 | is(devicePerms, aExpected ? Perms.ALLOW_ACTION : Perms.DENY_ACTION, |
michael@0 | 510 | aDevice + " persistently " + (aExpected ? "allowed" : "denied")); |
michael@0 | 511 | } |
michael@0 | 512 | Perms.remove(uri.host, aDevice); |
michael@0 | 513 | } |
michael@0 | 514 | checkDevicePermissions("microphone", aExpectedAudioPerm); |
michael@0 | 515 | checkDevicePermissions("camera", aExpectedVideoPerm); |
michael@0 | 516 | |
michael@0 | 517 | if (expectedMessage == "ok") |
michael@0 | 518 | yield closeStream(); |
michael@0 | 519 | } |
michael@0 | 520 | |
michael@0 | 521 | // 3 cases where the user accepts the device prompt. |
michael@0 | 522 | info("audio+video, user grants, expect both perms set to allow"); |
michael@0 | 523 | yield checkPerm(true, true, true, true, true, true); |
michael@0 | 524 | info("audio only, user grants, check audio perm set to allow, video perm not set"); |
michael@0 | 525 | yield checkPerm(true, false, true, undefined, true, undefined); |
michael@0 | 526 | info("video only, user grants, check video perm set to allow, audio perm not set"); |
michael@0 | 527 | yield checkPerm(false, true, undefined, true, undefined, true); |
michael@0 | 528 | |
michael@0 | 529 | // 3 cases where the user rejects the device request. |
michael@0 | 530 | // First test these cases by setting the device to 'No Audio'/'No Video' |
michael@0 | 531 | info("audio+video, user denies, expect both perms set to deny"); |
michael@0 | 532 | yield checkPerm(true, true, false, false, false, false); |
michael@0 | 533 | info("audio only, user denies, expect audio perm set to deny, video not set"); |
michael@0 | 534 | yield checkPerm(true, false, false, undefined, false, undefined); |
michael@0 | 535 | info("video only, user denies, expect video perm set to deny, audio perm not set"); |
michael@0 | 536 | yield checkPerm(false, true, undefined, false, undefined, false); |
michael@0 | 537 | // Now test these 3 cases again by using the 'Never Share' action. |
michael@0 | 538 | info("audio+video, user denies, expect both perms set to deny"); |
michael@0 | 539 | yield checkPerm(true, true, false, false, false, false, true); |
michael@0 | 540 | info("audio only, user denies, expect audio perm set to deny, video not set"); |
michael@0 | 541 | yield checkPerm(true, false, false, undefined, false, undefined, true); |
michael@0 | 542 | info("video only, user denies, expect video perm set to deny, audio perm not set"); |
michael@0 | 543 | yield checkPerm(false, true, undefined, false, undefined, false, true); |
michael@0 | 544 | |
michael@0 | 545 | // 2 cases where the user allows half of what's requested. |
michael@0 | 546 | info("audio+video, user denies video, grants audio, " + |
michael@0 | 547 | "expect video perm set to deny, audio perm set to allow."); |
michael@0 | 548 | yield checkPerm(true, true, true, false, true, false); |
michael@0 | 549 | info("audio+video, user denies audio, grants video, " + |
michael@0 | 550 | "expect video perm set to allow, audio perm set to deny."); |
michael@0 | 551 | yield checkPerm(true, true, false, true, false, true); |
michael@0 | 552 | |
michael@0 | 553 | // reset the menuitems to have no impact on the following tests. |
michael@0 | 554 | elt("webRTC-selectMicrophone-menulist").value = 0; |
michael@0 | 555 | elt("webRTC-selectCamera-menulist").value = 0; |
michael@0 | 556 | } |
michael@0 | 557 | }, |
michael@0 | 558 | |
michael@0 | 559 | { |
michael@0 | 560 | desc: "getUserMedia without prompt: use persistent permissions", |
michael@0 | 561 | run: function checkUsePersistentPermissions() { |
michael@0 | 562 | function usePerm(aAllowAudio, aAllowVideo, aRequestAudio, aRequestVideo, |
michael@0 | 563 | aExpectStream) { |
michael@0 | 564 | let Perms = Services.perms; |
michael@0 | 565 | let uri = content.document.documentURIObject; |
michael@0 | 566 | if (aAllowAudio !== undefined) { |
michael@0 | 567 | Perms.add(uri, "microphone", aAllowAudio ? Perms.ALLOW_ACTION |
michael@0 | 568 | : Perms.DENY_ACTION); |
michael@0 | 569 | } |
michael@0 | 570 | if (aAllowVideo !== undefined) { |
michael@0 | 571 | Perms.add(uri, "camera", aAllowVideo ? Perms.ALLOW_ACTION |
michael@0 | 572 | : Perms.DENY_ACTION); |
michael@0 | 573 | } |
michael@0 | 574 | |
michael@0 | 575 | let gum = function() { |
michael@0 | 576 | content.wrappedJSObject.requestDevice(aRequestAudio, aRequestVideo); |
michael@0 | 577 | }; |
michael@0 | 578 | |
michael@0 | 579 | if (aExpectStream === undefined) { |
michael@0 | 580 | // Check that we get a prompt. |
michael@0 | 581 | yield promisePopupNotificationShown("webRTC-shareDevices", gum); |
michael@0 | 582 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 583 | |
michael@0 | 584 | // Deny the request to cleanup... |
michael@0 | 585 | yield promiseMessage("error: PERMISSION_DENIED", () => { |
michael@0 | 586 | activateSecondaryAction(kActionDeny); |
michael@0 | 587 | }); |
michael@0 | 588 | expectObserverCalled("getUserMedia:response:deny"); |
michael@0 | 589 | expectObserverCalled("recording-window-ended"); |
michael@0 | 590 | } |
michael@0 | 591 | else { |
michael@0 | 592 | let expectedMessage = aExpectStream ? "ok" : "error: PERMISSION_DENIED"; |
michael@0 | 593 | yield promiseMessage(expectedMessage, gum); |
michael@0 | 594 | |
michael@0 | 595 | if (expectedMessage == "ok") { |
michael@0 | 596 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 597 | yield promiseNoPopupNotification("webRTC-shareDevices"); |
michael@0 | 598 | expectObserverCalled("getUserMedia:response:allow"); |
michael@0 | 599 | expectObserverCalled("recording-device-events"); |
michael@0 | 600 | |
michael@0 | 601 | // Check what's actually shared. |
michael@0 | 602 | let expected = []; |
michael@0 | 603 | if (aAllowVideo && aRequestVideo) |
michael@0 | 604 | expected.push("Camera"); |
michael@0 | 605 | if (aAllowAudio && aRequestAudio) |
michael@0 | 606 | expected.push("Microphone"); |
michael@0 | 607 | expected = expected.join("And"); |
michael@0 | 608 | is(getMediaCaptureState(), expected, |
michael@0 | 609 | "expected " + expected + " to be shared"); |
michael@0 | 610 | |
michael@0 | 611 | yield closeStream(); |
michael@0 | 612 | } |
michael@0 | 613 | else { |
michael@0 | 614 | expectObserverCalled("recording-window-ended"); |
michael@0 | 615 | } |
michael@0 | 616 | } |
michael@0 | 617 | |
michael@0 | 618 | Perms.remove(uri.host, "camera"); |
michael@0 | 619 | Perms.remove(uri.host, "microphone"); |
michael@0 | 620 | } |
michael@0 | 621 | |
michael@0 | 622 | // Set both permissions identically |
michael@0 | 623 | info("allow audio+video, request audio+video, expect ok (audio+video)"); |
michael@0 | 624 | yield usePerm(true, true, true, true, true); |
michael@0 | 625 | info("deny audio+video, request audio+video, expect denied"); |
michael@0 | 626 | yield usePerm(false, false, true, true, false); |
michael@0 | 627 | |
michael@0 | 628 | // Allow audio, deny video. |
michael@0 | 629 | info("allow audio, deny video, request audio+video, expect ok (audio)"); |
michael@0 | 630 | yield usePerm(true, false, true, true, true); |
michael@0 | 631 | info("allow audio, deny video, request audio, expect ok (audio)"); |
michael@0 | 632 | yield usePerm(true, false, true, false, true); |
michael@0 | 633 | info("allow audio, deny video, request video, expect denied"); |
michael@0 | 634 | yield usePerm(true, false, false, true, false); |
michael@0 | 635 | |
michael@0 | 636 | // Deny audio, allow video. |
michael@0 | 637 | info("deny audio, allow video, request audio+video, expect ok (video)"); |
michael@0 | 638 | yield usePerm(false, true, true, true, true); |
michael@0 | 639 | info("deny audio, allow video, request audio, expect denied"); |
michael@0 | 640 | yield usePerm(false, true, true, false, false); |
michael@0 | 641 | info("deny audio, allow video, request video, expect ok (video)"); |
michael@0 | 642 | yield usePerm(false, true, false, true, true); |
michael@0 | 643 | |
michael@0 | 644 | // Allow audio, video not set. |
michael@0 | 645 | info("allow audio, request audio+video, expect prompt"); |
michael@0 | 646 | yield usePerm(true, undefined, true, true, undefined); |
michael@0 | 647 | info("allow audio, request audio, expect ok (audio)"); |
michael@0 | 648 | yield usePerm(true, undefined, true, false, true); |
michael@0 | 649 | info("allow audio, request video, expect prompt"); |
michael@0 | 650 | yield usePerm(true, undefined, false, true, undefined); |
michael@0 | 651 | |
michael@0 | 652 | // Deny audio, video not set. |
michael@0 | 653 | info("deny audio, request audio+video, expect prompt"); |
michael@0 | 654 | yield usePerm(false, undefined, true, true, undefined); |
michael@0 | 655 | info("deny audio, request audio, expect denied"); |
michael@0 | 656 | yield usePerm(false, undefined, true, false, false); |
michael@0 | 657 | info("deny audio, request video, expect prompt"); |
michael@0 | 658 | yield usePerm(false, undefined, false, true, undefined); |
michael@0 | 659 | |
michael@0 | 660 | // Allow video, video not set. |
michael@0 | 661 | info("allow video, request audio+video, expect prompt"); |
michael@0 | 662 | yield usePerm(undefined, true, true, true, undefined); |
michael@0 | 663 | info("allow video, request audio, expect prompt"); |
michael@0 | 664 | yield usePerm(undefined, true, true, false, undefined); |
michael@0 | 665 | info("allow video, request video, expect ok (video)"); |
michael@0 | 666 | yield usePerm(undefined, true, false, true, true); |
michael@0 | 667 | |
michael@0 | 668 | // Deny video, video not set. |
michael@0 | 669 | info("deny video, request audio+video, expect prompt"); |
michael@0 | 670 | yield usePerm(undefined, false, true, true, undefined); |
michael@0 | 671 | info("deny video, request audio, expect prompt"); |
michael@0 | 672 | yield usePerm(undefined, false, true, false, undefined); |
michael@0 | 673 | info("deny video, request video, expect denied"); |
michael@0 | 674 | yield usePerm(undefined, false, false, true, false); |
michael@0 | 675 | } |
michael@0 | 676 | }, |
michael@0 | 677 | |
michael@0 | 678 | { |
michael@0 | 679 | desc: "Stop Sharing removes persistent permissions", |
michael@0 | 680 | run: function checkStopSharingRemovesPersistentPermissions() { |
michael@0 | 681 | function stopAndCheckPerm(aRequestAudio, aRequestVideo) { |
michael@0 | 682 | let Perms = Services.perms; |
michael@0 | 683 | let uri = content.document.documentURIObject; |
michael@0 | 684 | |
michael@0 | 685 | // Initially set both permissions to 'allow'. |
michael@0 | 686 | Perms.add(uri, "microphone", Perms.ALLOW_ACTION); |
michael@0 | 687 | Perms.add(uri, "camera", Perms.ALLOW_ACTION); |
michael@0 | 688 | |
michael@0 | 689 | // Start sharing what's been requested. |
michael@0 | 690 | yield promiseMessage("ok", () => { |
michael@0 | 691 | content.wrappedJSObject.requestDevice(aRequestAudio, aRequestVideo); |
michael@0 | 692 | }); |
michael@0 | 693 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 694 | expectObserverCalled("getUserMedia:response:allow"); |
michael@0 | 695 | expectObserverCalled("recording-device-events"); |
michael@0 | 696 | yield checkSharingUI(); |
michael@0 | 697 | |
michael@0 | 698 | PopupNotifications.getNotification("webRTC-sharingDevices").reshow(); |
michael@0 | 699 | let expectedIcon = "webRTC-sharingDevices"; |
michael@0 | 700 | if (aRequestAudio && !aRequestVideo) |
michael@0 | 701 | expectedIcon = "webRTC-sharingMicrophone"; |
michael@0 | 702 | is(PopupNotifications.getNotification("webRTC-sharingDevices").anchorID, |
michael@0 | 703 | expectedIcon + "-notification-icon", "anchored to correct icon"); |
michael@0 | 704 | is(PopupNotifications.panel.firstChild.getAttribute("popupid"), expectedIcon, |
michael@0 | 705 | "panel using correct icon"); |
michael@0 | 706 | |
michael@0 | 707 | // Stop sharing. |
michael@0 | 708 | activateSecondaryAction(kActionDeny); |
michael@0 | 709 | |
michael@0 | 710 | yield promiseObserverCalled("recording-device-events"); |
michael@0 | 711 | expectObserverCalled("getUserMedia:revoke"); |
michael@0 | 712 | |
michael@0 | 713 | yield promiseNoPopupNotification("webRTC-sharingDevices"); |
michael@0 | 714 | |
michael@0 | 715 | if (gObservedTopics["recording-device-events"] == 1) { |
michael@0 | 716 | todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719"); |
michael@0 | 717 | gObservedTopics["recording-device-events"] = 0; |
michael@0 | 718 | } |
michael@0 | 719 | |
michael@0 | 720 | // Check that permissions have been removed as expected. |
michael@0 | 721 | let audioPerm = Perms.testExactPermission(uri, "microphone"); |
michael@0 | 722 | if (aRequestAudio) |
michael@0 | 723 | is(audioPerm, Perms.UNKNOWN_ACTION, "microphone permissions removed"); |
michael@0 | 724 | else |
michael@0 | 725 | is(audioPerm, Perms.ALLOW_ACTION, "microphone permissions untouched"); |
michael@0 | 726 | |
michael@0 | 727 | let videoPerm = Perms.testExactPermission(uri, "camera"); |
michael@0 | 728 | if (aRequestVideo) |
michael@0 | 729 | is(videoPerm, Perms.UNKNOWN_ACTION, "camera permissions removed"); |
michael@0 | 730 | else |
michael@0 | 731 | is(videoPerm, Perms.ALLOW_ACTION, "camera permissions untouched"); |
michael@0 | 732 | |
michael@0 | 733 | // Cleanup. |
michael@0 | 734 | yield closeStream(true); |
michael@0 | 735 | |
michael@0 | 736 | Perms.remove(uri.host, "camera"); |
michael@0 | 737 | Perms.remove(uri.host, "microphone"); |
michael@0 | 738 | } |
michael@0 | 739 | |
michael@0 | 740 | info("request audio+video, stop sharing resets both"); |
michael@0 | 741 | yield stopAndCheckPerm(true, true); |
michael@0 | 742 | info("request audio, stop sharing resets audio only"); |
michael@0 | 743 | yield stopAndCheckPerm(true, false); |
michael@0 | 744 | info("request video, stop sharing resets video only"); |
michael@0 | 745 | yield stopAndCheckPerm(false, true); |
michael@0 | 746 | } |
michael@0 | 747 | }, |
michael@0 | 748 | |
michael@0 | 749 | { |
michael@0 | 750 | desc: "'Always Allow' ignored and not shown on http pages", |
michael@0 | 751 | run: function checkNoAlwaysOnHttp() { |
michael@0 | 752 | // Load an http page instead of the https version. |
michael@0 | 753 | let deferred = Promise.defer(); |
michael@0 | 754 | let browser = gBrowser.selectedTab.linkedBrowser; |
michael@0 | 755 | browser.addEventListener("load", function onload() { |
michael@0 | 756 | browser.removeEventListener("load", onload, true); |
michael@0 | 757 | deferred.resolve(); |
michael@0 | 758 | }, true); |
michael@0 | 759 | content.location = content.location.href.replace("https://", "http://"); |
michael@0 | 760 | yield deferred.promise; |
michael@0 | 761 | |
michael@0 | 762 | // Initially set both permissions to 'allow'. |
michael@0 | 763 | let Perms = Services.perms; |
michael@0 | 764 | let uri = content.document.documentURIObject; |
michael@0 | 765 | Perms.add(uri, "microphone", Perms.ALLOW_ACTION); |
michael@0 | 766 | Perms.add(uri, "camera", Perms.ALLOW_ACTION); |
michael@0 | 767 | |
michael@0 | 768 | // Request devices and expect a prompt despite the saved 'Allow' permission, |
michael@0 | 769 | // because the connection isn't secure. |
michael@0 | 770 | yield promisePopupNotificationShown("webRTC-shareDevices", () => { |
michael@0 | 771 | content.wrappedJSObject.requestDevice(true, true); |
michael@0 | 772 | }); |
michael@0 | 773 | expectObserverCalled("getUserMedia:request"); |
michael@0 | 774 | |
michael@0 | 775 | // Ensure that the 'Always Allow' action isn't shown. |
michael@0 | 776 | let alwaysLabel = gNavigatorBundle.getString("getUserMedia.always.label"); |
michael@0 | 777 | ok(!!alwaysLabel, "found the 'Always Allow' localized label"); |
michael@0 | 778 | let labels = []; |
michael@0 | 779 | let notification = PopupNotifications.panel.firstChild; |
michael@0 | 780 | for (let node of notification.childNodes) { |
michael@0 | 781 | if (node.localName == "menuitem") |
michael@0 | 782 | labels.push(node.getAttribute("label")); |
michael@0 | 783 | } |
michael@0 | 784 | is(labels.indexOf(alwaysLabel), -1, "The 'Always Allow' item isn't shown"); |
michael@0 | 785 | |
michael@0 | 786 | // Cleanup. |
michael@0 | 787 | yield closeStream(true); |
michael@0 | 788 | Perms.remove(uri.host, "camera"); |
michael@0 | 789 | Perms.remove(uri.host, "microphone"); |
michael@0 | 790 | } |
michael@0 | 791 | } |
michael@0 | 792 | |
michael@0 | 793 | ]; |
michael@0 | 794 | |
michael@0 | 795 | function test() { |
michael@0 | 796 | waitForExplicitFinish(); |
michael@0 | 797 | |
michael@0 | 798 | let tab = gBrowser.addTab(); |
michael@0 | 799 | gBrowser.selectedTab = tab; |
michael@0 | 800 | tab.linkedBrowser.addEventListener("load", function onload() { |
michael@0 | 801 | tab.linkedBrowser.removeEventListener("load", onload, true); |
michael@0 | 802 | |
michael@0 | 803 | kObservedTopics.forEach(topic => { |
michael@0 | 804 | Services.obs.addObserver(observer, topic, false); |
michael@0 | 805 | }); |
michael@0 | 806 | Services.prefs.setBoolPref(PREF_PERMISSION_FAKE, true); |
michael@0 | 807 | |
michael@0 | 808 | is(PopupNotifications._currentNotifications.length, 0, |
michael@0 | 809 | "should start the test without any prior popup notification"); |
michael@0 | 810 | |
michael@0 | 811 | Task.spawn(function () { |
michael@0 | 812 | for (let test of gTests) { |
michael@0 | 813 | info(test.desc); |
michael@0 | 814 | yield test.run(); |
michael@0 | 815 | |
michael@0 | 816 | // Cleanup before the next test |
michael@0 | 817 | expectNoObserverCalled(); |
michael@0 | 818 | } |
michael@0 | 819 | }).then(finish, ex => { |
michael@0 | 820 | ok(false, "Unexpected Exception: " + ex); |
michael@0 | 821 | finish(); |
michael@0 | 822 | }); |
michael@0 | 823 | }, true); |
michael@0 | 824 | let rootDir = getRootDirectory(gTestPath) |
michael@0 | 825 | rootDir = rootDir.replace("chrome://mochitests/content/", |
michael@0 | 826 | "https://example.com/"); |
michael@0 | 827 | content.location = rootDir + "get_user_media.html"; |
michael@0 | 828 | } |
michael@0 | 829 | |
michael@0 | 830 | |
michael@0 | 831 | function wait(time) { |
michael@0 | 832 | let deferred = Promise.defer(); |
michael@0 | 833 | setTimeout(deferred.resolve, time); |
michael@0 | 834 | return deferred.promise; |
michael@0 | 835 | } |