summaryrefslogtreecommitdiffstats
path: root/dom/media/autoplay/test/browser/browser_autoplay_policy_user_gestures.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/autoplay/test/browser/browser_autoplay_policy_user_gestures.js')
-rw-r--r--dom/media/autoplay/test/browser/browser_autoplay_policy_user_gestures.js277
1 files changed, 277 insertions, 0 deletions
diff --git a/dom/media/autoplay/test/browser/browser_autoplay_policy_user_gestures.js b/dom/media/autoplay/test/browser/browser_autoplay_policy_user_gestures.js
new file mode 100644
index 0000000000..2b9d8c1158
--- /dev/null
+++ b/dom/media/autoplay/test/browser/browser_autoplay_policy_user_gestures.js
@@ -0,0 +1,277 @@
+/* eslint-disable mozilla/no-arbitrary-setTimeout */
+
+const VIDEO_PAGE = GetTestWebBasedURL("file_video.html");
+
+const UserGestures = {
+ MOUSE_CLICK: "mouse-click",
+ MOUSE_MOVE: "mouse-move",
+ KEYBOARD_PRESS: "keyboard-press",
+};
+
+const UserGestureTests = [
+ { type: UserGestures.MOUSE_CLICK, isActivationGesture: true },
+ { type: UserGestures.MOUSE_MOVE, isActivationGesture: false },
+ // test different keycode here. printable key, non-printable key and other
+ // special keys.
+ {
+ type: UserGestures.KEYBOARD_PRESS,
+ isActivationGesture: true,
+ keyCode: "a",
+ },
+ {
+ type: UserGestures.KEYBOARD_PRESS,
+ isActivationGesture: false,
+ keyCode: "VK_ESCAPE",
+ },
+ {
+ type: UserGestures.KEYBOARD_PRESS,
+ isActivationGesture: true,
+ keyCode: "VK_RETURN",
+ },
+ {
+ type: UserGestures.KEYBOARD_PRESS,
+ isActivationGesture: true,
+ keyCode: "VK_SPACE",
+ },
+];
+
+/**
+ * This test is used to ensure we would stop blocking autoplay after document
+ * has been activated by user gestures. We would treat mouse clicking, key board
+ * pressing (printable keys or carriage return) as valid user gesture input.
+ */
+add_task(async function startTestUserGestureInput() {
+ info("- setup test preference -");
+ await setupTestPreferences();
+
+ info("- test play when page doesn't be activated -");
+ await testPlayWithoutUserGesture();
+
+ info("- test play after page got user gesture -");
+ for (let idx = 0; idx < UserGestureTests.length; idx++) {
+ info("- test play after page got user gesture -");
+ await testPlayWithUserGesture(UserGestureTests[idx]);
+
+ info("- test web audio with user gesture -");
+ await testWebAudioWithUserGesture(UserGestureTests[idx]);
+ }
+});
+
+/**
+ * testing helper functions
+ */
+function setupTestPreferences() {
+ return SpecialPowers.pushPrefEnv({
+ set: [
+ ["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
+ ["media.autoplay.blocking_policy", 0],
+ ["media.autoplay.block-event.enabled", true],
+ ["media.autoplay.block-webaudio", true],
+ ],
+ });
+}
+
+function simulateUserGesture(gesture, targetBrowser) {
+ info(`- simulate ${gesture.type} event -`);
+ switch (gesture.type) {
+ case UserGestures.MOUSE_CLICK:
+ return BrowserTestUtils.synthesizeMouseAtCenter(
+ "body",
+ { button: 0 },
+ targetBrowser
+ );
+ case UserGestures.MOUSE_MOVE:
+ return BrowserTestUtils.synthesizeMouseAtCenter(
+ "body",
+ { type: "mousemove" },
+ targetBrowser
+ );
+ case UserGestures.KEYBOARD_PRESS:
+ info(`- keycode=${gesture.keyCode} -`);
+ return BrowserTestUtils.synthesizeKey(gesture.keyCode, {}, targetBrowser);
+ default:
+ ok(false, "undefined user gesture");
+ return false;
+ }
+}
+
+async function testPlayWithoutUserGesture() {
+ info("- open new tab -");
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ window.gBrowser,
+ "about:blank"
+ );
+ BrowserTestUtils.loadURIString(tab.linkedBrowser, VIDEO_PAGE);
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ async function checkAutoplayKeyword() {
+ info("- create an new autoplay video -");
+ let video = content.document.createElement("video");
+ video.src = "gizmo.mp4";
+ video.autoplay = true;
+ let canplayPromise = new Promise(function (resolve) {
+ video.addEventListener(
+ "canplaythrough",
+ function () {
+ resolve();
+ },
+ { once: true }
+ );
+ });
+ content.document.body.appendChild(video);
+
+ info("- can't autoplay without user activation -");
+ await canplayPromise;
+ ok(video.paused, "video can't start without user input.");
+ }
+ await SpecialPowers.spawn(tab.linkedBrowser, [], checkAutoplayKeyword);
+
+ async function playVideo() {
+ let video = content.document.getElementById("v");
+ info("- call play() without user activation -");
+ await video.play().catch(function () {
+ ok(video.paused, "video can't start play without user input.");
+ });
+ }
+ await SpecialPowers.spawn(tab.linkedBrowser, [], playVideo);
+
+ info("- remove tab -");
+ BrowserTestUtils.removeTab(tab);
+}
+
+async function testPlayWithUserGesture(gesture) {
+ info("- open new tab -");
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ window.gBrowser,
+ "about:blank"
+ );
+ BrowserTestUtils.loadURIString(tab.linkedBrowser, VIDEO_PAGE);
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ info("- simulate user gesture -");
+ await simulateUserGesture(gesture, tab.linkedBrowser);
+
+ info("- call play() -");
+ async function playVideo(gesture) {
+ let video = content.document.getElementById("v");
+ try {
+ await video.play();
+ ok(gesture.isActivationGesture, "user gesture can activate the page");
+ ok(!video.paused, "video starts playing.");
+ } catch (e) {
+ ok(
+ !gesture.isActivationGesture,
+ "user gesture can not activate the page"
+ );
+ ok(video.paused, "video can not start playing.");
+ }
+ }
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [gesture], playVideo);
+
+ info("- remove tab -");
+ BrowserTestUtils.removeTab(tab);
+}
+
+function createAudioContext() {
+ content.ac = new content.AudioContext();
+ let ac = content.ac;
+ ac.resumePromises = [];
+ ac.stateChangePromise = new Promise(resolve => {
+ ac.addEventListener(
+ "statechange",
+ function () {
+ resolve();
+ },
+ { once: true }
+ );
+ });
+ ac.notAllowedToStart = new Promise(resolve => {
+ ac.addEventListener(
+ "blocked",
+ function () {
+ resolve();
+ },
+ { once: true }
+ );
+ });
+}
+
+function resumeWithoutExpectedSuccess() {
+ let ac = content.ac;
+ let promise = ac.resume();
+ ac.resumePromises.push(promise);
+ return new Promise((resolve, reject) => {
+ content.setTimeout(() => {
+ if (ac.state == "suspended") {
+ ok(true, "audio context is still suspended");
+ resolve();
+ } else {
+ reject("audio context should not be allowed to start");
+ }
+ }, 2000);
+ });
+}
+
+function resumeWithExpectedSuccess() {
+ let ac = content.ac;
+ ac.resumePromises.push(ac.resume());
+ return Promise.all(ac.resumePromises).then(() => {
+ ok(ac.state == "running", "audio context starts running");
+ });
+}
+
+async function testWebAudioWithUserGesture(gesture) {
+ info("- open new tab -");
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ window.gBrowser,
+ "about:blank"
+ );
+ info("- create audio context -");
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.ac = new content.AudioContext();
+ let ac = content.ac;
+ ac.resumePromises = [];
+ return new Promise(resolve => {
+ ac.addEventListener(
+ "blocked",
+ function () {
+ Assert.equal(
+ ac.state,
+ "suspended",
+ `AudioContext is not started yet.`
+ );
+ resolve();
+ },
+ { once: true }
+ );
+ });
+ });
+
+ info("- calling resume() -");
+ try {
+ await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ resumeWithoutExpectedSuccess
+ );
+ } catch (error) {
+ ok(false, error.toString());
+ }
+
+ info("- simulate user gesture -");
+ await simulateUserGesture(gesture, tab.linkedBrowser);
+
+ info("- calling resume() again");
+ try {
+ let resumeFunc = gesture.isActivationGesture
+ ? resumeWithExpectedSuccess
+ : resumeWithoutExpectedSuccess;
+ await SpecialPowers.spawn(tab.linkedBrowser, [], resumeFunc);
+ } catch (error) {
+ ok(false, error.toString());
+ }
+
+ info("- remove tab -");
+ await BrowserTestUtils.removeTab(tab);
+}