forked from mirrors/gecko-dev
538 lines
17 KiB
JavaScript
538 lines
17 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
/**
|
|
* Tests the warning that is displayed when switching to background
|
|
* tabs when sharing the browser window or screen
|
|
*/
|
|
|
|
// The number of tabs to have in the background for testing.
|
|
const NEW_BACKGROUND_TABS_TO_OPEN = 5;
|
|
const WARNING_PANEL_ID = "sharing-tabs-warning-panel";
|
|
const ALLOW_BUTTON_ID = "sharing-warning-proceed-to-tab";
|
|
const DISABLE_WARNING_FOR_SESSION_CHECKBOX_ID =
|
|
"sharing-warning-disable-for-session";
|
|
const WINDOW_SHARING_HEADER_ID = "sharing-warning-window-panel-header";
|
|
const SCREEN_SHARING_HEADER_ID = "sharing-warning-screen-panel-header";
|
|
// The number of milliseconds we're willing to wait for the
|
|
// warning panel before we decide that it's not coming.
|
|
const WARNING_PANEL_TIMEOUT_MS = 1000;
|
|
const CTRL_TAB_RUO_PREF = "browser.ctrlTab.sortByRecentlyUsed";
|
|
|
|
/**
|
|
* Common helper function that pretendToShareWindow and pretendToShareScreen
|
|
* call into. Ensures that the first tab is selected, and then (optionally)
|
|
* does the first "freebie" tab switch to the second tab.
|
|
*
|
|
* @param {boolean} doFirstTabSwitch - True if this function should take
|
|
* care of doing the "freebie" tab switch for you.
|
|
* @return {Promise}
|
|
* @resolves {undefined} - Once the simulation is set up.
|
|
*/
|
|
async function pretendToShareDisplay(doFirstTabSwitch) {
|
|
Assert.equal(
|
|
gBrowser.selectedTab,
|
|
gBrowser.tabs[0],
|
|
"Should start on the first tab."
|
|
);
|
|
|
|
webrtcUI.sharingDisplay = true;
|
|
if (doFirstTabSwitch) {
|
|
await BrowserTestUtils.switchTab(gBrowser, gBrowser.tabs[1]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Simulates the sharing of a particular browser window. The
|
|
* simulation doesn't actually share the window over WebRTC, but
|
|
* does enough to convince webrtcUI that the window is in the shared
|
|
* window list.
|
|
*
|
|
* It is assumed that the first tab is the selected tab when calling
|
|
* this function.
|
|
*
|
|
* This helper function can also automatically perform the first
|
|
* "freebie" tab switch that never warns. This is its default behaviour.
|
|
*
|
|
* @param {DOM Window} aWindow - The window that we're simulating sharing.
|
|
* @param {boolean} doFirstTabSwitch - True if this function should take
|
|
* care of doing the "freebie" tab switch for you. Defaults to true.
|
|
* @return {Promise}
|
|
* @resolves {undefined} - Once the simulation is set up.
|
|
*/
|
|
async function pretendToShareWindow(aWindow, doFirstTabSwitch = true) {
|
|
// Poke into webrtcUI so that it thinks that the current browser
|
|
// window is being shared.
|
|
webrtcUI.sharedBrowserWindows.add(aWindow);
|
|
await pretendToShareDisplay(doFirstTabSwitch);
|
|
}
|
|
|
|
/**
|
|
* Simulates the sharing of the screen. The simulation doesn't actually share
|
|
* the screen over WebRTC, but does enough to convince webrtcUI that the screen
|
|
* is being shared.
|
|
*
|
|
* It is assumed that the first tab is the selected tab when calling
|
|
* this function.
|
|
*
|
|
* This helper function can also automatically perform the first
|
|
* "freebie" tab switch that never warns. This is its default behaviour.
|
|
*
|
|
* @param {boolean} doFirstTabSwitch - True if this function should take
|
|
* care of doing the "freebie" tab switch for you. Defaults to true.
|
|
* @return {Promise}
|
|
* @resolves {undefined} - Once the simulation is set up.
|
|
*/
|
|
async function pretendToShareScreen(doFirstTabSwitch = true) {
|
|
// Poke into webrtcUI so that it thinks that the current screen is being
|
|
// shared.
|
|
webrtcUI.sharingScreen = true;
|
|
await pretendToShareDisplay(doFirstTabSwitch);
|
|
}
|
|
|
|
/**
|
|
* Resets webrtcUI's notion of what is being shared. This also clears
|
|
* out any simulated shared windows, and resets any state that only
|
|
* persists for a sharing session.
|
|
*
|
|
* This helper function will also:
|
|
* 1. Switch back to the first tab if it's not already selected.
|
|
* 2. Check if the tab switch warning panel is open, and if so, close it.
|
|
*
|
|
* @return {Promise}
|
|
* @resolves {undefined} - Once the state is reset.
|
|
*/
|
|
async function resetDisplaySharingState() {
|
|
let firstTabBC = gBrowser.browsers[0].browsingContext;
|
|
webrtcUI.streamAddedOrRemoved(firstTabBC, { remove: true });
|
|
|
|
if (gBrowser.selectedTab !== gBrowser.tabs[0]) {
|
|
await BrowserTestUtils.switchTab(gBrowser, gBrowser.tabs[0]);
|
|
}
|
|
|
|
let panel = document.getElementById(WARNING_PANEL_ID);
|
|
if (panel && (panel.state == "open" || panel.state == "showing")) {
|
|
info("Closing the warning panel.");
|
|
let panelHidden = BrowserTestUtils.waitForEvent(panel, "popuphidden");
|
|
panel.hidePopup();
|
|
await panelHidden;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks to make sure that a tab switch warning doesn't show
|
|
* within WARNING_PANEL_TIMEOUT_MS milliseconds.
|
|
*
|
|
* @return {Promise}
|
|
* @resolves {undefined} - Once the check is complete.
|
|
*/
|
|
async function ensureNoWarning() {
|
|
let timerExpired = false;
|
|
let sawWarning = false;
|
|
|
|
let resolver;
|
|
let timeoutOrPopupShowingPromise = new Promise(resolve => {
|
|
resolver = resolve;
|
|
});
|
|
|
|
let onPopupShowing = event => {
|
|
if (event.target.id == WARNING_PANEL_ID) {
|
|
sawWarning = true;
|
|
resolver();
|
|
}
|
|
};
|
|
// The panel might not have been lazily-inserted yet, so we
|
|
// attach the popupshowing handler to the window instead.
|
|
window.addEventListener("popupshowing", onPopupShowing);
|
|
|
|
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
|
let timer = setTimeout(() => {
|
|
timerExpired = true;
|
|
resolver();
|
|
}, WARNING_PANEL_TIMEOUT_MS);
|
|
|
|
await timeoutOrPopupShowingPromise;
|
|
|
|
clearTimeout(timer);
|
|
window.removeEventListener("popupshowing", onPopupShowing);
|
|
|
|
Assert.ok(timerExpired, "Timer should have expired.");
|
|
Assert.ok(!sawWarning, "Should not have shown the tab switch warning.");
|
|
}
|
|
|
|
/**
|
|
* Checks to make sure that a tab switch warning appears for
|
|
* a particular tab.
|
|
*
|
|
* @param {<xul:tab>} tab - The tab that the warning should be anchored to.
|
|
* @return {Promise}
|
|
* @resolves {undefined} - Once the check is complete.
|
|
*/
|
|
async function ensureWarning(tab) {
|
|
let popupShowingEvent = await BrowserTestUtils.waitForEvent(
|
|
window,
|
|
"popupshowing",
|
|
false,
|
|
event => {
|
|
return event.target.id == WARNING_PANEL_ID;
|
|
}
|
|
);
|
|
let panel = popupShowingEvent.target;
|
|
|
|
Assert.equal(
|
|
panel.anchorNode,
|
|
tab,
|
|
"Expected the warning to be anchored to the right tab."
|
|
);
|
|
}
|
|
|
|
add_setup(async function () {
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [["privacy.webrtc.sharedTabWarning", true]],
|
|
});
|
|
|
|
// Loads up NEW_BACKGROUND_TABS_TO_OPEN background tabs at about:blank,
|
|
// and waits until they're fully open.
|
|
let uris = new Array(NEW_BACKGROUND_TABS_TO_OPEN).fill("about:blank");
|
|
|
|
let loadPromises = Promise.all(
|
|
uris.map(uri => BrowserTestUtils.waitForNewTab(gBrowser, uri, false, true))
|
|
);
|
|
|
|
gBrowser.loadTabs(uris, {
|
|
inBackground: true,
|
|
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
|
});
|
|
|
|
await loadPromises;
|
|
|
|
// Switches to the first tab and closes all of the rest.
|
|
registerCleanupFunction(async () => {
|
|
await resetDisplaySharingState();
|
|
gBrowser.removeAllTabsBut(gBrowser.tabs[0]);
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Tests that when sharing the window that the first tab switch does _not_ show
|
|
* the warning. This is because we presume that the first tab switch since
|
|
* starting display sharing is for a tab that is intentionally being shared.
|
|
*/
|
|
add_task(async function testFirstTabSwitchAllowed() {
|
|
pretendToShareWindow(window, false);
|
|
|
|
let targetTab = gBrowser.tabs[1];
|
|
|
|
let noWarningPromise = ensureNoWarning();
|
|
await BrowserTestUtils.switchTab(gBrowser, targetTab);
|
|
await noWarningPromise;
|
|
|
|
await resetDisplaySharingState();
|
|
});
|
|
|
|
/**
|
|
* Tests that the second tab switch after sharing is not allowed
|
|
* without a warning. Also tests that the warning can "allow"
|
|
* the tab switch to proceed, and that no warning is subsequently
|
|
* shown for the "allowed" tab. Finally, ensures that if the sharing
|
|
* session ends and a new session begins, that warnings are shown
|
|
* again for the allowed tabs.
|
|
*/
|
|
add_task(async function testWarningOnSecondTabSwitch() {
|
|
pretendToShareWindow(window);
|
|
let originalTab = gBrowser.selectedTab;
|
|
|
|
// pretendToShareWindow will have switched us to the second
|
|
// tab automatically as the first "freebie" tab switch
|
|
|
|
let targetTab = gBrowser.tabs[2];
|
|
|
|
// Ensure that we show the warning on the second tab switch
|
|
let warningPromise = ensureWarning(targetTab);
|
|
await BrowserTestUtils.switchTab(gBrowser, targetTab);
|
|
await warningPromise;
|
|
|
|
// Not only should we have warned, but we should have prevented
|
|
// the tab switch from occurring.
|
|
Assert.equal(
|
|
gBrowser.selectedTab,
|
|
originalTab,
|
|
"Should still be on the original tab."
|
|
);
|
|
|
|
// Now test the "Allow" button in the warning to make sure the tab
|
|
// switch goes through.
|
|
let tabSwitchPromise = BrowserTestUtils.waitForEvent(
|
|
gBrowser,
|
|
"TabSwitchDone"
|
|
);
|
|
let allowButton = document.getElementById(ALLOW_BUTTON_ID);
|
|
allowButton.click();
|
|
await tabSwitchPromise;
|
|
|
|
Assert.equal(
|
|
gBrowser.selectedTab,
|
|
targetTab,
|
|
"Should have switched tabs to the target."
|
|
);
|
|
|
|
// We shouldn't see a warning when switching back to that first
|
|
// "freebie" tab.
|
|
let noWarningPromise = ensureNoWarning();
|
|
await BrowserTestUtils.switchTab(gBrowser, originalTab);
|
|
await noWarningPromise;
|
|
|
|
Assert.equal(
|
|
gBrowser.selectedTab,
|
|
originalTab,
|
|
"Should have switched tabs back to the original tab."
|
|
);
|
|
|
|
// We shouldn't see a warning when switching back to the tab that
|
|
// we had just allowed.
|
|
noWarningPromise = ensureNoWarning();
|
|
await BrowserTestUtils.switchTab(gBrowser, targetTab);
|
|
await noWarningPromise;
|
|
|
|
Assert.equal(
|
|
gBrowser.selectedTab,
|
|
targetTab,
|
|
"Should have switched tabs back to the target tab."
|
|
);
|
|
|
|
// Reset the sharing state, and make sure that warnings can
|
|
// be displayed again.
|
|
await resetDisplaySharingState();
|
|
pretendToShareWindow(window);
|
|
|
|
// pretendToShareWindow will have switched us to the second
|
|
// tab automatically as the first "freebie" tab switch
|
|
//
|
|
// Make sure we get the warning again when switching to the
|
|
// target tab.
|
|
warningPromise = ensureWarning(targetTab);
|
|
await BrowserTestUtils.switchTab(gBrowser, targetTab);
|
|
await warningPromise;
|
|
|
|
await resetDisplaySharingState();
|
|
});
|
|
|
|
/**
|
|
* Tests that warnings can be skipped for a session via the
|
|
* checkbox in the warning panel. Also checks that once the
|
|
* session ends and a new one begins that warnings are displayed
|
|
* again.
|
|
*/
|
|
add_task(async function testDisableWarningForSession() {
|
|
pretendToShareWindow(window);
|
|
|
|
// pretendToShareWindow will have switched us to the second
|
|
// tab automatically as the first "freebie" tab switch
|
|
let targetTab = gBrowser.tabs[2];
|
|
|
|
// Ensure that we show the warning on the second tab switch
|
|
let warningPromise = ensureWarning(targetTab);
|
|
await BrowserTestUtils.switchTab(gBrowser, targetTab);
|
|
await warningPromise;
|
|
|
|
// Check the checkbox to suppress warnings for the rest of this session.
|
|
let checkbox = document.getElementById(
|
|
DISABLE_WARNING_FOR_SESSION_CHECKBOX_ID
|
|
);
|
|
checkbox.checked = true;
|
|
|
|
// Now test the "Allow" button in the warning to make sure the tab
|
|
// switch goes through.
|
|
let tabSwitchPromise = BrowserTestUtils.waitForEvent(
|
|
gBrowser,
|
|
"TabSwitchDone"
|
|
);
|
|
let allowButton = document.getElementById(ALLOW_BUTTON_ID);
|
|
allowButton.click();
|
|
await tabSwitchPromise;
|
|
|
|
Assert.equal(
|
|
gBrowser.selectedTab,
|
|
targetTab,
|
|
"Should have switched tabs to the target tab."
|
|
);
|
|
|
|
// Switching to the 4th and 5th tabs should now not show warnings.
|
|
let noWarningPromise = ensureNoWarning();
|
|
await BrowserTestUtils.switchTab(gBrowser, gBrowser.tabs[3]);
|
|
await noWarningPromise;
|
|
|
|
noWarningPromise = ensureNoWarning();
|
|
await BrowserTestUtils.switchTab(gBrowser, gBrowser.tabs[4]);
|
|
await noWarningPromise;
|
|
|
|
// Reset the sharing state, and make sure that warnings can
|
|
// be displayed again.
|
|
await resetDisplaySharingState();
|
|
pretendToShareWindow(window);
|
|
|
|
// pretendToShareWindow will have switched us to the second
|
|
// tab automatically as the first "freebie" tab switch
|
|
//
|
|
// Make sure we get the warning again when switching to the
|
|
// target tab.
|
|
warningPromise = ensureWarning(targetTab);
|
|
await BrowserTestUtils.switchTab(gBrowser, targetTab);
|
|
await warningPromise;
|
|
|
|
await resetDisplaySharingState();
|
|
});
|
|
|
|
/**
|
|
* Tests that we don't show a warning when sharing a different
|
|
* window than the one we're switching tabs in.
|
|
*/
|
|
add_task(async function testOtherWindow() {
|
|
let otherWin = await BrowserTestUtils.openNewBrowserWindow();
|
|
await SimpleTest.promiseFocus(window);
|
|
pretendToShareWindow(otherWin);
|
|
|
|
// Switching to the 4th and 5th tabs should now not show warnings.
|
|
let noWarningPromise = ensureNoWarning();
|
|
await BrowserTestUtils.switchTab(gBrowser, gBrowser.tabs[3]);
|
|
await noWarningPromise;
|
|
|
|
noWarningPromise = ensureNoWarning();
|
|
await BrowserTestUtils.switchTab(gBrowser, gBrowser.tabs[4]);
|
|
await noWarningPromise;
|
|
|
|
await BrowserTestUtils.closeWindow(otherWin);
|
|
|
|
await resetDisplaySharingState();
|
|
});
|
|
|
|
/**
|
|
* Tests that we show a different label when sharing the screen
|
|
* vs when sharing a window.
|
|
*/
|
|
add_task(async function testWindowVsScreenLabel() {
|
|
pretendToShareWindow(window);
|
|
|
|
// pretendToShareWindow will have switched us to the second
|
|
// tab automatically as the first "freebie" tab switch.
|
|
// Let's now switch to the third tab.
|
|
let targetTab = gBrowser.tabs[2];
|
|
|
|
// Ensure that we show the warning on this second tab switch
|
|
let warningPromise = ensureWarning(targetTab);
|
|
await BrowserTestUtils.switchTab(gBrowser, targetTab);
|
|
await warningPromise;
|
|
|
|
let windowHeader = document.getElementById(WINDOW_SHARING_HEADER_ID);
|
|
let screenHeader = document.getElementById(SCREEN_SHARING_HEADER_ID);
|
|
Assert.ok(
|
|
!BrowserTestUtils.is_hidden(windowHeader),
|
|
"Should be showing window sharing header"
|
|
);
|
|
Assert.ok(
|
|
BrowserTestUtils.is_hidden(screenHeader),
|
|
"Should not be showing screen sharing header"
|
|
);
|
|
|
|
// Reset the sharing state, and then pretend to share the screen.
|
|
await resetDisplaySharingState();
|
|
pretendToShareScreen();
|
|
|
|
// Ensure that we show the warning on this second tab switch
|
|
warningPromise = ensureWarning(targetTab);
|
|
await BrowserTestUtils.switchTab(gBrowser, targetTab);
|
|
await warningPromise;
|
|
|
|
Assert.ok(
|
|
BrowserTestUtils.is_hidden(windowHeader),
|
|
"Should not be showing window sharing header"
|
|
);
|
|
Assert.ok(
|
|
!BrowserTestUtils.is_hidden(screenHeader),
|
|
"Should be showing screen sharing header"
|
|
);
|
|
await resetDisplaySharingState();
|
|
});
|
|
|
|
/**
|
|
* Tests that tab switching via the keyboard can also trigger the
|
|
* tab switch warnings.
|
|
*/
|
|
add_task(async function testKeyboardTabSwitching() {
|
|
let pressCtrlTab = async (expectPanel = false) => {
|
|
let promise;
|
|
if (expectPanel) {
|
|
promise = BrowserTestUtils.waitForEvent(ctrlTab.panel, "popupshown");
|
|
} else {
|
|
promise = BrowserTestUtils.waitForEvent(document, "keyup");
|
|
}
|
|
EventUtils.synthesizeKey("VK_TAB", {
|
|
ctrlKey: true,
|
|
shiftKey: false,
|
|
});
|
|
await promise;
|
|
};
|
|
|
|
let releaseCtrl = async () => {
|
|
let promise;
|
|
if (ctrlTab.isOpen) {
|
|
promise = BrowserTestUtils.waitForEvent(ctrlTab.panel, "popuphidden");
|
|
} else {
|
|
promise = BrowserTestUtils.waitForEvent(document, "keyup");
|
|
}
|
|
EventUtils.synthesizeKey("VK_CONTROL", { type: "keyup" });
|
|
return promise;
|
|
};
|
|
|
|
// Ensure that the (on by default) ctrl-tab switch panel is enabled.
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [[CTRL_TAB_RUO_PREF, true]],
|
|
});
|
|
|
|
pretendToShareWindow(window);
|
|
let originalTab = gBrowser.selectedTab;
|
|
await pressCtrlTab(true);
|
|
|
|
// The Ctrl-Tab MRU list should be:
|
|
// 0: Second tab (currently selected)
|
|
// 1: First tab
|
|
// 2: Last tab
|
|
//
|
|
// Having pressed Ctrl-Tab once, 1 (First tab) is selected in the
|
|
// panel. We want a tab that will warn, so let's hit Ctrl-Tab again
|
|
// to choose 2 (Last tab).
|
|
let targetTab = ctrlTab.tabList[2];
|
|
await pressCtrlTab();
|
|
|
|
let warningPromise = ensureWarning(targetTab);
|
|
await releaseCtrl();
|
|
await warningPromise;
|
|
|
|
// Hide the warning without allowing the tab switch.
|
|
let panel = document.getElementById(WARNING_PANEL_ID);
|
|
panel.hidePopup();
|
|
|
|
Assert.equal(
|
|
gBrowser.selectedTab,
|
|
originalTab,
|
|
"Should not have changed from the original tab."
|
|
);
|
|
|
|
// Now switch to the in-order tab switching keyboard shortcut mode.
|
|
await SpecialPowers.popPrefEnv();
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [[CTRL_TAB_RUO_PREF, false]],
|
|
});
|
|
|
|
// Hitting Ctrl-Tab should choose the _next_ tab over from
|
|
// the originalTab, which should be the third tab.
|
|
targetTab = gBrowser.tabs[2];
|
|
|
|
warningPromise = ensureWarning(targetTab);
|
|
await pressCtrlTab();
|
|
await warningPromise;
|
|
|
|
await resetDisplaySharingState();
|
|
});
|