Bug 1463919 - Tests for prompting for permission to autoplay. r?jya,r?mconley draft
authorChris Pearce <cpearce@mozilla.com>
Mon, 25 Jun 2018 15:35:33 +1200
changeset 811178 f463b2628eec8d6fa08920851c2918cb09389a9f
parent 811177 62c94ba5b54b91f7689e100bf9eb9460b10684c9
child 811179 ec210847b6fd605c560a1bd1f2fe8beef76258ef
push id114217
push userbmo:cpearce@mozilla.com
push dateWed, 27 Jun 2018 04:21:06 +0000
reviewersjya, mconley
bugs1463919
milestone62.0a1
Bug 1463919 - Tests for prompting for permission to autoplay. r?jya,r?mconley Test that video that autoplays via a play() call or via autoplay attribute plays or is blocked or prompts with a doorhanger for approval and plays when "allow" clicked and doesn't when "block" clicked. MozReview-Commit-ID: CpftV6RQbtU
dom/html/HTMLMediaElement.cpp
toolkit/content/tests/browser/browser.ini
toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
toolkit/content/tests/browser/file_empty.html
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4068,16 +4068,19 @@ HTMLMediaElement::Play(ErrorResult& aRv)
   }
 
   // Otherwise, not allowed to play. We may still be allowed to play if we
   // ask for and are granted permission by the user.
 
   if (!Preferences::GetBool("media.autoplay.ask-permission", false)) {
     LOG(LogLevel::Debug, ("%p play not allowed and prompting disabled.", this));
     promise->MaybeReject(NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR);
+    if (Preferences::GetBool("media.autoplay.block-event.enabled", false)) {
+      DispatchAsyncEvent(NS_LITERAL_STRING("blocked"));
+    }
     return promise.forget();
   }
 
   // Prompt the user for permission to play.
   mPendingPlayPromises.AppendElement(promise);
   EnsureAutoplayRequested(handlingUserInput);
   return promise.forget();
 }
@@ -7901,16 +7904,21 @@ HTMLMediaElement::AsyncRejectPendingPlay
     mPaused = true;
     DispatchAsyncEvent(NS_LITERAL_STRING("pause"));
   }
 
   if (mShuttingDown) {
     return;
   }
 
+  if (aError == NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR &&
+      Preferences::GetBool("media.autoplay.block-event.enabled", false)) {
+    DispatchAsyncEvent(NS_LITERAL_STRING("blocked"));
+  }
+
   nsCOMPtr<nsIRunnable> event = new nsResolveOrRejectPendingPlayPromisesRunner(
     this, TakePendingPlayPromises(), aError);
 
   mMainThreadEventTarget->Dispatch(event.forget());
 }
 
 void
 HTMLMediaElement::GetEMEInfo(nsString& aEMEInfo)
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -37,16 +37,20 @@ support-files =
   file_autoplay_two_layers_frame1.html
   file_autoplay_two_layers_frame2.html
   file_video.html
   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
