diff options
Diffstat (limited to 'toolkit/components/pictureinpicture/tests/browser_changePiPSrcInFullscreen.js')
-rw-r--r-- | toolkit/components/pictureinpicture/tests/browser_changePiPSrcInFullscreen.js | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/toolkit/components/pictureinpicture/tests/browser_changePiPSrcInFullscreen.js b/toolkit/components/pictureinpicture/tests/browser_changePiPSrcInFullscreen.js new file mode 100644 index 0000000000..e971f17296 --- /dev/null +++ b/toolkit/components/pictureinpicture/tests/browser_changePiPSrcInFullscreen.js @@ -0,0 +1,511 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { sinon } = ChromeUtils.importESModule( + "resource://testing-common/Sinon.sys.mjs" +); + +const NEW_VIDEO_ASPECT_RATIO = 1.334; + +async function switchVideoSource(browser, src) { + await ContentTask.spawn(browser, { src }, async ({ src }) => { + let doc = content.document; + let video = doc.getElementById("no-controls"); + video.src = src; + }); +} + +/** + * + * @param {Object} actual The actual size and position of the window + * @param {Object} expected The expected size and position of the window + * @param {String} message A message to print before asserting the size and position + */ +function assertEvent(actual, expected, message) { + info(message); + isfuzzy( + actual.width, + expected.width, + ACCEPTABLE_DIFFERENCE, + `The actual width: ${actual.width}. The expected width: ${expected.width}` + ); + isfuzzy( + actual.height, + expected.height, + ACCEPTABLE_DIFFERENCE, + `The actual height: ${actual.height}. The expected height: ${expected.height}` + ); + isfuzzy( + actual.left, + expected.left, + ACCEPTABLE_DIFFERENCE, + `The actual left: ${actual.left}. The expected left: ${expected.left}` + ); + isfuzzy( + actual.top, + expected.top, + ACCEPTABLE_DIFFERENCE, + `The actual top: ${actual.top}. The expected top: ${expected.top}` + ); +} + +/** + * This test is our control test. This tests that when the PiP window exits + * fullscreen it will return to the size it was before being fullscreened. + */ +add_task(async function testNoSrcChangeFullscreen() { + // After opening the PiP window, it is resized to 640x360. There is a change + // the PiP window will open with that size. To prevent that we override the + // last saved position so we open at (0, 0) and 300x300. + overrideSavedPosition(0, 0, 300, 300); + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + await ensureVideosReady(browser); + let pipWin = await triggerPictureInPicture(browser, "no-controls"); + let controls = pipWin.document.getElementById("controls"); + const screen = pipWin.screen; + + let resizeEventArray = []; + pipWin.addEventListener("resize", event => { + let win = event.target; + let obj = { + width: win.innerWidth, + height: win.innerHeight, + left: win.screenLeft, + top: win.screenTop, + }; + resizeEventArray.push(obj); + }); + + // Move the PiP window to an unsaved location + let left = 100; + let top = 100; + pipWin.moveTo(left, top); + + await BrowserTestUtils.waitForCondition( + () => pipWin.screenLeft === 100 && pipWin.screenTop === 100, + "Waiting for PiP to move to 100, 100" + ); + + let width = 640; + let height = 360; + + let resizePromise = BrowserTestUtils.waitForEvent(pipWin, "resize"); + pipWin.resizeTo(width, height); + await resizePromise; + + Assert.equal( + resizeEventArray.length, + 1, + "resizeEventArray should have 1 event" + ); + + let actualEvent = resizeEventArray.splice(0, 1)[0]; + let expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned before fullscreen" + ); + + await promiseFullscreenEntered(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.equal( + pipWin.document.fullscreenElement, + pipWin.document.body, + "Double-click caused us to enter fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length === 1, + "Waiting for resizeEventArray to have 1 event" + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { + width: screen.width, + height: screen.height, + left: screen.left, + top: screen.top, + }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly fullscreened before switching source" + ); + + await promiseFullscreenExited(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.ok( + !pipWin.document.fullscreenElement, + "Double-click caused us to exit fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length >= 1, + "Waiting for resizeEventArray to have 1 event, got " + + resizeEventArray.length + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned after exiting fullscreen" + ); + + await ensureMessageAndClosePiP(browser, "no-controls", pipWin, false); + + clearSavedPosition(); + } + ); +}); + +/** + * This function tests changing the src of a Picture-in-Picture player while + * the player is fullscreened and then ensuring the that video stays + * fullscreened after the src change and that the player will resize to the new + * video size. + */ +add_task(async function testChangingSameSizeVideoSrcFullscreen() { + // After opening the PiP window, it is resized to 640x360. There is a change + // the PiP window will open with that size. To prevent that we override the + // last saved position so we open at (0, 0) and 300x300. + overrideSavedPosition(0, 0, 300, 300); + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + await ensureVideosReady(browser); + let pipWin = await triggerPictureInPicture(browser, "no-controls"); + let controls = pipWin.document.getElementById("controls"); + const screen = pipWin.screen; + let sandbox = sinon.createSandbox(); + let resizeToVideoSpy = sandbox.spy(pipWin, "resizeToVideo"); + + let resizeEventArray = []; + pipWin.addEventListener("resize", event => { + let win = event.target; + let obj = { + width: win.innerWidth, + height: win.innerHeight, + left: win.screenLeft, + top: win.screenTop, + }; + resizeEventArray.push(obj); + }); + + // Move the PiP window to an unsaved location + let left = 100; + let top = 100; + pipWin.moveTo(left, top); + + await BrowserTestUtils.waitForCondition( + () => pipWin.screenLeft === 100 && pipWin.screenTop === 100, + "Waiting for PiP to move to 100, 100" + ); + + let width = 640; + let height = 360; + + let resizePromise = BrowserTestUtils.waitForEvent(pipWin, "resize"); + pipWin.resizeTo(width, height); + await resizePromise; + + Assert.equal( + resizeEventArray.length, + 1, + "resizeEventArray should have 1 event" + ); + + let actualEvent = resizeEventArray.splice(0, 1)[0]; + let expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned before fullscreen" + ); + + await promiseFullscreenEntered(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.equal( + pipWin.document.fullscreenElement, + pipWin.document.body, + "Double-click caused us to enter fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length === 1, + "Waiting for resizeEventArray to have 1 event" + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { + width: screen.width, + height: screen.height, + left: screen.left, + top: screen.top, + }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly fullscreened before switching source" + ); + + await switchVideoSource(browser, "test-video.mp4"); + + await BrowserTestUtils.waitForCondition( + () => resizeToVideoSpy.calledOnce, + "Waiting for deferredResize to be updated" + ); + + await promiseFullscreenExited(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.ok( + !pipWin.document.fullscreenElement, + "Double-click caused us to exit fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length >= 1, + "Waiting for resizeEventArray to have 1 event, got " + + resizeEventArray.length + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned after exiting fullscreen" + ); + + sandbox.restore(); + await ensureMessageAndClosePiP(browser, "no-controls", pipWin, false); + + clearSavedPosition(); + } + ); +}); + +/** + * This is similar to the previous test but in this test we switch to a video + * with a different aspect ratio to confirm that the PiP window will take the + * new aspect ratio after exiting fullscreen. We also exit fullscreen with the + * escape key instead of double clicking in this test. + */ +add_task(async function testChangingDifferentSizeVideoSrcFullscreen() { + // After opening the PiP window, it is resized to 640x360. There is a change + // the PiP window will open with that size. To prevent that we override the + // last saved position so we open at (0, 0) and 300x300. + overrideSavedPosition(0, 0, 300, 300); + await BrowserTestUtils.withNewTab( + { + url: TEST_PAGE, + gBrowser, + }, + async browser => { + await ensureVideosReady(browser); + let pipWin = await triggerPictureInPicture(browser, "no-controls"); + let controls = pipWin.document.getElementById("controls"); + const screen = pipWin.screen; + let sandbox = sinon.createSandbox(); + let resizeToVideoSpy = sandbox.spy(pipWin, "resizeToVideo"); + + let resizeEventArray = []; + pipWin.addEventListener("resize", event => { + let win = event.target; + let obj = { + width: win.innerWidth, + height: win.innerHeight, + left: win.screenLeft, + top: win.screenTop, + }; + resizeEventArray.push(obj); + }); + + // Move the PiP window to an unsaved location + let left = 100; + let top = 100; + pipWin.moveTo(left, top); + + await BrowserTestUtils.waitForCondition( + () => pipWin.screenLeft === 100 && pipWin.screenTop === 100, + "Waiting for PiP to move to 100, 100" + ); + + let width = 640; + let height = 360; + + let resizePromise = BrowserTestUtils.waitForEvent(pipWin, "resize"); + pipWin.resizeTo(width, height); + await resizePromise; + + Assert.equal( + resizeEventArray.length, + 1, + "resizeEventArray should have 1 event" + ); + + let actualEvent = resizeEventArray.splice(0, 1)[0]; + let expectedEvent = { width, height, left, top }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned before fullscreen" + ); + + await promiseFullscreenEntered(pipWin, async () => { + EventUtils.sendMouseEvent( + { + type: "dblclick", + }, + controls, + pipWin + ); + }); + + Assert.equal( + pipWin.document.fullscreenElement, + pipWin.document.body, + "Double-click caused us to enter fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length === 1, + "Waiting for resizeEventArray to have 1 event" + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { + width: screen.width, + height: screen.height, + left: screen.left, + top: screen.top, + }; + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly fullscreened before switching source" + ); + + let previousWidth = pipWin.getDeferredResize().width; + + await switchVideoSource(browser, "test-video-long.mp4"); + + // Confirm that we are updating the `deferredResize` and not actually resizing + await BrowserTestUtils.waitForCondition( + () => resizeToVideoSpy.calledOnce, + "Waiting for deferredResize to be updated" + ); + + // Confirm that we updated the deferredResize to the new width + await BrowserTestUtils.waitForCondition( + () => previousWidth !== pipWin.getDeferredResize().width, + "Waiting for deferredResize to update" + ); + + await promiseFullscreenExited(pipWin, async () => { + EventUtils.synthesizeKey("KEY_Escape", {}, pipWin); + }); + + Assert.ok( + !pipWin.document.fullscreenElement, + "Escape key caused us to exit fullscreen." + ); + + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length >= 1, + "Waiting for resizeEventArray to have 1 event, got " + + resizeEventArray.length + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + expectedEvent = { + width: height * NEW_VIDEO_ASPECT_RATIO, + height, + left, + top, + }; + + // When two resize events happen very close together we optimize by + // "coalescing" the two resizes into a single resize event. Sometimes + // the events aren't "coalesced" together (I don't know why) so I check + // if the most recent event is what we are looking for and if it is not + // then I'll wait for the resize event we are looking for. + if ( + Math.abs( + actualEvent.width - expectedEvent.width <= ACCEPTABLE_DIFFERENCE + ) + ) { + // The exit fullscreen resize events were "coalesced". + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned after exiting fullscreen" + ); + } else { + // For some reason the exit fullscreen resize events weren't "coalesced" + // so we have to wait for the next resize event. + await BrowserTestUtils.waitForCondition( + () => resizeEventArray.length === 1, + "Waiting for resizeEventArray to have 1 event" + ); + + actualEvent = resizeEventArray.splice(0, 1)[0]; + + assertEvent( + actualEvent, + expectedEvent, + "The PiP window has been correctly positioned after exiting fullscreen" + ); + } + + sandbox.restore(); + await ensureMessageAndClosePiP(browser, "no-controls", pipWin, false); + + clearSavedPosition(); + } + ); +}); |