Bug 1477926 - Test that we hide the autoplay-media permission doorhanger and cancel permission requests when a media element starts playing. r?alwu draft
authorChris Pearce <cpearce@mozilla.com>
Wed, 01 Aug 2018 16:11:05 +1200
changeset 826187 3820a1540ef716ea284737be653c7b64d392dede
parent 826186 eb8ff7d45f82efa05bb4e55bfbef7b6ccedcf0c7
push id118257
push userbmo:cpearce@mozilla.com
push dateFri, 03 Aug 2018 04:44:24 +0000
reviewersalwu
bugs1477926
milestone63.0a1
Bug 1477926 - Test that we hide the autoplay-media permission doorhanger and cancel permission requests when a media element starts playing. r?alwu MozReview-Commit-ID: 5NXT85cOhe1
toolkit/content/tests/browser/browser.ini
toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
toolkit/content/tests/browser/file_video_autoplay.html
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -40,16 +40,17 @@ support-files =
   gizmo.mp4
 [browser_autoplay_policy_play_twice.js]
 support-files =
   gizmo.mp4
   file_video.html
 [browser_autoplay_policy_request_permission.js]
 support-files =
   file_empty.html
+  file_video_autoplay.html
   gizmo.mp4
 [browser_autoplay_policy_user_gestures.js]
 support-files =
   gizmo.mp4
   file_video.html
 [browser_autoplay_videoDocument.js]
 [browser_autoscroll_disabled.js]
 [browser_block_autoplay_media.js]
