Bug 1439437 - Tests for autoplay gesture activation in new windows/frames. r=kamidphish draft
authorChris Pearce <cpearce@mozilla.com>
Mon, 19 Feb 2018 16:31:36 +1300
changeset 758231 38d77ce42ec5f4edb0119ba2ccf03f53cd8cdb00
parent 757574 861067332bac96a44bbf41ef366f58a30476057b
child 758232 6f117a036fc5ce10413660fb9fd5d418d74e159d
child 758240 153a68f27ec5c2b17c3c5a9e31d54b98ccc1a1ea
push id99992
push userbmo:cpearce@mozilla.com
push dateThu, 22 Feb 2018 02:05:05 +0000
reviewerskamidphish
bugs1439437
milestone60.0a1
Bug 1439437 - Tests for autoplay gesture activation in new windows/frames. r=kamidphish Autoplay of audible media should be blocked in documents until they have a user gesture in them, or in a same-origin parent document. This patch adds tests for those cases. MozReview-Commit-ID: B4FQhPOukId
dom/media/test/AutoplayTestUtils.js
dom/media/test/file_autoplay_policy_activation_frame.html
dom/media/test/file_autoplay_policy_activation_window.html
dom/media/test/mochitest.ini
dom/media/test/test_autoplay_policy_activation.html
new file mode 100644
--- /dev/null
+++ b/dom/media/test/AutoplayTestUtils.js
@@ -0,0 +1,39 @@
+function playAndPostResult(test_case, parent_window) {
+  log("runTest " + test_case.name);
+
+  let element = document.createElement("video");
+  element.preload = "auto";
+  element.muted = test_case.muted;
+  element.src = "short.mp4";
+  element.id = "video";
+  document.body.appendChild(element);
+
+  element.play().then(
+      () => {
+        parent_window.postMessage({played: true}, "*");
+      },
+      () => {
+        parent_window.postMessage({played: false}, "*");
+      }
+    );
+}
+
+function nextEvent(eventTarget, eventName) {
+  return new Promise(function(resolve, reject) {
+    let f = function(event) {
+      eventTarget.removeEventListener(eventName, f, false);
+      resolve(event);
+    };
+    eventTarget.addEventListener(eventName, f, false);
+  });
+}
+
+function nextWindowMessage() {
+  return nextEvent(window, "message");
+}
+
+function log(msg) {
+  var log_pane = document.body;
+  log_pane.appendChild(document.createTextNode(msg));
+  log_pane.appendChild(document.createElement("br"));
+}
new file mode 100644
--- /dev/null
+++ b/dom/media/test/file_autoplay_policy_activation_frame.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Autoplay policy frame</title>
+    <script type="text/javascript" src="AutoplayTestUtils.js"></script>
+    <style>
+      video {
+        width: 50%;
+        height: 50%;
+      }
+    </style>
+  </head>
+  <body>
+    <script>
+      nextWindowMessage().then(
+        (event) => {
+          playAndPostResult(event.data, event.source);
+        });
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/test/file_autoplay_policy_activation_window.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Autoplay policy window</title>
+    <style>
+      video {
+        width: 50%;
+        height: 50%;
+      }
+    </style>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="manifest.js"></script>
+    <script type="text/javascript" src="AutoplayTestUtils.js"></script>
+  </head>
+  <body>
+    <pre id="test">
+      <script>
+
+        function testAutoplayInWindow(test_case, parent_window) {
+          log("testAutoplayInWindow: " + test_case.name);
+          playAndPostResult(test_case, parent_window);
+        }
+
+        async function testAutoplayInChildFrame(test_case, parent_window) {
+          log("testAutoplayInChildFrame: " + test_case.name);
+          // Create a child iframe...
+          var frame = document.createElement("iframe");
+          var origin = test_case.same_origin_child
+            ? "http://mochi.test:8888" : "http://example.org";
+          frame.src = origin + "/tests/dom/media/test/file_autoplay_policy_activation_frame.html";
+          // Wait for it to load...
+          document.body.appendChild(frame);
+          await once(frame, "load");
+          // Click the iframe to activate if appropriate.
+          if (test_case.activated_child) {
+            synthesizeMouseAtCenter(frame, {});
+          }
+          // Ask the child iframe to try to play video.
+          frame.contentWindow.postMessage(test_case, "*");
+          // Wait for the iframe to tell us whether it could play video.
+          let result = await nextWindowMessage();
+          // Report whether the iframe could play to the parent.
+          parent_window.postMessage(result.data, "*");
+        }
+
+        nextWindowMessage().then(
+          (event) => {
+            let test_case = event.data;
+            // Click the window to activate if appropriate.
+            if (test_case.activated_parent) {
+              synthesizeMouseAtCenter(document.body, {});
+            }
+            let parent_window = event.source;
+            if (test_case.same_origin_child === undefined) {
+              testAutoplayInWindow(test_case, parent_window);
+            } else {
+              testAutoplayInChildFrame(test_case, parent_window);
+            }
+          });
+
+      </script>
+    </pre>
+  </body>
+</html>
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -26,16 +26,17 @@ subsuite = media
 skip-if = android_version == '18' # Run on real devices via autophone
 support-files =
   16bit_wave_extrametadata.wav
   16bit_wave_extrametadata.wav^headers^
   320x240.ogv
   320x240.ogv^headers^
   448636.ogv
   448636.ogv^headers^
+  AutoplayTestUtils.js
   A4.ogv
   A4.ogv^headers^
   VID_0001.ogg
   VID_0001.ogg^headers^
   allowed.sjs
   ambisonics.mp4
   ambisonics.mp4^headers^
   audio-gaps.ogg
