456 lines
13 KiB
JavaScript
456 lines
13 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const { TelemetryTestUtils } = ChromeUtils.importESModule(
|
|
"resource://testing-common/TelemetryTestUtils.sys.mjs"
|
|
);
|
|
|
|
const { ASRouter } = ChromeUtils.importESModule(
|
|
"resource:///modules/asrouter/ASRouter.sys.mjs"
|
|
);
|
|
|
|
const PIP_URLBAR_EVENTS = [
|
|
{
|
|
category: "pictureinpicture",
|
|
method: "opened_method",
|
|
object: "urlBar",
|
|
},
|
|
];
|
|
|
|
const PIP_DISABLED_EVENTS = [
|
|
{
|
|
category: "pictureinpicture",
|
|
method: "opened_method",
|
|
object: "urlBar",
|
|
extra: { disableDialog: "true" },
|
|
},
|
|
{
|
|
category: "pictureinpicture",
|
|
method: "disrespect_disable",
|
|
object: "urlBar",
|
|
},
|
|
];
|
|
|
|
const FIRST_TOGGLE_AFTER_CALLOUT_EXPECTED_EVENTS = [
|
|
{
|
|
category: "pictureinpicture",
|
|
method: "opened_method",
|
|
object: "urlBar",
|
|
extra: { firstTimeToggle: "true", callout: "true" },
|
|
},
|
|
];
|
|
|
|
add_task(async function test_urlbar_toggle_multiple_contexts() {
|
|
await BrowserTestUtils.withNewTab(
|
|
{
|
|
url: TEST_PAGE_MULTIPLE_CONTEXTS,
|
|
gBrowser,
|
|
},
|
|
async browser => {
|
|
Services.telemetry.clearEvents();
|
|
await ensureVideosReady(browser);
|
|
await ensureVideosReady(browser.browsingContext.children[0]);
|
|
|
|
await TestUtils.waitForCondition(
|
|
() =>
|
|
PictureInPicture.getEligiblePipVideoCount(browser).totalPipCount ===
|
|
2,
|
|
"Waiting for videos to register"
|
|
);
|
|
|
|
let { totalPipCount } =
|
|
PictureInPicture.getEligiblePipVideoCount(browser);
|
|
is(totalPipCount, 2, "Total PiP count is 2");
|
|
|
|
let pipUrlbarToggle = document.getElementById(
|
|
"picture-in-picture-button"
|
|
);
|
|
ok(
|
|
BrowserTestUtils.isHidden(pipUrlbarToggle),
|
|
"PiP urlbar toggle is hidden because there is more than 1 video"
|
|
);
|
|
|
|
// Remove one video from page so urlbar toggle will show
|
|
await SpecialPowers.spawn(browser, [], async () => {
|
|
let video = content.document.getElementById("with-controls");
|
|
video.remove();
|
|
});
|
|
|
|
await BrowserTestUtils.waitForMutationCondition(
|
|
pipUrlbarToggle,
|
|
{ attributeFilter: ["hidden"] },
|
|
() => BrowserTestUtils.isVisible(pipUrlbarToggle)
|
|
);
|
|
|
|
ok(
|
|
BrowserTestUtils.isVisible(pipUrlbarToggle),
|
|
"PiP urlbar toggle is visible"
|
|
);
|
|
|
|
({ totalPipCount } = PictureInPicture.getEligiblePipVideoCount(browser));
|
|
is(totalPipCount, 1, "Total PiP count is 1");
|
|
|
|
let domWindowOpened = BrowserTestUtils.domWindowOpenedAndLoaded(null);
|
|
pipUrlbarToggle.click();
|
|
let win = await domWindowOpened;
|
|
ok(win, "A Picture-in-Picture window opened.");
|
|
|
|
await assertVideoIsBeingCloned(
|
|
browser.browsingContext.children[0],
|
|
"video"
|
|
);
|
|
|
|
let filter = {
|
|
category: "pictureinpicture",
|
|
method: "opened_method",
|
|
object: "urlBar",
|
|
};
|
|
await waitForTelemeryEvents(filter, PIP_URLBAR_EVENTS.length, "content");
|
|
|
|
TelemetryTestUtils.assertEvents(PIP_URLBAR_EVENTS, filter, {
|
|
clear: true,
|
|
process: "content",
|
|
});
|
|
|
|
let domWindowClosed = BrowserTestUtils.domWindowClosed(win);
|
|
pipUrlbarToggle.click();
|
|
await domWindowClosed;
|
|
|
|
await SpecialPowers.spawn(browser, [], async () => {
|
|
let iframe = content.document.getElementById("iframe");
|
|
iframe.remove();
|
|
});
|
|
|
|
await BrowserTestUtils.waitForMutationCondition(
|
|
pipUrlbarToggle,
|
|
{ attributeFilter: ["hidden"] },
|
|
() => BrowserTestUtils.isHidden(pipUrlbarToggle)
|
|
);
|
|
|
|
ok(
|
|
BrowserTestUtils.isHidden(pipUrlbarToggle),
|
|
"PiP urlbar toggle is hidden because there are no videos on the page"
|
|
);
|
|
|
|
({ totalPipCount } = PictureInPicture.getEligiblePipVideoCount(browser));
|
|
is(totalPipCount, 0, "Total PiP count is 0");
|
|
}
|
|
);
|
|
});
|
|
|
|
add_task(async function test_urlbar_toggle_switch_tabs() {
|
|
await BrowserTestUtils.withNewTab(
|
|
{
|
|
url: TEST_PAGE_TRANSPARENT_NESTED_IFRAMES,
|
|
gBrowser,
|
|
},
|
|
async browser => {
|
|
await ensureVideosReady(browser);
|
|
|
|
await TestUtils.waitForCondition(
|
|
() =>
|
|
PictureInPicture.getEligiblePipVideoCount(browser).totalPipCount ===
|
|
1,
|
|
"Waiting for video to register"
|
|
);
|
|
|
|
let { totalPipCount } =
|
|
PictureInPicture.getEligiblePipVideoCount(browser);
|
|
is(totalPipCount, 1, "Total PiP count is 1");
|
|
|
|
let pipUrlbarToggle = document.getElementById(
|
|
"picture-in-picture-button"
|
|
);
|
|
ok(
|
|
BrowserTestUtils.isVisible(pipUrlbarToggle),
|
|
"PiP urlbar toggle is visible because there is 1 video"
|
|
);
|
|
|
|
let pipActivePromise = BrowserTestUtils.waitForMutationCondition(
|
|
pipUrlbarToggle,
|
|
{ attributeFilter: ["pipactive"] },
|
|
() => pipUrlbarToggle.hasAttribute("pipactive")
|
|
);
|
|
|
|
let domWindowOpened = BrowserTestUtils.domWindowOpenedAndLoaded(null);
|
|
pipUrlbarToggle.click();
|
|
let win = await domWindowOpened;
|
|
ok(win, "A Picture-in-Picture window opened.");
|
|
|
|
await assertVideoIsBeingCloned(browser, "video");
|
|
|
|
await pipActivePromise;
|
|
|
|
ok(
|
|
pipUrlbarToggle.hasAttribute("pipactive"),
|
|
"We are PiP'd in this tab so the icon is active"
|
|
);
|
|
|
|
let newTab = BrowserTestUtils.addTab(
|
|
gBrowser,
|
|
TEST_PAGE_TRANSPARENT_NESTED_IFRAMES
|
|
);
|
|
await BrowserTestUtils.browserLoaded(newTab.linkedBrowser);
|
|
|
|
await BrowserTestUtils.switchTab(gBrowser, newTab);
|
|
|
|
await BrowserTestUtils.waitForMutationCondition(
|
|
pipUrlbarToggle,
|
|
{ attributeFilter: ["pipactive"] },
|
|
() => !pipUrlbarToggle.hasAttribute("pipactive")
|
|
);
|
|
|
|
ok(
|
|
!pipUrlbarToggle.hasAttribute("pipactive"),
|
|
"After switching tabs the pip icon is not active"
|
|
);
|
|
|
|
BrowserTestUtils.removeTab(newTab);
|
|
|
|
await ensureMessageAndClosePiP(
|
|
browser,
|
|
"video-transparent-background",
|
|
win,
|
|
false
|
|
);
|
|
}
|
|
);
|
|
});
|
|
|
|
add_task(async function test_pipDisabled() {
|
|
await BrowserTestUtils.withNewTab(
|
|
{
|
|
url: TEST_PAGE_PIP_DISABLED,
|
|
gBrowser,
|
|
},
|
|
async browser => {
|
|
Services.telemetry.clearEvents();
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [
|
|
[
|
|
"media.videocontrols.picture-in-picture.respect-disablePictureInPicture",
|
|
true,
|
|
],
|
|
],
|
|
});
|
|
|
|
const VIDEO_ID = "with-controls";
|
|
await ensureVideosReady(browser);
|
|
|
|
await TestUtils.waitForCondition(
|
|
() =>
|
|
PictureInPicture.getEligiblePipVideoCount(browser).totalPipCount ===
|
|
1,
|
|
"Waiting for video to register"
|
|
);
|
|
|
|
let { totalPipCount, totalPipDisabled } =
|
|
PictureInPicture.getEligiblePipVideoCount(browser);
|
|
is(totalPipCount, 1, "Total PiP count is 1");
|
|
is(totalPipDisabled, 1, "PiP is disabled on 1 video");
|
|
|
|
// Confirm that the toggle is hidden because we are respecting disablePictureInPicture
|
|
await testToggleHelper(browser, VIDEO_ID, false);
|
|
|
|
let pipUrlbarToggle = document.getElementById(
|
|
"picture-in-picture-button"
|
|
);
|
|
ok(
|
|
BrowserTestUtils.isVisible(pipUrlbarToggle),
|
|
"PiP urlbar toggle is visible because PiP is disabled"
|
|
);
|
|
|
|
pipUrlbarToggle.click();
|
|
|
|
let panel = browser.ownerDocument.querySelector("#PictureInPicturePanel");
|
|
await BrowserTestUtils.waitForCondition(async () => {
|
|
if (!panel) {
|
|
panel = browser.ownerDocument.querySelector("#PictureInPicturePanel");
|
|
}
|
|
return BrowserTestUtils.isVisible(panel);
|
|
});
|
|
|
|
let respectPipDisableSwitch = panel.querySelector(
|
|
"#respect-pipDisabled-switch"
|
|
);
|
|
ok(
|
|
!respectPipDisableSwitch.pressed,
|
|
"Respect PiP disabled is not pressed"
|
|
);
|
|
|
|
EventUtils.synthesizeMouseAtCenter(respectPipDisableSwitch.buttonEl, {});
|
|
await BrowserTestUtils.waitForEvent(respectPipDisableSwitch, "toggle");
|
|
ok(respectPipDisableSwitch.pressed, "Respect PiP disabled is pressed");
|
|
|
|
pipUrlbarToggle.click();
|
|
|
|
await BrowserTestUtils.waitForCondition(async () => {
|
|
return BrowserTestUtils.isHidden(panel);
|
|
});
|
|
|
|
let filter = {
|
|
category: "pictureinpicture",
|
|
object: "urlBar",
|
|
};
|
|
await waitForTelemeryEvents(filter, PIP_DISABLED_EVENTS.length, "parent");
|
|
TelemetryTestUtils.assertEvents(PIP_DISABLED_EVENTS, filter, {
|
|
clear: true,
|
|
process: "parent",
|
|
});
|
|
|
|
// Confirm that the toggle is now visible because we no longer respect disablePictureInPicture
|
|
await testToggleHelper(browser, VIDEO_ID, true);
|
|
|
|
let pipActivePromise = BrowserTestUtils.waitForMutationCondition(
|
|
pipUrlbarToggle,
|
|
{ attributeFilter: ["pipactive"] },
|
|
() => pipUrlbarToggle.hasAttribute("pipactive")
|
|
);
|
|
|
|
let domWindowOpened = BrowserTestUtils.domWindowOpenedAndLoaded(null);
|
|
pipUrlbarToggle.click();
|
|
let win = await domWindowOpened;
|
|
ok(win, "A Picture-in-Picture window opened.");
|
|
|
|
await assertVideoIsBeingCloned(browser, "video");
|
|
|
|
await pipActivePromise;
|
|
|
|
ok(
|
|
pipUrlbarToggle.hasAttribute("pipactive"),
|
|
"We are PiP'd in this tab so the icon is active"
|
|
);
|
|
|
|
let domWindowClosed = BrowserTestUtils.domWindowClosed(win);
|
|
pipUrlbarToggle.click();
|
|
await domWindowClosed;
|
|
|
|
await BrowserTestUtils.waitForMutationCondition(
|
|
pipUrlbarToggle,
|
|
{ attributeFilter: ["pipactive"] },
|
|
() => !pipUrlbarToggle.hasAttribute("pipactive")
|
|
);
|
|
|
|
ok(
|
|
!pipUrlbarToggle.hasAttribute("pipactive"),
|
|
"We closed the PiP window so the urlbar button is no longer active"
|
|
);
|
|
|
|
await SpecialPowers.popPrefEnv();
|
|
}
|
|
);
|
|
});
|
|
|
|
add_task(async function test_urlbar_toggle_telemetry() {
|
|
await BrowserTestUtils.withNewTab(
|
|
{
|
|
url: TEST_PAGE_MULTIPLE_CONTEXTS,
|
|
gBrowser,
|
|
},
|
|
async browser => {
|
|
Services.telemetry.clearEvents();
|
|
await ensureVideosReady(browser);
|
|
await ensureVideosReady(browser.browsingContext.children[0]);
|
|
|
|
await TestUtils.waitForCondition(
|
|
() =>
|
|
PictureInPicture.getEligiblePipVideoCount(browser).totalPipCount ===
|
|
2,
|
|
"Waiting for videos to register"
|
|
);
|
|
|
|
let { totalPipCount } =
|
|
PictureInPicture.getEligiblePipVideoCount(browser);
|
|
is(totalPipCount, 2, "Total PiP count is 2");
|
|
|
|
let pipUrlbarToggle = document.getElementById(
|
|
"picture-in-picture-button"
|
|
);
|
|
ok(
|
|
BrowserTestUtils.isHidden(pipUrlbarToggle),
|
|
"PiP urlbar toggle is hidden because there is more than 1 video"
|
|
);
|
|
|
|
// Remove one video from page so urlbar toggle will show
|
|
await SpecialPowers.spawn(browser, [], async () => {
|
|
let video = content.document.getElementById("with-controls");
|
|
video.remove();
|
|
});
|
|
await BrowserTestUtils.waitForMutationCondition(
|
|
pipUrlbarToggle,
|
|
{ attributeFilter: ["hidden"] },
|
|
() => BrowserTestUtils.isVisible(pipUrlbarToggle)
|
|
);
|
|
ok(
|
|
BrowserTestUtils.isVisible(pipUrlbarToggle),
|
|
"PiP urlbar toggle is visible"
|
|
);
|
|
|
|
// open for first time after seeing feature callout message
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [
|
|
[
|
|
"media.videocontrols.picture-in-picture.video-toggle.has-used",
|
|
false,
|
|
],
|
|
],
|
|
});
|
|
let fakeMessage = {
|
|
template: "feature_callout",
|
|
id: "FAKE_PIP_FEATURE_CALLOUT",
|
|
content: {
|
|
screens: [{ anchors: [{ selector: "#picture-in-picture-button" }] }],
|
|
},
|
|
};
|
|
await ASRouter.waitForInitialized;
|
|
let originalASRouterState;
|
|
await ASRouter.setState(state => {
|
|
originalASRouterState = state;
|
|
return {
|
|
messages: [...state.messages, fakeMessage],
|
|
messageImpressions: {
|
|
...state.messageImpressions,
|
|
[fakeMessage.id]: [Date.now()],
|
|
},
|
|
};
|
|
});
|
|
|
|
({ totalPipCount } = PictureInPicture.getEligiblePipVideoCount(browser));
|
|
is(totalPipCount, 1, "Total PiP count is 1");
|
|
|
|
let domWindowOpened = BrowserTestUtils.domWindowOpenedAndLoaded(null);
|
|
pipUrlbarToggle.click();
|
|
let win = await domWindowOpened;
|
|
ok(win, "A Picture-in-Picture window opened.");
|
|
await assertVideoIsBeingCloned(
|
|
browser.browsingContext.children[0],
|
|
"video"
|
|
);
|
|
|
|
let filter = {
|
|
category: "pictureinpicture",
|
|
method: "opened_method",
|
|
object: "urlBar",
|
|
};
|
|
await waitForTelemeryEvents(
|
|
filter,
|
|
FIRST_TOGGLE_AFTER_CALLOUT_EXPECTED_EVENTS.length,
|
|
"content"
|
|
);
|
|
|
|
TelemetryTestUtils.assertEvents(
|
|
FIRST_TOGGLE_AFTER_CALLOUT_EXPECTED_EVENTS,
|
|
filter,
|
|
{ clear: true, process: "content" }
|
|
);
|
|
|
|
let domWindowClosed = BrowserTestUtils.domWindowClosed(win);
|
|
pipUrlbarToggle.click();
|
|
await domWindowClosed;
|
|
|
|
await ASRouter.setState(originalASRouterState);
|
|
}
|
|
);
|
|
});
|