diff options
Diffstat (limited to 'dom/media/mediacontrol/tests/browser/browser_media_control_non_eligible_media.js')
-rw-r--r-- | dom/media/mediacontrol/tests/browser/browser_media_control_non_eligible_media.js | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/dom/media/mediacontrol/tests/browser/browser_media_control_non_eligible_media.js b/dom/media/mediacontrol/tests/browser/browser_media_control_non_eligible_media.js new file mode 100644 index 0000000000..ab18eab634 --- /dev/null +++ b/dom/media/mediacontrol/tests/browser/browser_media_control_non_eligible_media.js @@ -0,0 +1,204 @@ +const PAGE_NON_ELIGIBLE_MEDIA = + "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_non_eligible_media.html"; + +// Import this in order to use `triggerPictureInPicture()`. +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/toolkit/components/pictureinpicture/tests/head.js", + this +); + +// Bug 1673509 - This test requests a lot of fullscreen for media elements, +// which sometime Gecko would take longer time to fulfill. +requestLongerTimeout(2); + +// This array contains the elements' id in `file_non_eligible_media.html`. +const gNonEligibleElementIds = [ + "muted", + "volume-0", + "silent-audio-track", + "no-audio-track", + "short-duration", + "inaudible-captured-media", +]; + +/** + * This test is used to test couples of things about what kinds of media is + * eligible for being controlled by media control keys. + * (1) If media is inaudible all the time, then we would not control it. + * (2) If media starts inaudibly, we would not try to control it. But once it + * becomes audible later, we would keep controlling it until it's destroyed. + * (3) If media's duration is too short (<3s), then we would not control it. + */ +add_task(async function setupTestingPref() { + await SpecialPowers.pushPrefEnv({ + set: [["media.mediacontrol.testingevents.enabled", true]], + }); +}); + +add_task( + async function testNonAudibleMediaCantActivateControllerButAudibleMediaCan() { + for (const elementId of gNonEligibleElementIds) { + info(`open new tab with non eligible media elements`); + const tab = await createLoadedTabWrapper(PAGE_NON_ELIGIBLE_MEDIA, { + needCheck: couldElementBecomeEligible(elementId), + }); + + info(`although media is playing but it won't activate controller`); + await Promise.all([ + startNonEligibleMedia(tab, elementId), + checkIfMediaIsStillPlaying(tab, elementId), + ]); + ok(!tab.controller.isActive, "controller is still inactive"); + + if (couldElementBecomeEligible(elementId)) { + info(`make element ${elementId} audible would activate controller`); + await Promise.all([ + makeElementEligible(tab, elementId), + checkOrWaitUntilControllerBecomeActive(tab), + ]); + } + + info(`remove tab`); + await tab.close(); + } + } +); + +/** + * Normally those media are not able to being controlled, however, once they + * enter fullsceen or Picture-in-Picture mode, then they can be controlled. + */ +add_task(async function testNonEligibleMediaEnterFullscreen() { + info(`open new tab with non eligible media elements`); + const tab = await createLoadedTabWrapper(PAGE_NON_ELIGIBLE_MEDIA); + + for (const elementId of gNonEligibleElementIds) { + await startNonEligibleMedia(tab, elementId); + + info(`entering fullscreen should activate the media controller`); + await enterFullScreen(tab, elementId); + await checkOrWaitUntilControllerBecomeActive(tab); + ok(true, `fullscreen ${elementId} media is able to being controlled`); + + info(`leave fullscreen`); + await leaveFullScreen(tab); + } + info(`remove tab`); + await tab.close(); +}); + +add_task(async function testNonEligibleMediaEnterPIPMode() { + info(`open new tab with non eligible media elements`); + const tab = await createLoadedTabWrapper(PAGE_NON_ELIGIBLE_MEDIA); + + for (const elementId of gNonEligibleElementIds) { + await startNonEligibleMedia(tab, elementId); + + info(`media entering PIP mode should activate the media controller`); + const winPIP = await triggerPictureInPicture(tab.linkedBrowser, elementId); + await checkOrWaitUntilControllerBecomeActive(tab); + ok(true, `PIP ${elementId} media is able to being controlled`); + + info(`stop PIP mode`); + await BrowserTestUtils.closeWindow(winPIP); + } + info(`remove tab`); + await tab.close(); +}); + +/** + * The following are helper functions. + */ +function startNonEligibleMedia(tab, elementId) { + return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => { + const video = content.document.getElementById(Id); + if (!video) { + ok(false, `can't get the media element!`); + } + if (Id == "volume-0") { + video.volume = 0.0; + } + if (Id == "inaudible-captured-media") { + const context = new content.AudioContext(); + context.createMediaElementSource(video); + } + info(`start non eligible media ${Id}`); + return video.play(); + }); +} + +function checkIfMediaIsStillPlaying(tab, elementId) { + return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => { + const video = content.document.getElementById(Id); + if (!video) { + ok(false, `can't get the media element!`); + } + return new Promise(r => { + // In order to test "media isn't affected by media control", we would not + // only check `mPaused`, we would also oberve "timeupdate" event multiple + // times to ensure that video is still playing continually. + let timeUpdateCount = 0; + ok(!video.paused); + video.ontimeupdate = () => { + if (++timeUpdateCount == 3) { + video.ontimeupdate = null; + r(); + } + }; + }); + }); +} + +function couldElementBecomeEligible(elementId) { + return elementId == "muted" || elementId == "volume-0"; +} + +function makeElementEligible(tab, elementId) { + return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => { + const video = content.document.getElementById(Id); + if (!video) { + ok(false, `can't get the media element!`); + } + // to turn inaudible media become audible in order to be controlled. + video.volume = 1.0; + video.muted = false; + }); +} + +function waitUntilMediaPaused(tab, elementId) { + return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => { + const video = content.document.getElementById(Id); + if (!video) { + ok(false, `can't get the media element!`); + } + if (video.paused) { + ok(true, "media has been paused"); + return Promise.resolve(); + } + return new Promise(r => (video.onpaused = r)); + }); +} + +function enterFullScreen(tab, elementId) { + return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => { + return new Promise(r => { + const element = content.document.getElementById(Id); + element.requestFullscreen(); + element.onfullscreenchange = () => { + element.onfullscreenchange = null; + element.onfullscreenerror = null; + r(); + }; + element.onfullscreenerror = () => { + // Retry until the element successfully enters fullscreen. + element.requestFullscreen(); + }; + }); + }); +} + +function leaveFullScreen(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], _ => { + return content.document.exitFullscreen(); + }); +} |