@@ -432,16 +433,18 @@ support-files =
   detodos-short.opus
   detodos-short.opus^headers^
   dirac.ogg
   dirac.ogg^headers^
   dynamic_redirect.sjs
   dynamic_resource.sjs
   eme.js
   file_access_controls.html
+  file_autoplay_policy_activation_window.html
+  file_autoplay_policy_activation_frame.html
   flac-s24.flac
   flac-s24.flac^headers^
   flac-noheader-s16.flac
   flac-noheader-s16.flac^headers^
   fragment_noplay.js
   fragment_play.js
   gizmo.mp4
   gizmo.mp4^headers^
@@ -679,16 +682,18 @@ skip-if = android_version == '15' # andr
 [test_audio2.html]
 [test_audioDocumentTitle.html]
 skip-if = true # bug 475110 - disabled since we don't play Wave files standalone
 [test_autoplay.html]
 [test_autoplay_contentEditable.html]
 skip-if = android_version == '15' || android_version == '17' || android_version == '22' # android(bug 1232305, bug 1232318, bug 1372457)
 [test_autoplay_policy.html]
 skip-if = android_version == '23' # bug 1424903
+[test_autoplay_policy_activation.html]
+skip-if = android_version == '23' # bug 1424903
 [test_buffered.html]
 skip-if = android_version == '15' || android_version == '22' # bug 1308388, android(bug 1232305)
 [test_bug448534.html]
 [test_bug463162.xhtml]
 [test_bug465498.html]
 skip-if = toolkit == 'android' # android(bug 1232305)
 [test_bug495145.html]
 skip-if = (os == 'mac' && os_version == '10.6') || (toolkit == 'android')  # bug 1311229, android(bug 1232305)
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_autoplay_policy_activation.html
@@ -0,0 +1,158 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Autoplay policy test</title>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="manifest.js"></script>
+    <script type="text/javascript" src="AutoplayTestUtils.js"></script>
+  </head>
+  <body>
+    <pre id="test">
+      <script>
+
+        // Tests that videos can only play audibly in windows/frames
+        // which have been activated by same-origin user gesture.
+
+        gTestPrefs.push(["media.autoplay.enabled", false],
+                        ["media.autoplay.enabled.user-gestures-needed", true]);
+
+        SpecialPowers.pushPrefEnv({'set': gTestPrefs}, () => {
+          runTest();
+        });
+
+        let test_cases = [
+          {
+            name: "inaudible playback in unactivated same-origin iframe in activated parent allowed",
+            muted: true,
+            same_origin_child: true,
+            activated_child: false,
+            activated_parent: true,
+            should_play: true,
+          },
+
+          {
+            name: "inaudible playback in unactivated same-origin iframe in unactivated parent allowed",
+            muted: true,
+            same_origin_child: true,
+            activated_child: false,
+            activated_parent: false,
+            should_play: true,
+          },
+
+          {
+            name: "audible playback in unactivated same-origin iframe in activated parent allowed",
+            muted: false,
+            same_origin_child: true,
+            activated_child: false,
+            activated_parent: true,
+            should_play: true,
+          },
+
+          {
+            name: "audible playback in unactivated same-origin iframe in unactivated parent blocked",
+            muted: false,
+            same_origin_child: true,
+            activated_child: false,
+            activated_parent: false,
+            should_play: false,
+          },
+
+          {
+            name: "inaudible playback in unactivated cross-origin iframe in activated parent allowed",
+            muted: true,
+            same_origin_child: false,
+            activated_child: false,
+            activated_parent: true,
+            should_play: true,
+          },
+
+          {
+            name: "inaudible playback in unactivated cross-origin iframe in unactivated parent allowed",
+            muted: true,
+            same_origin_child: false,
+            activated_child: false,
+            activated_parent: false,
+            should_play: true,
+          },
+
+          // TODO: This case fails, Firefox's behaviour needs to be fixed.
+          // {
+          //   name: "audible playback in unactivated cross-origin iframe in activated parent blocked",
+          //   muted: false,
+          //   same_origin_child: false,
+          //   activated_child: false,
+          //   activated_parent: true,
+          //   should_play: false,
+          // },
+
+          {
+            name: "audible playback in unactivated cross-origin iframe in unactivated parent blocked",
+            muted: false,
+            same_origin_child: false,
+            activated_child: false,
+            activated_parent: false,
+            should_play: false,
+          },
+
+          {
+            name: "audible playback in activated cross-origin iframe allowed",
+            muted: false,
+            same_origin_child: false,
+            activated_child: true,
+            activated_parent: false,
+            should_play: true,
+          },
+
+          {
+            name: "audible playback in activated document allowed",
+            muted: false,
+            activated_parent: true,
+            should_play: true,
+          },
+
+          {
+            name: "audible playback in unactivated document blocked",
+            muted: false,
+            activated_parent: false,
+            should_play: false,
+          },
+
+          {
+            name: "inaudible playback in activated document allowed",
+            muted: true,
+            activated_parent: true,
+            should_play: true,
+          },
+
+          {
+            name: "inaudible playback in unactivated document allowed",
+            muted: true,
+            activated_parent: false,
+            should_play: true,
+          },
+
+        ];
+
+        let child_url = "file_autoplay_policy_activation_window.html";
+
+        async function runTest() {
+          for (test_case of test_cases) {
+            // Run each test in a new window, to ensure its user gesture
+            // activation state isn't tainted by preceeding tests.
+            let child = window.open(child_url, "", "width=500,height=500");
+            await once(child, "load");
+            child.postMessage(test_case, window.origin);
+            let result = await nextWindowMessage();
+            SimpleTest.is(result.data.played, test_case.should_play, test_case.name);
+            child.close();
+          }
+          SimpleTest.finish();
+        }
+
+        SimpleTest.waitForExplicitFinish();
+
+      </script>
+    </pre>
+  </body>
+</html>