<!DOCTYPE HTML> <html> <head> <title>Video controls test</title> <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="text/javascript" src="/tests/SimpleTest/EventUtils.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> <pre id="test"> <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 playButtonWidth = 28; const playButtonHeight = 28; const muteButtonWidth = 33; const muteButtonHeight = 28; const durationWidth = 34; const fullscreenButtonWidth = 28; const fullscreenButtonHeight = 28; const volumeSliderWidth = 32; const scrubberWidth = videoWidth - playButtonWidth - durationWidth - muteButtonWidth - volumeSliderWidth - fullscreenButtonWidth; const scrubberHeight = 28; // 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; 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); 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 = 0 + playButtonWidth; const scrubberCenterY = videoHeight - Math.round(scrubberHeight / 2); var testnum = 1; var video = document.getElementById("video"); const domUtil = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"] .getService(SpecialPowers.Ci.inIDOMUtils); function getButtonByAttribute(aName, aValue) { var kids = domUtil.getChildrenForNode(video, true); var videocontrols = kids[1]; return SpecialPowers.wrap(document) .getAnonymousElementByAttribute(videocontrols, aName, aValue); } function isMuteButtonMuted() { var muteButton = getButtonByAttribute('class', 'muteButton'); return muteButton.getAttribute('muted') === 'true'; } function isVolumeSliderShowingCorrectVolume(expectedVolume) { var volumeButton = getButtonByAttribute('anonid', 'volumeForeground'); let expectedPaddingRight = (1 - expectedVolume) * volumeSliderWidth + "px"; is(volumeButton.style.paddingRight, expectedPaddingRight, "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 runTest(event) { ok(true, "----- test #" + testnum + " -----"); switch (testnum) { /* * Check operation of play/pause/mute/unmute buttons. */ case 1: // Check initial state upon load is(event.type, "canplaythrough", "checking event type"); is(video.paused, true, "checking video play state"); is(video.muted, false, "checking video mute state"); // Click the play button SimpleTest.executeSoon(() => { synthesizeMouse(video, playButtonCenterX, playButtonCenterY, { }); }); break; case 2: is(event.type, "play", "checking event type"); is(video.paused, false, "checking video play state"); is(video.muted, false, "checking video mute state"); // Click the pause button SimpleTest.executeSoon(() => { synthesizeMouse(video, playButtonCenterX, playButtonCenterY, { }); }); break; case 3: is(event.type, "pause", "checking event type"); is(video.paused, true, "checking video play state"); is(video.muted, false, "checking video mute state"); SimpleTest.executeSoon(() => { synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, { }); // Mute. }); break; case 4: is(event.type, "volumechange", "checking event type"); is(video.paused, true, "checking video play state"); is(video.muted, true, "checking video mute state"); SimpleTest.executeSoon(() => { synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, { }); // Unmute. }); break; /* * Bug 470596: Make sure that having CSS border or padding doesn't * break the controls (though it should move them) */ case 5: is(event.type, "volumechange", "checking event type"); is(video.paused, true, "checking video play state"); is(video.muted, false, "checking video mute state"); 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 SimpleTest.executeSoon(() => { synthesizeMouse(video, 100 + playButtonCenterX, 40 + playButtonCenterY, { }); }); break; case 6: is(event.type, "play", "checking event type"); is(video.paused, false, "checking video play state"); is(video.muted, false, "checking video mute state"); video.pause(); break; case 7: is(event.type, "pause", "checking event type"); is(video.paused, true, "checking video play state"); is(video.muted, false, "checking video mute state"); // Click the mute button SimpleTest.executeSoon(() => { synthesizeMouse(video, 100 + muteButtonCenterX, 40 + muteButtonCenterY, { }); }); break; case 8: is(event.type, "volumechange", "checking event type"); is(video.paused, true, "checking video play state"); is(video.muted, true, "checking video mute state"); // Clear the style set in test 5. video.style.border = ""; video.style.borderWidth = ""; video.style.padding = ""; video.muted = false; break; /* * Previous tests have moved playback postion, reset it to 0. */ case 9: is(event.type, "volumechange", "checking event type"); is(video.paused, true, "checking video play state"); is(video.muted, false, "checking video mute state"); ok(true, "video position is at " + video.currentTime); video.currentTime = 0.0; break; case 10: is(event.type, "seeking", "checking event type"); ok(true, "video position is at " + video.currentTime); break; /* * Drag the slider's thumb to the halfway point with the mouse. */ case 11: is(event.type, "seeked", "checking event type"); ok(true, "video position is at " + video.currentTime); // Bug 477434 -- sometimes we get 0.098999 here instead of 0! // is(video.currentTime, 0.0, "checking playback position"); SimpleTest.executeSoon(() => { var beginDragX = scrubberOffsetX; var endDragX = scrubberOffsetX + (scrubberWidth / 2); synthesizeMouse(video, beginDragX, scrubberCenterY, { type: "mousedown", button: 0 }); synthesizeMouse(video, endDragX, scrubberCenterY, { type: "mousemove", button: 0 }); synthesizeMouse(video, endDragX, scrubberCenterY, { type: "mouseup", button: 0 }); }); break; case 12: is(event.type, "seeking", "checking event type"); ok(true, "video position is at " + video.currentTime); break; /* * Click the slider at the 1/4 point with the mouse (jump backwards) */ case 13: is(event.type, "seeked", "checking event type"); ok(true, "video position is at " + video.currentTime); var expectedTime = videoDuration / 2; ok(Math.abs(video.currentTime - expectedTime) < 0.1, "checking expected playback position"); SimpleTest.executeSoon(() => { synthesizeMouse(video, scrubberOffsetX + (scrubberWidth / 4), scrubberCenterY, { }); }); break; case 14: is(event.type, "seeking", "checking event type"); ok(true, "video position is at " + video.currentTime); break; case 15: is(event.type, "seeked", "checking event type"); 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. 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; break; // See bug 694696. case 16: is(event.type, "volumechange", "checking event type"); is(video.volume, 0.1, "Volume should be set."); ok(!video.muted, "Video is not muted."); video.focus(); SimpleTest.executeSoon(() => synthesizeKey("VK_DOWN", {})); break; case 17: is(event.type, "volumechange", "checking event type"); is(video.volume, 0, "Volume should be 0."); ok(!video.muted, "Video is not muted."); SimpleTest.executeSoon(() => { ok(isMuteButtonMuted(), "Mute button says it's muted"); synthesizeKey("VK_UP", {}); }); break; case 18: is(event.type, "volumechange", "checking event type"); is(video.volume, 0.1, "Volume is increased."); ok(!video.muted, "Video is not muted."); SimpleTest.executeSoon(() => { ok(!isMuteButtonMuted(), "Mute button says it's not muted"); synthesizeKey("VK_DOWN", {}); }); break; case 19: is(event.type, "volumechange", "checking event type"); is(video.volume, 0, "Volume should be 0."); ok(!video.muted, "Video is not muted."); SimpleTest.executeSoon(() => { ok(isMuteButtonMuted(), "Mute button says it's muted"); synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, { }); }); break; case 20: is(event.type, "volumechange", "checking event type"); is(video.volume, 0.5, "Volume should be 0.5."); ok(!video.muted, "Video is not muted."); SimpleTest.executeSoon(() => synthesizeKey("VK_UP", {})); break; case 21: is(event.type, "volumechange", "checking event type"); is(video.volume, 0.6, "Volume should be 0.6."); ok(!video.muted, "Video is not muted."); SimpleTest.executeSoon(() => { synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, { }); }); break; case 22: is(event.type, "volumechange", "checking event type"); is(video.volume, 0.6, "Volume should be 0.6."); ok(video.muted, "Video is muted."); SimpleTest.executeSoon(() => { ok(isMuteButtonMuted(), "Mute button says it's muted"); synthesizeMouse(video, muteButtonCenterX, muteButtonCenterY, { }); }); break; case 23: is(event.type, "volumechange", "checking event type"); is(video.volume, 0.6, "Volume should be 0.6."); ok(!video.muted, "Video is not muted."); SimpleTest.executeSoon(() => { ok(!isMuteButtonMuted(), "Mute button says it's not muted"); synthesizeMouse(video, fullscreenButtonCenterX, fullscreenButtonCenterY, { }); }); break; case 24: is(event.type, "mozfullscreenchange", "checking event type"); is(video.volume, 0.6, "Volume should still be 0.6"); SimpleTest.executeSoon(function() { isVolumeSliderShowingCorrectVolume(video.volume); synthesizeKey("VK_ESCAPE", {}); }); break; case 25: is(event.type, "mozfullscreenchange", "checking event type"); is(video.volume, 0.6, "Volume should still be 0.6"); SimpleTest.executeSoon(function() { isVolumeSliderShowingCorrectVolume(video.volume); forceReframe(); video.focus(); synthesizeKey("VK_DOWN", {}); }); break; case 26: is(event.type, "volumechange", "checking event type"); is(video.volume, 0.5, "Volume should be decreased by 0.1"); SimpleTest.executeSoon(function() { isVolumeSliderShowingCorrectVolume(video.volume); SimpleTest.finish(); }); break; default: throw "unexpected test #" + testnum + " w/ event " + event.type; } testnum++; } function canplaythroughevent(event) { video.removeEventListener("canplaythrough", canplaythroughevent, false); // Other events expected by the test. video.addEventListener("play", runTest, false); video.addEventListener("pause", runTest, false); video.addEventListener("volumechange", runTest, false); video.addEventListener("seeking", runTest, false); video.addEventListener("seeked", runTest, false); document.addEventListener("mozfullscreenchange", runTest, false); // Begin the test. runTest(event); } function startMediaLoad() { // Kick off test once video has loaded, in its canplaythrough event handler. video.src = "seek_with_sound.ogg"; video.addEventListener("canplaythrough", canplaythroughevent, false); } function loadevent(event) { SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, startMediaLoad); } window.addEventListener("load", loadevent, false); SimpleTest.waitForExplicitFinish(); </script> </pre> </body> </html>