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
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>