Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
/* Any copyright is dedicated to the Public Domain.
"use strict";
const { sinon } = ChromeUtils.importESModule(
);
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.outerWidth,
height: win.outerHeight,
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.outerWidth,
height: win.outerHeight,
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.outerWidth,
height: win.outerHeight,
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();
}
);
});