659 lines
24 KiB
HTML
659 lines
24 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>Video controls test</title>
|
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
|
<script type="text/javascript" src="head.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
|
</head>
|
|
<body>
|
|
<p id="display"></p>
|
|
|
|
<div id="content">
|
|
<video
|
|
width="320"
|
|
height="240"
|
|
id="video"
|
|
controls
|
|
mozNoDynamicControls
|
|
preload="auto"
|
|
></video>
|
|
</div>
|
|
|
|
<div id="host"></div>
|
|
|
|
<script class="testbody" type="text/javascript">
|
|
/*
|
|
* Positions of the UI elements, relative to the upper-left corner of the
|
|
* <video> box.
|
|
*/
|
|
const videoWidth = 320;
|
|
const videoHeight = 240;
|
|
const videoDuration = 3.8329999446868896;
|
|
|
|
const controlBarMargin = 9;
|
|
|
|
const playButtonWidth = 30;
|
|
const playButtonHeight = 40;
|
|
const muteButtonWidth = 30;
|
|
const muteButtonHeight = 40;
|
|
const positionAndDurationWidth = 75;
|
|
const fullscreenButtonWidth = 30;
|
|
const fullscreenButtonHeight = 40;
|
|
const volumeSliderWidth = 48;
|
|
const volumeSliderMarginStart = 4;
|
|
const volumeSliderMarginEnd = 6;
|
|
const scrubberMargin = 9;
|
|
const scrubberWidth =
|
|
videoWidth -
|
|
controlBarMargin -
|
|
playButtonWidth -
|
|
scrubberMargin * 2 -
|
|
positionAndDurationWidth -
|
|
muteButtonWidth -
|
|
volumeSliderMarginStart -
|
|
volumeSliderWidth -
|
|
volumeSliderMarginEnd -
|
|
fullscreenButtonWidth -
|
|
controlBarMargin;
|
|
const scrubberHeight = 40;
|
|
|
|
// Play button is on the bottom-left
|
|
const playButtonCenterX = 0 + Math.round(playButtonWidth / 2);
|
|
const playButtonCenterY = videoHeight - Math.round(playButtonHeight / 2);
|
|
// Mute button is on the bottom-right before the full screen button and volume slider
|
|
const muteButtonCenterX =
|
|
videoWidth -
|
|
Math.round(muteButtonWidth / 2) -
|
|
volumeSliderWidth -
|
|
fullscreenButtonWidth -
|
|
controlBarMargin;
|
|
const muteButtonCenterY = videoHeight - Math.round(muteButtonHeight / 2);
|
|
// Fullscreen button is on the bottom-right at the far end
|
|
const fullscreenButtonCenterX =
|
|
videoWidth - Math.round(fullscreenButtonWidth / 2) - controlBarMargin;
|
|
const fullscreenButtonCenterY =
|
|
videoHeight - Math.round(fullscreenButtonHeight / 2);
|
|
// Scrubber bar is between the play and mute buttons. We don't need it's
|
|
// X center, just the offset of its box.
|
|
const scrubberOffsetX =
|
|
controlBarMargin + playButtonWidth + scrubberMargin;
|
|
const scrubberCenterY = videoHeight - Math.round(scrubberHeight / 2);
|
|
|
|
const video = document.getElementById("video");
|
|
|
|
let requiredEvents = [];
|
|
let forbiddenEvents = [];
|
|
let receivedEvents = [];
|
|
let expectingEventPromise;
|
|
|
|
async function isMuteButtonMuted() {
|
|
const muteButton = getElementWithinVideo(video, "muteButton");
|
|
await new Promise(SimpleTest.executeSoon);
|
|
return muteButton.hasAttribute("muted");
|
|
}
|
|
|
|
async function isVolumeSliderShowingCorrectVolume(expectedVolume) {
|
|
const volumeControl = getElementWithinVideo(video, "volumeControl");
|
|
await new Promise(SimpleTest.executeSoon);
|
|
is(
|
|
+volumeControl.value,
|
|
expectedVolume * 100,
|
|
"volume slider should match expected volume"
|
|
);
|
|
}
|
|
|
|
function forceReframe() {
|
|
// Setting display then getting the bounding rect to force a frame
|
|
// reconstruction on the video element.
|
|
video.style.display = "block";
|
|
video.getBoundingClientRect();
|
|
video.style.display = "";
|
|
video.getBoundingClientRect();
|
|
}
|
|
|
|
function captureEventThenCheck(event) {
|
|
if (event) {
|
|
info(`Received event ${event.type}.`);
|
|
receivedEvents.push(event.type);
|
|
}
|
|
|
|
const cleanupExpectations = () => {
|
|
requiredEvents.length = 0;
|
|
forbiddenEvents.length = 0;
|
|
receivedEvents.length = 0;
|
|
};
|
|
|
|
// If receivedEvents contains any of the forbiddenEvents, reject the expectingEventPromise.
|
|
for (const forbidden of forbiddenEvents) {
|
|
if (receivedEvents.includes(forbidden)) {
|
|
// Capture list of requiredEvents for later reporting.
|
|
const oldRequiredEvents = requiredEvents.slice();
|
|
cleanupExpectations();
|
|
expectingEventPromise.reject(
|
|
new Error(
|
|
`Got forbidden event ${forbidden} while expecting ${oldRequiredEvents}`
|
|
)
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!requiredEvents.length) {
|
|
// We might be getting an event before we started waiting for it. That's fine,
|
|
// just early exit.
|
|
return;
|
|
}
|
|
|
|
// We are expecting at least one event. If receivedEvents is lacking one of the
|
|
// requiredEvents, exit.
|
|
for (const required of requiredEvents) {
|
|
if (!receivedEvents.includes(required)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// We've received all the events we required. Resolve the expectingEventPromise.
|
|
info(`No longer waiting for expected event(s) ${requiredEvents}.`);
|
|
cleanupExpectations();
|
|
|
|
// Don't resolve this right away, because this is called from within event handlers and
|
|
// we want all other event handlers to have a chance to respond to this event before we
|
|
// proceed with the test. This solves problems with things like a play-pause-play, where
|
|
// some of the actions will be discarded if the video controls themselves aren't in the
|
|
// expected state.
|
|
SimpleTest.executeSoon(expectingEventPromise.resolve);
|
|
}
|
|
|
|
function waitForEvent(required, forbidden) {
|
|
return new Promise((resolve, reject) => {
|
|
expectingEventPromise = { resolve, reject };
|
|
|
|
info(
|
|
`Waiting for ${required}` +
|
|
(forbidden ? ` but not ${forbidden}...` : `...`)
|
|
);
|
|
if (Array.isArray(required)) {
|
|
requiredEvents.push(...required);
|
|
} else {
|
|
requiredEvents.push(required);
|
|
}
|
|
if (forbidden) {
|
|
if (Array.isArray(forbidden)) {
|
|
forbiddenEvents.push(...forbidden);
|
|
} else {
|
|
forbiddenEvents.push(forbidden);
|
|
}
|
|
}
|
|
|
|
// Immediately check the received events, since the calling pattern used in this test is
|
|
// calling this method *after* the events could have been triggered.
|
|
captureEventThenCheck();
|
|
});
|
|
}
|
|
|
|
async function repeatUntilSuccessful(f) {
|
|
let successful = false;
|
|
do {
|
|
try {
|
|
// Delay one event loop.
|
|
await new Promise(r => SimpleTest.executeSoon(r));
|
|
await f();
|
|
successful = true;
|
|
} catch (error) {
|
|
info(`repeatUntilSuccessful: error ${error}.`);
|
|
}
|
|
} while (!successful);
|
|
}
|
|
|
|
add_task(async function setup() {
|
|
SimpleTest.requestCompleteLog();
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [
|
|
["media.cache_size", 40000],
|
|
["full-screen-api.enabled", true],
|
|
["full-screen-api.allow-trusted-requests-only", false],
|
|
["full-screen-api.transition-duration.enter", "0 0"],
|
|
["full-screen-api.transition-duration.leave", "0 0"],
|
|
],
|
|
});
|
|
await new Promise(resolve => {
|
|
video.addEventListener("canplaythrough", resolve, { once: true });
|
|
video.src = "seek_with_sound.webm";
|
|
});
|
|
|
|
video.addEventListener("play", captureEventThenCheck);
|
|
video.addEventListener("pause", captureEventThenCheck);
|
|
video.addEventListener("volumechange", captureEventThenCheck);
|
|
video.addEventListener("seeking", captureEventThenCheck);
|
|
video.addEventListener("seeked", captureEventThenCheck);
|
|
document.addEventListener("mozfullscreenchange", captureEventThenCheck);
|
|
document.addEventListener("fullscreenerror", captureEventThenCheck);
|
|
|
|
["mousedown", "mouseup", "dblclick", "click"].forEach(eventType => {
|
|
window.addEventListener(eventType, evt => {
|
|
// Prevent default action of leaked events and make the tests fail.
|
|
evt.preventDefault();
|
|
ok(
|
|
false,
|
|
"Event " +
|
|
eventType +
|
|
" in videocontrol should not leak to content;" +
|
|
"the event was dispatched from the " +
|
|
evt.target.tagName.toLowerCase() +
|
|
" element."
|
|
);
|
|
});
|
|
});
|
|
|
|
// Check initial state upon load
|
|
is(video.paused, true, "checking video play state");
|
|
is(video.muted, false, "checking video mute state");
|
|
});
|
|
|
|
add_task(async function click_playbutton() {
|
|
synthesizeMouse(video, playButtonCenterX, playButtonCenterY, {});
|
|
await waitForEvent("play");
|
|
is(video.paused, false, "checking video play state");
|
|
is(video.muted, false, "checking video mute state");
|
|
});
|
|
|
|
add_task(async function click_pausebutton() {
|
|
synthesizeMouse(video, playButtonCenterX, playButtonCenterY, {});
|
|
await waitForEvent("pause");
|
|
is(video.paused, true, "checking video play state");
|
|
is(video.muted, false, "checking video mute state");
|
|
});
|
|
|
|
add_task(async function mute_volume() {
|
|
synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, {});
|
|
await waitForEvent("volumechange");
|
|
is(video.paused, true, "checking video play state");
|
|
is(video.muted, true, "checking video mute state");
|
|
});
|
|
|
|
add_task(async function unmute_volume() {
|
|
synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, {});
|
|
await waitForEvent("volumechange");
|
|
is(video.paused, true, "checking video play state");
|
|
is(video.muted, false, "checking video mute state");
|
|
});
|
|
|
|
/*
|
|
* Bug 470596: Make sure that having CSS border or padding doesn't
|
|
* break the controls (though it should move them)
|
|
*/
|
|
add_task(async function styled_video() {
|
|
video.style.border = "medium solid purple";
|
|
video.style.borderWidth = "30px 40px 50px 60px";
|
|
video.style.padding = "10px 20px 30px 40px";
|
|
// totals: top: 40px, right: 60px, bottom: 80px, left: 100px
|
|
|
|
// Click the play button
|
|
synthesizeMouse(
|
|
video,
|
|
100 + playButtonCenterX,
|
|
40 + playButtonCenterY,
|
|
{}
|
|
);
|
|
await waitForEvent("play");
|
|
is(video.paused, false, "checking video play state");
|
|
is(video.muted, false, "checking video mute state");
|
|
|
|
// Pause the video
|
|
video.pause();
|
|
await waitForEvent("pause");
|
|
is(video.paused, true, "checking video play state");
|
|
is(video.muted, false, "checking video mute state");
|
|
|
|
// Click the mute button
|
|
synthesizeMouse(
|
|
video,
|
|
100 + muteButtonCenterX,
|
|
40 + muteButtonCenterY,
|
|
{}
|
|
);
|
|
await waitForEvent("volumechange");
|
|
is(video.paused, true, "checking video play state");
|
|
is(video.muted, true, "checking video mute state");
|
|
|
|
// Clear the style set
|
|
video.style.border = "";
|
|
video.style.borderWidth = "";
|
|
video.style.padding = "";
|
|
|
|
// Unmute the video
|
|
video.muted = false;
|
|
await waitForEvent("volumechange");
|
|
is(video.paused, true, "checking video play state");
|
|
is(video.muted, false, "checking video mute state");
|
|
});
|
|
|
|
/*
|
|
* Previous tests have moved playback postion, reset it to 0.
|
|
*/
|
|
add_task(async function reset_currentTime() {
|
|
ok(true, "video position is at " + video.currentTime);
|
|
video.currentTime = 0.0;
|
|
await waitForEvent(["seeking", "seeked"]);
|
|
// Bug 477434 -- sometimes we get 0.098999 here instead of 0!
|
|
// is(video.currentTime, 0.0, "checking playback position");
|
|
ok(true, "video position is at " + video.currentTime);
|
|
});
|
|
|
|
/*
|
|
* Drag the slider's thumb to the halfway point with the mouse.
|
|
*/
|
|
add_task(async function drag_slider() {
|
|
const beginDragX = scrubberOffsetX;
|
|
const endDragX = scrubberOffsetX + scrubberWidth / 2;
|
|
const expectedTime = videoDuration / 2;
|
|
|
|
function mousemoved(evt) {
|
|
ok(
|
|
false,
|
|
"Mousemove event should not be handled by content while dragging; " +
|
|
"the event was dispatched from the " +
|
|
evt.target.tagName.toLowerCase() +
|
|
" element."
|
|
);
|
|
}
|
|
|
|
window.addEventListener("mousemove", mousemoved);
|
|
|
|
synthesizeMouse(video, beginDragX, scrubberCenterY, {
|
|
type: "mousedown",
|
|
button: 0,
|
|
});
|
|
synthesizeMouse(video, endDragX, scrubberCenterY, {
|
|
type: "mousemove",
|
|
button: 0,
|
|
});
|
|
synthesizeMouse(video, endDragX, scrubberCenterY, {
|
|
type: "mouseup",
|
|
button: 0,
|
|
});
|
|
await waitForEvent(["seeking", "seeked"]);
|
|
ok(true, "video position is at " + video.currentTime);
|
|
// The width of srubber is not equal in every platform as we use system default font
|
|
// in duration and position box. We can not precisely drag to expected position, so
|
|
// we just make sure the difference is within 10% of video duration.
|
|
ok(
|
|
Math.abs(video.currentTime - expectedTime) < videoDuration / 10,
|
|
"checking expected playback position"
|
|
);
|
|
|
|
window.removeEventListener("mousemove", mousemoved);
|
|
});
|
|
|
|
/*
|
|
* Click the slider at the 1/4 point with the mouse (jump backwards)
|
|
*/
|
|
add_task(async function click_slider() {
|
|
synthesizeMouse(
|
|
video,
|
|
scrubberOffsetX + scrubberWidth / 4,
|
|
scrubberCenterY,
|
|
{}
|
|
);
|
|
await waitForEvent(["seeking", "seeked"]);
|
|
ok(true, "video position is at " + video.currentTime);
|
|
// The scrubber currently just jumps towards the nearest pageIncrement point, not
|
|
// precisely to the point clicked. So, expectedTime isn't (videoDuration / 4).
|
|
// We should end up at 1.733, but sometimes we end up at 1.498. I guess
|
|
// it's timing depending if the <scale> things it's click-and-hold, or a
|
|
// single click. So, just make sure we end up less that the previous
|
|
// position.
|
|
const lastPosition = videoDuration / 2 - 0.1;
|
|
ok(
|
|
video.currentTime < lastPosition,
|
|
"checking expected playback position"
|
|
);
|
|
|
|
// Set volume to 0.1 so one down arrow hit will decrease it to 0.
|
|
video.volume = 0.1;
|
|
await waitForEvent("volumechange");
|
|
is(video.volume, 0.1, "Volume should be set.");
|
|
ok(!video.muted, "Video is not muted.");
|
|
});
|
|
|
|
// See bug 694696.
|
|
add_task(async function change_volume() {
|
|
video.focus();
|
|
|
|
synthesizeKey("KEY_ArrowDown");
|
|
await waitForEvent("volumechange");
|
|
is(video.volume, 0, "Volume should be 0.");
|
|
ok(!video.muted, "Video is not muted.");
|
|
ok(await isMuteButtonMuted(), "Mute button says it's muted");
|
|
|
|
synthesizeKey("KEY_ArrowUp");
|
|
await waitForEvent("volumechange");
|
|
is(video.volume, 0.1, "Volume is increased.");
|
|
ok(!video.muted, "Video is not muted.");
|
|
ok(!(await isMuteButtonMuted()), "Mute button says it's not muted");
|
|
|
|
synthesizeKey("KEY_ArrowDown");
|
|
await waitForEvent("volumechange");
|
|
is(video.volume, 0, "Volume should be 0.");
|
|
ok(!video.muted, "Video is not muted.");
|
|
ok(await isMuteButtonMuted(), "Mute button says it's muted");
|
|
|
|
synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, {});
|
|
await waitForEvent("volumechange");
|
|
is(video.volume, 0.5, "Volume should be 0.5.");
|
|
ok(!video.muted, "Video is not muted.");
|
|
|
|
synthesizeKey("KEY_ArrowUp");
|
|
await waitForEvent("volumechange");
|
|
is(video.volume, 0.6, "Volume should be 0.6.");
|
|
ok(!video.muted, "Video is not muted.");
|
|
|
|
synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, {});
|
|
await waitForEvent("volumechange");
|
|
is(video.volume, 0.6, "Volume should be 0.6.");
|
|
ok(video.muted, "Video is muted.");
|
|
ok(await isMuteButtonMuted(), "Mute button says it's muted");
|
|
|
|
synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, {});
|
|
await waitForEvent("volumechange");
|
|
is(video.volume, 0.6, "Volume should be 0.6.");
|
|
ok(!video.muted, "Video is not muted.");
|
|
ok(!(await isMuteButtonMuted()), "Mute button says it's not muted");
|
|
|
|
await repeatUntilSuccessful(async () => {
|
|
synthesizeMouse(
|
|
video,
|
|
fullscreenButtonCenterX,
|
|
fullscreenButtonCenterY,
|
|
{}
|
|
);
|
|
await waitForEvent("mozfullscreenchange", "fullscreenerror");
|
|
});
|
|
|
|
is(video.volume, 0.6, "Volume should still be 0.6");
|
|
await isVolumeSliderShowingCorrectVolume(video.volume);
|
|
|
|
await repeatUntilSuccessful(async () => {
|
|
video.focus();
|
|
synthesizeKey("KEY_Escape");
|
|
await waitForEvent("mozfullscreenchange", "fullscreenerror");
|
|
});
|
|
|
|
is(video.volume, 0.6, "Volume should still be 0.6");
|
|
await isVolumeSliderShowingCorrectVolume(video.volume);
|
|
forceReframe();
|
|
|
|
video.focus();
|
|
synthesizeKey("KEY_ArrowDown");
|
|
await waitForEvent("volumechange");
|
|
is(video.volume, 0.5, "Volume should be decreased by 0.1");
|
|
await isVolumeSliderShowingCorrectVolume(video.volume);
|
|
});
|
|
|
|
add_task(async function whitespace_pause_video() {
|
|
synthesizeMouse(video, playButtonCenterX, playButtonCenterY, {});
|
|
await waitForEvent("play");
|
|
|
|
video.focus();
|
|
sendString(" ");
|
|
await waitForEvent("pause");
|
|
|
|
synthesizeMouse(video, playButtonCenterX, playButtonCenterY, {});
|
|
await waitForEvent("play");
|
|
});
|
|
|
|
/*
|
|
* Bug 1352724: Click and hold on timeline should pause video immediately.
|
|
*/
|
|
add_task(async function click_and_hold_slider() {
|
|
synthesizeMouse(video, scrubberOffsetX + 10, scrubberCenterY, {
|
|
type: "mousedown",
|
|
button: 0,
|
|
});
|
|
await waitForEvent(["pause", "seeking", "seeked"]);
|
|
|
|
synthesizeMouse(video, scrubberOffsetX + 10, scrubberCenterY, {});
|
|
await waitForEvent("play");
|
|
});
|
|
|
|
/*
|
|
* Bug 1402877: Don't let click event dispatch through media controls to video element.
|
|
*/
|
|
add_task(async function click_event_dispatch() {
|
|
const clientScriptClickHandler = () => {
|
|
ok(false, "Should not receive the event");
|
|
};
|
|
video.addEventListener("click", clientScriptClickHandler);
|
|
|
|
video.pause();
|
|
await waitForEvent("pause");
|
|
video.currentTime = 0.0;
|
|
await waitForEvent(["seeking", "seeked"]);
|
|
is(video.paused, true, "checking video play state");
|
|
synthesizeMouse(video, scrubberOffsetX + 10, scrubberCenterY, {});
|
|
await waitForEvent(["seeking", "seeked"]);
|
|
|
|
video.removeEventListener("click", clientScriptClickHandler);
|
|
});
|
|
|
|
// Bug 1367194: Always ensure video is paused before finishing the test.
|
|
add_task(async function ensure_video_pause() {
|
|
if (!video.paused) {
|
|
video.pause();
|
|
await waitForEvent("pause");
|
|
}
|
|
});
|
|
|
|
// Bug 1452342: Make sure the cursor hides and shows on full screen mode.
|
|
add_task(async function ensure_fullscreen_cursor() {
|
|
video.removeAttribute("mozNoDynamicControls");
|
|
video.play();
|
|
await waitForEvent("play");
|
|
|
|
await repeatUntilSuccessful(async () => {
|
|
video.focus();
|
|
await video.mozRequestFullScreen();
|
|
await waitForEvent("mozfullscreenchange", "fullscreenerror");
|
|
});
|
|
|
|
const controlsSpacer = getElementWithinVideo(video, "controlsSpacer");
|
|
is(controlsSpacer.hasAttribute("hideCursor"), true, "Cursor is hidden");
|
|
|
|
let delta = 1;
|
|
await SimpleTest.promiseWaitForCondition(() => {
|
|
// Wiggle the mouse a bit
|
|
synthesizeMouse(
|
|
video,
|
|
playButtonCenterX + delta,
|
|
playButtonCenterY + delta,
|
|
{ type: "mousemove" }
|
|
);
|
|
delta = !delta;
|
|
return !controlsSpacer.hasAttribute("hideCursor");
|
|
}, "Waiting for hideCursor attribute to disappear");
|
|
is(controlsSpacer.hasAttribute("hideCursor"), false, "Cursor is shown");
|
|
|
|
// Restore
|
|
video.setAttribute("mozNoDynamicControls", "");
|
|
|
|
await repeatUntilSuccessful(async () => {
|
|
await document.mozCancelFullScreen();
|
|
await waitForEvent("mozfullscreenchange", "fullscreenerror");
|
|
});
|
|
|
|
if (!video.paused) {
|
|
video.pause();
|
|
await waitForEvent("pause");
|
|
}
|
|
});
|
|
|
|
// Bug 1505547: Make sure the fullscreen button works if the video element is in shadow tree.
|
|
add_task(async function ensure_fullscreen_button() {
|
|
video.removeAttribute("mozNoDynamicControls");
|
|
let host = document.getElementById("host");
|
|
let root = host.attachShadow({ mode: "open" });
|
|
root.appendChild(video);
|
|
forceReframe();
|
|
|
|
await repeatUntilSuccessful(async () => {
|
|
await video.mozRequestFullScreen();
|
|
await waitForEvent("mozfullscreenchange", "fullscreenerror");
|
|
});
|
|
|
|
await repeatUntilSuccessful(async () => {
|
|
// Compute the location to click on to hit the fullscreen button.
|
|
// Use the video size instead of the screen size here, because mozfullscreenchange
|
|
// does not guarantee that our document covers the screen, see bug 1575630.
|
|
const r = video.getBoundingClientRect();
|
|
const buttonCenterX =
|
|
r.right - fullscreenButtonWidth / 2 - controlBarMargin;
|
|
const buttonCenterY = r.bottom - fullscreenButtonHeight / 2;
|
|
|
|
// Though the video no longer has mozNoDynamicControls, it sometimes appears
|
|
// in the shadow DOM without visible controls. This might happen because
|
|
// toggling the attribute doesn't force the controls to appear or disappear;
|
|
// it just affects the timed fadeout behavior. So we wiggle the mouse here
|
|
// as if we were still using dynamic controls.
|
|
synthesizeMouse(video, buttonCenterX, buttonCenterY, {
|
|
type: "mousemove",
|
|
});
|
|
|
|
info(`Clicking at ${buttonCenterX}, ${buttonCenterY}.`);
|
|
synthesizeMouse(video, buttonCenterX, buttonCenterY, {});
|
|
await waitForEvent("mozfullscreenchange", [
|
|
"fullscreenerror",
|
|
"play",
|
|
"pause",
|
|
]);
|
|
});
|
|
|
|
// Restore
|
|
video.setAttribute("mozNoDynamicControls", "");
|
|
document.getElementById("content").appendChild(video);
|
|
forceReframe();
|
|
});
|
|
|
|
add_task(async function ensure_doubleclick_triggers_fullscreen() {
|
|
const { x, y } = video.getBoundingClientRect();
|
|
info("Simulate double click on media player.");
|
|
|
|
await repeatUntilSuccessful(async () => {
|
|
synthesizeMouse(video, x, y, { clickCount: 2 });
|
|
// TODO: A double-click for fullscreen should *not* cause the video to play,
|
|
// but it does. Adding the "play" event to the forbidden events makes the
|
|
// test timeout.
|
|
await waitForEvent("mozfullscreenchange", "fullscreenerror");
|
|
});
|
|
|
|
ok(true, "Double clicking should trigger fullscreen event");
|
|
|
|
await repeatUntilSuccessful(async () => {
|
|
await document.mozCancelFullScreen();
|
|
await waitForEvent("mozfullscreenchange", "fullscreenerror");
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|