Bug 1491475 - part3 : add test to ensure doorhanger would not dismiss when inaudible media starts. r=cpearce
authoralwu <alwu@mozilla.com>
Mon, 19 Nov 2018 17:55:11 +0000
changeset 506723 345d44957fee
parent 506722 3b5ff99abb5e
child 506724 bd685d374d7c
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1491475
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1491475 - part3 : add test to ensure doorhanger would not dismiss when inaudible media starts. r=cpearce Differential Revision: https://phabricator.services.mozilla.com/D12178
toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
toolkit/content/tests/browser/browser_autoplay_policy_web_audio.js
toolkit/content/tests/browser/head.js
--- a/toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
+++ b/toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
@@ -8,16 +8,17 @@ ChromeUtils.import("resource:///modules/
 
 const VIDEO_PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_empty.html";
 
 add_task(() => {
   return SpecialPowers.pushPrefEnv({"set": [
     ["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.PROMPT],
     ["media.autoplay.enabled.user-gestures-needed", true],
     ["media.autoplay.ask-permission", true],
+    ["media.autoplay.block-webaudio", true],
     ["media.autoplay.block-event.enabled", true],
   ]});
 });
 
 async function testAutoplayExistingPermission(args) {
   info("- Starting '" + args.name + "' -");
   await BrowserTestUtils.withNewTab({
     gBrowser,
@@ -199,19 +200,28 @@ add_task(async () => {
     name: "Unknown permission click block call play and no check check-box",
     button: "block",
     shouldPlay: false,
     mode: "call play",
     checkbox: false,
   });
 });
 
-// Test that if playback starts while the permission prompt is shown,
-// that the prompt is hidden.
-add_task(async () => {
+async function testIgnorePrompt({name, type, isAudible}) {
+  info(`- Starting test '${name}' -`);
+  if (type == "MediaElement") {
+    await testIgnorePromptAndPlayMediaElement(isAudible);
+  } else if (type == "WebAudio") {
+    await testIgnorePromptAndPlayWebAudio(isAudible);
+  } else {
+    ok(false, `undefined test type.`);
+  }
+}
+
+async function testIgnorePromptAndPlayMediaElement(isAudible) {
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: VIDEO_PAGE,
   }, async (browser) => {
     info("- Started test prompt hides upon play -");
     let promptShowing = () =>
       PopupNotifications.getNotification("autoplay-media", browser);
 
@@ -229,36 +239,130 @@ add_task(async () => {
     // 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");
       });
 
     let popuphidden = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
-
-    await ContentTask.spawn(browser, null,
-      async () => {
+    await ContentTask.spawn(browser, isAudible,
+      async (isAudible) => {
         // Gesture activate the document, i.e. simulate a click in the document,
         // to unblock autoplay,
         content.document.notifyUserGestureActivation();
         let video = content.document.getElementById("v1");
+        video.muted = !isAudible;
         // 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");
       });
 
-    info("Awaiting popuphidden");
-    await popuphidden;
-    ok(!promptShowing(), "Permission prompt should have hidden when media started playing");
+    if (isAudible) {
+      info("Awaiting popuphidden");
+      await popuphidden;
+      ok(!promptShowing(), "Permission prompt should have hidden when media started playing");
+    } else {
+      ok(promptShowing(), `doorhanger would only be dismissed when audible media starts`);
+    }
 
     // Reset permission.
     SitePermissions.remove(browser.currentURI, "autoplay-media");
     info("- Finished test prompt hides upon play -");
   });
+}
+
+async function testIgnorePromptAndPlayWebAudio(isAudible) {
+  function createAudioContext() {
+    content.ac = new content.AudioContext();
+    content.ac.notAllowedToStart = new Promise(resolve => {
+      content.ac.addEventListener("blocked", function() {
+        resolve();
+      }, {once: true});
+    });
+  }
+
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: VIDEO_PAGE,
+  }, async (browser) => {
+    info(`- set the 'autoplay-media' permission to UNKNOWN -`);
+    const promptShowing = () =>
+      PopupNotifications.getNotification("autoplay-media", browser);
+    SitePermissions.set(browser.currentURI, "autoplay-media", SitePermissions.UNKNOWN);
+    ok(!promptShowing(), "Should not be showing permission prompt");
+
+    info(`- create AudioContext which should not start until user approves -`);
+    loadFrameScript(browser, createAudioContext);
+    await ContentTask.spawn(browser, null, async () => {
+      await content.ac.notAllowedToStart;
+      ok(content.ac.state === "suspended", `AudioContext is not started yet.`);
+    });
+
+    info(`- try to start AudioContext and show doorhanger to ask for user's approval -`);
+    const popupShow = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    await ContentTask.spawn(browser, null, () => {
+      content.ac.resume();
+    });
+    await popupShow;
+    ok(promptShowing(), `should now be showing permission prompt`);
+
+    info(`- simulate user activate the page -`);
+    await ContentTask.spawn(browser, null, () => {
+      content.document.notifyUserGestureActivation();
+    });
+
+    if (isAudible) {
+      info(`- ignore doorhanger, connect audible node and start node -`);
+      const popupHide = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+      await ContentTask.spawn(browser, null, () => {
+        const ac = content.ac;
+        let node = ac.createOscillator();
+        node.connect(ac.destination);
+        node.start();
+      });
+      await popupHide;
+      ok(true, `doorhanger should dismiss after AudioContext starts audible`);
+    } else {
+      info(`- ignore doorhanger and resume AudioContext without connecting audible node -`);
+      await ContentTask.spawn(browser, null, async () => {
+        await content.ac.resume();
+        ok(true, `successfully resume AudioContext.`);
+      });
+      ok(promptShowing(),
+         `doorhanger would only be dismissed when audible media starts`);
+    }
+
+    SitePermissions.remove(browser.currentURI, "autoplay-media");
+  });
+}
+
+// Test that the prompt would dismiss when audible media starts, but not dismiss
+// when inaudible media starts.
+add_task(async () => {
+  await testIgnorePrompt({
+    name: "ignore doorhanger and play audible media element",
+    type: "MediaElement",
+    isAudible: true,
+  });
+  await testIgnorePrompt({
+    name: "ignore doorhanger and play inaudible media element",
+    type: "MediaElement",
+    isAudible: false,
+  });
+  await testIgnorePrompt({
+    name: "ignore doorhanger and play audible web audio",
+    type: "WebAudio",
+    isAudible: true,
+  });
+  await testIgnorePrompt({
+    name: "ignore doorhanger and play inaudible web audio",
+    type: "WebAudio",
+    isAudible: false,
+  });
 });
--- a/toolkit/content/tests/browser/browser_autoplay_policy_web_audio.js
+++ b/toolkit/content/tests/browser/browser_autoplay_policy_web_audio.js
@@ -17,23 +17,16 @@ function setup_test_preference() {
     ["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.PROMPT],
     ["media.autoplay.enabled.user-gestures-needed", true],
     ["media.autoplay.ask-permission", true],
     ["media.autoplay.block-webaudio", true],
     ["media.autoplay.block-event.enabled", true],
   ]});
 }
 
-function loadFrameScript(browser, fn) {
-  // We want the same audio context to be used across different content
-  // tasks, so it needs to be loaded by a frame script.
-  const mm = browser.messageManager;
-  mm.loadFrameScript("data:,(" + fn.toString() + ")();", false);
-}
-
 function createAudioContext() {
   content.ac = new content.AudioContext();
   const ac = content.ac;
 
   ac.allowedToStart = new Promise(resolve => {
     ac.addEventListener("statechange", function() {
       if (ac.state === "running") {
         resolve();
--- a/toolkit/content/tests/browser/head.js
+++ b/toolkit/content/tests/browser/head.js
@@ -293,8 +293,15 @@ function checkVideoDidPlay(browser, args
     let video = content.document.getElementById("v1");
     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);
   });
 }
+
+// The JS content loaded by frame script can be used across different content
+// tasks.
+function loadFrameScript(browser, fn) {
+  const mm = browser.messageManager;
+  mm.loadFrameScript("data:,(" + fn.toString() + ")();", false);
+}