Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
/**
* Tests that we apply dark theme variants to PBM windows where applicable.
*/
const { BuiltInThemes } = ChromeUtils.importESModule(
"resource:///modules/BuiltInThemes.sys.mjs"
);
const { PromptTestUtils } = ChromeUtils.importESModule(
);
const LIGHT_THEME_ID = "firefox-compact-light@mozilla.org";
const DARK_THEME_ID = "firefox-compact-dark@mozilla.org";
// This tests opens many chrome windows which is slow on debug builds.
requestLongerTimeout(2);
async function testIsDark(win, expectDark) {
let mql = win.matchMedia("(prefers-color-scheme: dark)");
if (mql.matches != expectDark) {
// The color scheme change might not have been processed yet, since that
// happens on a refresh driver tick.
await new Promise(r => mql.addEventListener("change", r, { once: true }));
}
is(
mql.matches,
expectDark,
`Window should${expectDark ? "" : " not"} be dark.`
);
}
/**
* Test a window's theme color scheme.
*
* @param {*} options - Test options.
* @param {Window} options.win - Window object to test.
* @param {boolean} options.colorScheme - Whether expected chrome color scheme
* is dark (true) or light (false).
* @param {boolean} options.expectLWTAttributes - Whether the window should
* have the LWT attributes set matching the color scheme.
*/
async function testWindowColorScheme({ win, expectDark, expectLWTAttributes }) {
let docEl = win.document.documentElement;
await testIsDark(win, expectDark);
if (expectLWTAttributes) {
ok(docEl.hasAttribute("lwtheme"), "Window should have LWT attribute.");
is(
docEl.getAttribute("lwtheme-brighttext"),
expectDark ? "true" : null,
"LWT text color attribute should be set."
);
} else {
ok(!docEl.hasAttribute("lwtheme"), "Window should not have LWT attribute.");
ok(
!docEl.hasAttribute("lwtheme-brighttext"),
"LWT text color attribute should not be set."
);
}
}
/**
* Match the prefers-color-scheme media query and return the results.
*
* @param {object} options
* @param {Window} options.win - If chrome=true, window to test, otherwise
* parent window of the content window to test.
* @param {boolean} options.chrome - If true the media queries will be matched
* against the supplied chrome window. Otherwise they will be matched against
* the content window.
* @returns {Promise<{light: boolean, dark: boolean}>} - Resolves with an
* object of the media query results.
*/
function getPrefersColorSchemeInfo({ win, chrome = false }) {
let fn = async windowObj => {
// If called in the parent, we use the supplied win object. Otherwise use
// the content window global.
let win = windowObj || content;
// LookAndFeel updates are async.
await new Promise(resolve => {
win.requestAnimationFrame(() => win.requestAnimationFrame(resolve));
});
return {
light: win.matchMedia("(prefers-color-scheme: light)").matches,
dark: win.matchMedia("(prefers-color-scheme: dark)").matches,
};
};
if (chrome) {
return fn(win);
}
return SpecialPowers.spawn(win.gBrowser.selectedBrowser, [], fn);
}
add_setup(async function () {
// Set system theme to light to ensure consistency across test machines.
await SpecialPowers.pushPrefEnv({
set: [
["browser.theme.dark-private-windows", true],
["ui.systemUsesDarkTheme", 0],
],
});
// Ensure the built-in themes are initialized.
await BuiltInThemes.ensureBuiltInThemes();
// The previous test, browser_ext_themes_ntp_colors.js has side effects.
// Switch to a theme, then switch back to the default theme to reach a
// consistent themeData state. Without this, themeData in
// LightWeightConsumer#_update does not contain darkTheme data and PBM windows
// don't get themed correctly.
let lightTheme = await AddonManager.getAddonByID(LIGHT_THEME_ID);
await lightTheme.enable();
await lightTheme.disable();
});
// For the default theme with light color scheme, private browsing windows
// should be themed dark.
// The PBM window's content should not be themed dark.
add_task(async function test_default_theme_light() {
info("Normal browsing window should not be in dark mode.");
await testWindowColorScheme({
win: window,
expectDark: false,
expectLWTAttributes: false,
});
let windowB = await BrowserTestUtils.openNewBrowserWindow();
info("Additional normal browsing window should not be in dark mode.");
await testWindowColorScheme({
win: windowB,
expectDark: false,
expectLWTAttributes: false,
});
let pbmWindowA = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
info("Private browsing window should be in dark mode.");
await testWindowColorScheme({
win: pbmWindowA,
expectDark: true,
expectLWTAttributes: true,
});
let prefersColorScheme = await getPrefersColorSchemeInfo({ win: pbmWindowA });
ok(
prefersColorScheme.light && !prefersColorScheme.dark,
"Content of dark themed PBM window should still be themed light"
);
let pbmWindowB = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
info("Additional private browsing window should be in dark mode.");
await testWindowColorScheme({
win: pbmWindowB,
expectDark: true,
expectLWTAttributes: true,
});
await BrowserTestUtils.closeWindow(windowB);
await BrowserTestUtils.closeWindow(pbmWindowA);
await BrowserTestUtils.closeWindow(pbmWindowB);
});
// For the default theme with dark color scheme, normal and private browsing
// windows should be themed dark.
add_task(async function test_default_theme_dark() {
// Set the system theme to dark. The default theme will follow this color
// scheme.
await SpecialPowers.pushPrefEnv({ set: [["ui.systemUsesDarkTheme", 1]] });
info("Normal browsing window should be in dark mode.");
await testWindowColorScheme({
win: window,
expectDark: true,
expectLWTAttributes: false,
});
let pbmWindow = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
info("Private browsing window should be in dark mode.");
await testWindowColorScheme({
win: pbmWindow,
expectDark: true,
expectLWTAttributes: false,
});
await BrowserTestUtils.closeWindow(pbmWindow);
await SpecialPowers.popPrefEnv();
});
// For the light theme both normal and private browsing windows should have a
// bright color scheme applied.
add_task(async function test_light_theme_builtin() {
let lightTheme = await AddonManager.getAddonByID(LIGHT_THEME_ID);
await lightTheme.enable();
info("Normal browsing window should not be in dark mode.");
await testWindowColorScheme({
win: window,
expectDark: false,
expectLWTAttributes: true,
});
let pbmWindow = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
info("Private browsing window should not be in dark mode.");
await testWindowColorScheme({
win: pbmWindow,
expectDark: false,
expectLWTAttributes: true,
});
await BrowserTestUtils.closeWindow(pbmWindow);
await lightTheme.disable();
});
// For the dark theme both normal and private browsing should have a dark color
// scheme applied.
add_task(async function test_dark_theme_builtin() {
let darkTheme = await AddonManager.getAddonByID(DARK_THEME_ID);
await darkTheme.enable();
info("Normal browsing window should be in dark mode.");
await testWindowColorScheme({
win: window,
expectDark: true,
expectLWTAttributes: true,
});
let pbmWindow = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
info("Private browsing window should be in dark mode.");
await testWindowColorScheme({
win: pbmWindow,
expectDark: true,
expectLWTAttributes: true,
});
await BrowserTestUtils.closeWindow(pbmWindow);
await darkTheme.disable();
});
// When switching between default, light and dark theme the private browsing
// window color scheme should update accordingly.
add_task(async function test_theme_switch_updates_existing_pbm_win() {
let windowB = await BrowserTestUtils.openNewBrowserWindow();
let pbmWindow = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
info("Normal browsing window should not be in dark mode.");
await testWindowColorScheme({
win: window,
expectDark: false,
expectLWTAttributes: false,
});
info("Private browsing window should be in dark mode.");
await testWindowColorScheme({
win: pbmWindow,
expectDark: true,
expectLWTAttributes: true,
});
info("Enabling light theme.");
let lightTheme = await AddonManager.getAddonByID(LIGHT_THEME_ID);
await lightTheme.enable();
info("Normal browsing window should not be in dark mode.");
await testWindowColorScheme({
win: window,
expectDark: false,
expectLWTAttributes: true,
});
info("Private browsing window should not be in dark mode.");
await testWindowColorScheme({
win: pbmWindow,
expectDark: false,
expectLWTAttributes: true,
});
await lightTheme.disable();
info("Enabling dark theme.");
let darkTheme = await AddonManager.getAddonByID(DARK_THEME_ID);
await darkTheme.enable();
info("Normal browsing window should be in dark mode.");
await testWindowColorScheme({
win: window,
expectDark: true,
expectLWTAttributes: true,
});
info("Private browsing window should be in dark mode.");
await testWindowColorScheme({
win: pbmWindow,
expectDark: true,
expectLWTAttributes: true,
});
await darkTheme.disable();
await BrowserTestUtils.closeWindow(windowB);
await BrowserTestUtils.closeWindow(pbmWindow);
});
// pageInfo windows should inherit the PBM window dark theme.
add_task(async function test_pbm_dark_page_info() {
for (let isPBM of [false, true]) {
let win = await BrowserTestUtils.openNewBrowserWindow({
private: isPBM,
});
let windowTypeStr = isPBM ? "private" : "normal";
info(`Opening pageInfo from ${windowTypeStr} browsing.`);
await BrowserTestUtils.withNewTab(
{ gBrowser: win.gBrowser, url: "https://example.com" },
async () => {
let pageInfo = win.BrowserCommands.pageInfo(null, "securityTab");
await BrowserTestUtils.waitForEvent(pageInfo, "page-info-init");
let prefersColorScheme = await getPrefersColorSchemeInfo({
win: pageInfo,
chrome: true,
});
if (isPBM) {
ok(
!prefersColorScheme.light && prefersColorScheme.dark,
"pageInfo from private window should be themed dark."
);
} else {
ok(
prefersColorScheme.light && !prefersColorScheme.dark,
"pageInfo from normal window should be themed light."
);
}
pageInfo.close();
}
);
await BrowserTestUtils.closeWindow(win);
}
});
// Prompts should inherit the PBM window dark theme.
add_task(async function test_pbm_dark_prompts() {
const { MODAL_TYPE_TAB, MODAL_TYPE_CONTENT } = Services.prompt;
for (let isPBM of [false, true]) {
let win = await BrowserTestUtils.openNewBrowserWindow({
private: isPBM,
});
// TODO: Once Bug 1751953 has been fixed, we can also test MODAL_TYPE_WINDOW
// here.
for (let modalType of [MODAL_TYPE_TAB, MODAL_TYPE_CONTENT]) {
let windowTypeStr = isPBM ? "private" : "normal";
let modalTypeStr = modalType == MODAL_TYPE_TAB ? "tab" : "content";
info(`Opening ${modalTypeStr} prompt from ${windowTypeStr} browsing.`);
let openPromise = PromptTestUtils.waitForPrompt(
win.gBrowser.selectedBrowser,
{
modalType,
promptType: "alert",
}
);
let promptPromise = Services.prompt.asyncAlert(
win.gBrowser.selectedBrowser.browsingContext,
modalType,
"Hello",
"Hello, world!"
);
let dialog = await openPromise;
let prefersColorScheme = await getPrefersColorSchemeInfo({
win: dialog.ui.prompt,
chrome: true,
});
if (isPBM) {
ok(
!prefersColorScheme.light && prefersColorScheme.dark,
"Prompt from private window should be themed dark."
);
} else {
ok(
prefersColorScheme.light && !prefersColorScheme.dark,
"Prompt from normal window should be themed light."
);
}
await PromptTestUtils.handlePrompt(dialog);
await promptPromise;
}
await BrowserTestUtils.closeWindow(win);
}
});