Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
"use strict";
const { TelemetryTestUtils } = ChromeUtils.importESModule(
);
const TEST_PAGE_LONG = TEST_ROOT + "test-video-selection.html";
const IMPROVED_CONTROLS_ENABLED_PREF =
"media.videocontrols.picture-in-picture.improved-video-controls.enabled";
async function getVideoCurrentTime(browser, videoID) {
return SpecialPowers.spawn(browser, [videoID], async videoID => {
return content.document.getElementById(videoID).currentTime;
});
}
async function getVideoDuration(browser, videoID) {
return SpecialPowers.spawn(browser, [videoID], async videoID => {
return content.document.getElementById(videoID).duration;
});
}
async function timestampUpdated(timestampEl, expectedTimestamp) {
await BrowserTestUtils.waitForMutationCondition(
timestampEl,
{ childList: true },
() => {
return expectedTimestamp === timestampEl.textContent;
}
);
}
function checkTimeCloseEnough(actual, expected, message) {
let equal = Math.abs(actual - expected);
if (equal <= 0.5) {
is(equal <= 0.5, true, message);
} else {
is(actual, expected, message);
}
}
/**
* Tests the functionality of improved Picture-in-picture
* playback controls.
*/
add_task(async () => {
let videoID = "with-controls";
await BrowserTestUtils.withNewTab(
{
url: TEST_PAGE,
gBrowser,
},
async browser => {
let waitForVideoEvent = eventType => {
return BrowserTestUtils.waitForContentEvent(browser, eventType, true);
};
await ensureVideosReady(browser);
await SpecialPowers.spawn(browser, [videoID], async videoID => {
await content.document.getElementById(videoID).play();
});
await SpecialPowers.pushPrefEnv({
set: [[IMPROVED_CONTROLS_ENABLED_PREF, true]],
});
// Open the video in PiP
let pipWin = await triggerPictureInPicture(browser, videoID);
ok(pipWin, "Got Picture-in-Picture window.");
let fullscreenButton = pipWin.document.getElementById("fullscreen");
let seekForwardButton = pipWin.document.getElementById("seekForward");
let seekBackwardButton = pipWin.document.getElementById("seekBackward");
// Try seek forward button
let seekedForwardPromise = waitForVideoEvent("seeked");
EventUtils.synthesizeMouseAtCenter(seekForwardButton, {}, pipWin);
ok(await seekedForwardPromise, "The Forward button triggers");
// Try seek backward button
let seekedBackwardPromise = waitForVideoEvent("seeked");
EventUtils.synthesizeMouseAtCenter(seekBackwardButton, {}, pipWin);
ok(await seekedBackwardPromise, "The Backward button triggers");
// The Fullsreen button appears when the pref is enabled and the fullscreen hidden property is set to false
Assert.ok(!fullscreenButton.hidden, "The Fullscreen button is visible");
// The seek Forward button appears when the pref is enabled and the seek forward button hidden property is set to false
Assert.ok(!seekForwardButton.hidden, "The Forward button is visible");
// The seek Backward button appears when the pref is enabled and the seek backward button hidden property is set to false
Assert.ok(!seekBackwardButton.hidden, "The Backward button is visible");
// CLose the PIP window
let pipClosed = BrowserTestUtils.domWindowClosed(pipWin);
let closeButton = pipWin.document.getElementById("close");
EventUtils.synthesizeMouseAtCenter(closeButton, {}, pipWin);
await pipClosed;
await SpecialPowers.pushPrefEnv({
set: [[IMPROVED_CONTROLS_ENABLED_PREF, false]],
});
// Open the video in PiP
pipWin = await triggerPictureInPicture(browser, videoID);
ok(pipWin, "Got Picture-in-Picture window.");
fullscreenButton = pipWin.document.getElementById("fullscreen");
seekForwardButton = pipWin.document.getElementById("seekForward");
seekBackwardButton = pipWin.document.getElementById("seekBackward");
// The Fullsreen button disappears when the pref is disabled and the fullscreen hidden property is set to true
Assert.ok(
fullscreenButton.hidden,
"The Fullscreen button is not visible"
);
// The seek Forward button disappears when the pref is disabled and the seek forward button hidden property is set to true
Assert.ok(seekForwardButton.hidden, "The Forward button is not visible");
// The seek Backward button disappears when the pref is disabled and the seek backward button hidden property is set to true
Assert.ok(
seekBackwardButton.hidden,
"The Backward button is not visible"
);
}
);
});
/**
* Tests the functionality of Picture-in-picture
* video scrubber
*/
add_task(async function testVideoScrubber() {
let videoID = "long";
await BrowserTestUtils.withNewTab(
{
url: TEST_PAGE_LONG,
gBrowser,
},
async browser => {
await ensureVideosReady(browser);
await SpecialPowers.pushPrefEnv({
set: [[IMPROVED_CONTROLS_ENABLED_PREF, true]],
});
// Open the video in PiP
let pipWin = await triggerPictureInPicture(browser, videoID);
ok(pipWin, "Got Picture-in-Picture window.");
let scrubber = pipWin.document.getElementById("scrubber");
scrubber.focus();
let currentTime = await getVideoCurrentTime(browser, videoID);
let expectedVideoTime = 0;
const duration = await getVideoDuration(browser, videoID);
checkTimeCloseEnough(
currentTime,
expectedVideoTime,
"Video current time is 0"
);
let timestampEl = pipWin.document.getElementById("timestamp");
let expectedTimestamp = "0:00 / 0:08";
// Wait for the timestamp to update
await timestampUpdated(timestampEl, expectedTimestamp);
let actualTimestamp = timestampEl.textContent;
is(actualTimestamp, expectedTimestamp, "Timestamp reads 0:00 / 0:08");
EventUtils.synthesizeKey("KEY_ArrowRight", {}, pipWin);
currentTime = await getVideoCurrentTime(browser, videoID);
expectedVideoTime = 5;
checkTimeCloseEnough(
currentTime,
expectedVideoTime,
"Video current time is 5"
);
expectedTimestamp = "0:05 / 0:08";
await timestampUpdated(timestampEl, expectedTimestamp);
actualTimestamp = timestampEl.textContent;
is(actualTimestamp, expectedTimestamp, "Timestamp reads 0:05 / 0:08");
EventUtils.synthesizeKey("KEY_ArrowLeft", {}, pipWin);
currentTime = await getVideoCurrentTime(browser, videoID);
expectedVideoTime = 0;
checkTimeCloseEnough(
currentTime,
expectedVideoTime,
"Video current time is 0"
);
expectedTimestamp = "0:00 / 0:08";
await timestampUpdated(timestampEl, expectedTimestamp);
actualTimestamp = timestampEl.textContent;
is(actualTimestamp, expectedTimestamp, "Timestamp reads 0:00 / 0:08");
let rect = scrubber.getBoundingClientRect();
EventUtils.synthesizeMouse(
scrubber,
rect.width / 2,
rect.height / 2,
{},
pipWin
);
expectedVideoTime = duration / 2;
currentTime = await getVideoCurrentTime(browser, videoID);
checkTimeCloseEnough(
currentTime,
expectedVideoTime,
"Video current time is 3.98..."
);
expectedTimestamp = "0:04 / 0:08";
await timestampUpdated(timestampEl, expectedTimestamp);
actualTimestamp = timestampEl.textContent;
is(actualTimestamp, expectedTimestamp, "Timestamp reads 0:04 / 0:08");
EventUtils.synthesizeMouse(
scrubber,
rect.width / 2,
rect.height / 2,
{ type: "mousedown" },
pipWin
);
EventUtils.synthesizeMouse(
scrubber,
rect.width,
rect.height / 2,
{ type: "mousemove" },
pipWin
);
EventUtils.synthesizeMouse(
scrubber,
rect.width,
rect.height / 2,
{ type: "mouseup" },
pipWin
);
expectedVideoTime = duration;
currentTime = await getVideoCurrentTime(browser, videoID);
checkTimeCloseEnough(
currentTime,
expectedVideoTime,
"Video current time is 7.96..."
);
await ensureMessageAndClosePiP(browser, videoID, pipWin, false);
}
);
});
/**
* Tests the behavior of the scrubber and position/duration indicator for a
* video with an invalid/non-finite duration.
*/
add_task(async function testInvalidDuration() {
await BrowserTestUtils.withNewTab(
{
url: TEST_PAGE_WITH_NAN_VIDEO_DURATION,
gBrowser,
},
async browser => {
const videoID = "nan-duration";
// This tests skips calling ensureVideosReady, because canplaythrough
// will never fire for the NaN duration video.
await SpecialPowers.pushPrefEnv({
set: [[IMPROVED_CONTROLS_ENABLED_PREF, true]],
});
// Open the video in PiP
let pipWin = await triggerPictureInPicture(browser, videoID);
ok(pipWin, "Got Picture-in-Picture window.");
// Both the scrubber and the duration should be hidden.
let timestampEl = pipWin.document.getElementById("timestamp");
ok(timestampEl.hidden, "Timestamp in the PIP window should be hidden.");
let scrubberEl = pipWin.document.getElementById("scrubber");
ok(
scrubberEl.hidden,
"Scrubber control in the PIP window should be hidden"
);
}
);
});