--- a/toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
+++ b/toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
@@ -21,24 +21,24 @@ add_task(() => {
 //  browser: the browser to run the script in.
 //  args: test case definition, required members {
 //    mode: String, "autoplay attribute" or "call play".
 //  }
 function loadAutoplayVideo(browser, args) {
   return ContentTask.spawn(browser, args, async (args) => {
     info("- create a new autoplay video -");
     let video = content.document.createElement("video");
-    video.id = "v1";
     video.didPlayPromise = new Promise((resolve, reject) => {
       video.addEventListener("play", (e) => {
         video.didPlay = true;
         resolve();
       }, {once: true});
       video.addEventListener("blocked", (e) => {
         video.didPlay = false;
+        video.playPromiseRejected = true;
         resolve();
       }, {once: true});
     });
     if (args.mode == "autoplay attribute") {
       info("autoplay attribute set to true");
       video.autoplay = true;
     } else if (args.mode == "call play") {
       info("will call play() when reached loadedmetadata");
@@ -65,33 +65,33 @@ function loadAutoplayVideo(browser, args
 //  browser: the browser to run the script in.
 //  args: test case definition, required members {
 //    name: String, description of test.
 //    mode: String, "autoplay attribute" or "call play".
 //    shouldPlay: boolean, whether video should play.
 //  }
 function checkVideoDidPlay(browser, args) {
   return ContentTask.spawn(browser, args, async (args) => {
-    let video = content.document.getElementById("v1");
+    let video = content.document.querySelector("video");
     await video.didPlayPromise;
     is(video.didPlay, args.shouldPlay,
       args.name + " should " + (!args.shouldPlay ? "not " : "") + "be able to autoplay");
     video.src = "";
     content.document.body.remove(video);
   });
 }
 
 async function testAutoplayExistingPermission(args) {
   info("- Starting '" + args.name + "' -");
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: VIDEO_PAGE,
   }, async (browser) => {
     let promptShowing = () =>
-    PopupNotifications.getNotification("autoplay-media", browser);
+      PopupNotifications.getNotification("autoplay-media", browser);
 
     SitePermissions.set(browser.currentURI, "autoplay-media", args.permission);
     ok(!promptShowing(), "Should not be showing permission prompt yet");
 
     await loadAutoplayVideo(browser, args);
     await checkVideoDidPlay(browser, args);
 
     // Reset permission.
@@ -197,17 +197,53 @@ add_task(async () => {
   await testAutoplayUnknownPermission({
     name: "Unknown permission click block call play",
     button: "block",
     shouldPlay: false,
     mode: "call play",
   });
 });
 
-// Test that if playback starts while the permission prompt is shown,
+function checkAllVideosNotPlayed(browser) {
+  return ContentTask.spawn(browser, null,
+    async () => {
+      content.document.querySelectorAll("video").forEach((video) => {
+        ok(video.paused && !video.didPlay, "Video should not be playing");
+      });
+  });
+}
+
+function unblockAndPlayVideo(browser, args) {
+  return ContentTask.spawn(browser, args,
+    async (args) => {
+      ok(args.index != undefined, "Must specify index");
+      ok(args.unblockMode != undefined, "Must specify unblock mode");
+      let video = content.document.querySelectorAll("video")[args.index];
+      if (args.unblockMode == "muted") {
+        video.muted = true;
+        // Muting in itself should not cause the previous pending play to proceed.
+        ok(video.paused && !video.didPlay, "First video should not have played yet");
+      } else if (args.unblockMode == "gesture") {
+        // Gesture activate the document, i.e. simulate a click in the document,
+        // to unblock autoplay,
+        content.document.notifyUserGestureActivation();
+      } else {
+        ok(false, "Invalid unblock mode.");
+      }
+      // Trying to play now that we're unblocked should work...
+      let played = await video.play().then(() => true, () => false);
+      ok(played, "Should have played as now muted");
+      // And because we started playing, the previous promise returned in the
+      // previous call to play() should also resolve too.
+      await video.didPlayPromise;
+      ok(video.didPlay, "Existing promise should resolve when media starts playing");
+    });
+}
+
+// Test that if audible playback starts due to user gesture while the permission prompt is shown,
 // that the prompt is hidden.
 add_task(async () => {
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: VIDEO_PAGE,
   }, async (browser) => {
     info("- Started test prompt hides upon play -");
     let promptShowing = () =>
@@ -220,43 +256,131 @@ add_task(async () => {
     let popupshown = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
     await loadAutoplayVideo(browser, { mode: "call play" });
 
     info("Awaiting popupshown");
     await popupshown;
     ok(promptShowing(), "Should now be showing permission prompt");
 
     // Check that the video didn't start playing.
-    await ContentTask.spawn(browser, null,
-      async () => {
-        let video = content.document.getElementById("v1");
-        ok(video.paused && !video.didPlay, "Video should not be playing");
-      });
+    await checkAllVideosNotPlayed(browser);
 
     let popuphidden = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
 
-    await ContentTask.spawn(browser, null,
-      async () => {
-        // Gesture activate the document, i.e. simulate a click in the document,
-        // to unblock autoplay,
-        content.document.notifyUserGestureActivation();
-        let video = content.document.getElementById("v1");
-        // Gesture activating in itself should not cause the previous pending
-        // play to proceed.
-        ok(video.paused && !video.didPlay, "Video should not have played yet");
-        // But trying to play again now that we're gesture activated will work...
-        let played = await video.play().then(() => true, () => false);
-        ok(played, "Should have played as now gesture activated");
-        // And because we started playing, the previous promise returned in the
-        // first call to play() above should also resolve too.
-        await video.didPlayPromise;
-        ok(video.didPlay, "Existing promise should resolve when media starts playing");
-      });
+    // Unblock via user gesture and play.
+    await unblockAndPlayVideo(browser, {index: 0, unblockMode: "gesture"});
 
     info("Awaiting popuphidden");
     await popuphidden;
     ok(!promptShowing(), "Permission prompt should have hidden when media started playing");
 
     // Reset permission.
     SitePermissions.remove(browser.currentURI, "autoplay-media");
     info("- Finished test prompt hides upon play -");
   });
 });
+
+// Test that if there's only 1 document, and inaudible playback starts while
+// the permission prompt is shown, that the prompt is hidden.
+add_task(async () => {
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: VIDEO_PAGE,
+  }, async (browser) => {
+    info("- Started test prompt hides upon inaudible play in 1 doc -");
+    let promptShowing = () =>
+      PopupNotifications.getNotification("autoplay-media", browser);
+
+    // Set this site to ask permission to autoplay.
+    SitePermissions.set(browser.currentURI, "autoplay-media", SitePermissions.UNKNOWN);
+    ok(!promptShowing(), "Should not be showing permission prompt");
+
+    let popupshown = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    await loadAutoplayVideo(browser, { mode: "call play" });
+
+    info("Awaiting popupshown");
+    await popupshown;
+    ok(promptShowing(), "Should now be showing permission prompt");
+
+    // Check that the video didn't start playing.
+    await checkAllVideosNotPlayed(browser);
+
+    let popuphidden = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+
+    // Make video inaudible, and then start to play.
+    await unblockAndPlayVideo(browser, {index: 0, unblockMode: "muted"});
+
+    info("Awaiting popuphidden");
+    await popuphidden;
+    ok(!promptShowing(), "Permission prompt should have hidden when media started playing");
+
+    // Reset permission.
+    SitePermissions.remove(browser.currentURI, "autoplay-media");
+    info("- Finished test prompt hides upon inaudible play in 1 doc -");
+  });
+});
+
+// Test that one media element playing inaudibly will cause other media elements
+// waiting on a doorhanger to have their play promises rejected.
+add_task(async () => {
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: VIDEO_PAGE,
+  }, async (browser) => {
+    info("- Started test prompt hides upon inaudible play in multi doc -");
+    let promptShowing = () =>
+      PopupNotifications.getNotification("autoplay-media", browser);
+
+    // Set this site to ask permission to autoplay.
+    SitePermissions.set(browser.currentURI, "autoplay-media", SitePermissions.UNKNOWN);
+    ok(!promptShowing(), "Should not be showing permission prompt");
+
+    let popupshown = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+
+    // Load multiple videos.
+    await loadAutoplayVideo(browser, { mode: "call play" });
+    await loadAutoplayVideo(browser, { mode: "call play" });
+
+    // Create an autoplay audio element in a subdocument.
+    await ContentTask.spawn(browser, null,
+      async () => {
+        let iframe = content.document.createElement("iframe");
+        let iframeLoaded = new Promise((resolve, reject) => {
+          iframe.addEventListener("load", e => resolve(), {once: true});
+        });
+        iframe.src = "file_video_autoplay.html";
+        content.document.body.appendChild(iframe);
+        await iframeLoaded;
+      });
+
+    info("Awaiting popupshown");
+    await popupshown;
+    ok(promptShowing(), "Should now be showing permission prompt");
+
+    // Check that the video didn't start playing.
+    await checkAllVideosNotPlayed(browser);
+
+    let popuphidden = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+
+    // Make one video inaudible, and then start to play.
+    await unblockAndPlayVideo(browser, {index: 0, unblockMode: "muted"});
+
+    // Test that the second video shouldn't have been unblocked when the first was.
+    await ContentTask.spawn(browser, null,
+      async () => {
+        let video = content.document.querySelectorAll("video")[1];
+        ok(video.paused && !video.didPlay, "Second video should not have played yet");
+        ok(video.playPromiseRejected, "Second video should have had its play promise rejected");
+
+        // Check the video in the subdocument had its promise rejected too.
+        let iframe = content.document.querySelector("iframe");
+        video = iframe.contentDocument.querySelector("video");
+        ok(video.paused, "Subdoc video should not have played");
+        is(video.played.length, 0, "Should have empty played ranges");
+      });
+
+    ok(!promptShowing(), "We should no longer be showing permission prompt");
+
+    // Reset permission.
+    SitePermissions.remove(browser.currentURI, "autoplay-media");
+    info("- Finished test prompt hides upon inaudible play in multi doc -");
+  });
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/file_video_autoplay.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+    <meta content="utf-8" http-equiv="encoding">
+  </head>
+  <body>
+    <video src="gizmo.mp4" autoplay />
+  </body>
+</html>
\ No newline at end of file