+  gizmo.mp4
 [browser_autoplay_policy_user_gestures.js]
 support-files =
   gizmo.mp4
   file_video.html
 [browser_autoscroll_disabled.js]
 [browser_block_autoplay_media.js]
 tags = audiochannel
 [browser_block_autoplay_media_pausedAfterPlay.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
@@ -0,0 +1,196 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+ChromeUtils.import("resource:///modules/SitePermissions.jsm", this);
+
+const VIDEO_PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_empty.html";
+
+add_task(() => {
+  return SpecialPowers.pushPrefEnv({"set": [
+    ["media.autoplay.enabled", false],
+    ["media.autoplay.enabled.user-gestures-needed", true],
+    ["media.autoplay.ask-permission", true],
+    ["media.autoplay.block-event.enabled", true],
+  ]});
+});
+
+// Content script that creates an autoplay video.
+async function loadAutoplayVideo(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;
+      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");
+    video.addEventListener("loadedmetadata", (e) => {
+      video.play().then(
+        () => {
+          info("video play() resolved");
+        },
+        () => {
+          info("video play() rejected");
+        });
+    }, {once: true});
+  } else {
+    ok(false, "Invalid 'mode' arg");
+  }
+  video.src = "gizmo.mp4";
+  content.document.body.appendChild(video);
+}
+
+// Content script that checks whether the video created by loadAutoplayVideo()
+// started playing.
+async function checkVideoDidPlay(args) {
+  let video = content.document.getElementById("v1");
+  await video.didPlayPromise;
+  is(video.didPlay, args.shouldPlay,
+      args.test + " mode=" + args.mode + " button=" + args.button +
+      " video should " + (!args.shouldPlay ? "not " : "") + "be able to autoplay");
+  video.src = "";
+  content.document.body.remove(video);
+}
+
+async function testAutoplayExistingPermission(args) {
+  info("- Starting '" + args.name + "' -");
+  info("- open new tab -");
+
+  let tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser,
+                                                        "about:blank");
+  tab.linkedBrowser.loadURI(VIDEO_PAGE);
+  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+  let promptShowing = () =>
+    PopupNotifications.getNotification("autoplay-media", tab.linkedBrowser);
+
+  SitePermissions.set(gBrowser.currentURI, "autoplay-media", args.permission);
+  ok(!promptShowing(), "Should not be showing permission prompt yet");
+
+  await ContentTask.spawn(tab.linkedBrowser, args, loadAutoplayVideo);
+  await ContentTask.spawn(tab.linkedBrowser, args, checkVideoDidPlay);
+
+  // Reset permission.
+  SitePermissions.remove(gBrowser.currentURI, "autoplay-media");
+
+  info("- remove tab -");
+  BrowserTestUtils.removeTab(tab);
+  info("- Finished '" + args.name + "' -");
+}
+
+// Test the simple ALLOW/BLOCK cases; when permission is already set to ALLOW,
+// we shoud be able to autoplay via calling play(), or via the autoplay attribute,
+// and when it's set to BLOCK, we should not.
+add_task(async () => {
+  await testAutoplayExistingPermission({
+    name: "Prexisting allow permission autoplay attribute",
+    permission: SitePermissions.ALLOW,
+    shouldPlay: true,
+    mode: "autoplay attribute",
+  });
+  await testAutoplayExistingPermission({
+    name: "Prexisting allow permission call play",
+    permission: SitePermissions.ALLOW,
+    shouldPlay: true,
+    mode: "call play",
+  });
+  await testAutoplayExistingPermission({
+    name: "Prexisting block permission autoplay attribute",
+    permission: SitePermissions.BLOCK,
+    shouldPlay: false,
+    mode: "autoplay attribute",
+  });
+  await testAutoplayExistingPermission({
+    name: "Prexisting block permission call play",
+    permission: SitePermissions.BLOCK,
+    shouldPlay: false,
+    mode: "call play",
+  });
+});
+
+async function testAutoplayUnknownPermission(args) {
+  info("- Starting '" + args.name + "' -");
+  info("- open new tab -");
+
+  let tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser,
+                                                        "about:blank");
+  tab.linkedBrowser.loadURI(VIDEO_PAGE);
+  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+  let promptShowing = () =>
+    PopupNotifications.getNotification("autoplay-media", tab.linkedBrowser);
+
+  // Set this site to ask permission to autoplay.
+  SitePermissions.set(gBrowser.currentURI, "autoplay-media", SitePermissions.UNKNOWN);
+  ok(!promptShowing(), "Should not be showing permission prompt");
+
+  let popupshown = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+  await ContentTask.spawn(tab.linkedBrowser, args, loadAutoplayVideo);
+
+  info("Awaiting popupshown");
+  await popupshown;
+  ok(promptShowing(), "Should now be showing permission prompt");
+
+  // Click the appropriate doorhanger button.
+  if (args.button == "allow") {
+    info("Clicking allow button");
+    PopupNotifications.panel.firstElementChild.button.click();
+  } else if (args.button == "block") {
+    info("Clicking block button");
+    PopupNotifications.panel.firstChild.secondaryButton.click();
+  } else {
+    ok(false, "Invalid button field");
+  }
+  // Check that the video started playing.
+  await ContentTask.spawn(tab.linkedBrowser, args, checkVideoDidPlay);
+
+  // Reset permission.
+  SitePermissions.remove(gBrowser.currentURI, "autoplay-media");
+
+  info("- remove tab -");
+  BrowserTestUtils.removeTab(tab);
+  info("- Finished '" + args.name + "' -");
+}
+
+// Test the permission UNKNOWN case; we should prompt for permission, and
+// test pressing approve/block in both the autoplay attribute and call
+// play case.
+add_task(async () => {
+  await testAutoplayUnknownPermission({
+    name: "Unknown permission click allow autoplay attribute",
+    button: "allow",
+    shouldPlay: true,
+    mode: "autoplay attribute",
+  });
+  await testAutoplayUnknownPermission({
+    name: "Unknown permission click allow call play",
+    button: "allow",
+    shouldPlay: true,
+    mode: "call play",
+  });
+  await testAutoplayUnknownPermission({
+    name: "Unknown permission click block autoplay attribute",
+    button: "block",
+    shouldPlay: false,
+    mode: "autoplay attribute",
+  });
+  await testAutoplayUnknownPermission({
+    name: "Unknown permission click block call play",
+    button: "block",
+    shouldPlay: false,
+    mode: "call play",
+  });
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/file_empty.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Page left intentionally blank...</title>
+  </head>
+  <body>
+  </body>
+</html>