/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; /** * This test file checks that our en-US builds use APA-style Title Case strings * where appropriate. */ // MINOR_WORDS are words that are okay to not be capitalized when they're // mid-string. // // Source: https://apastyle.apa.org/style-grammar-guidelines/capitalization/title-case const MINOR_WORDS = [ "a", "an", "and", "as", "at", "but", "by", "for", "if", "in", "nor", "of", "off", "on", "or", "per", "so", "the", "to", "up", "via", "yet", ]; /** * Returns a generator that will yield all of the * beneath elements within a given . Each * will have the "popupshowing" and "popupshown" * event fired on them to give them an opportunity to fully populate * themselves before being yielded. * * @generator * @param {} menubar The to get s * for. * @yields {} The next under the . */ async function* iterateMenuPopups(menubar) { let menus = menubar.querySelectorAll("menu"); for (let menu of menus) { for (let menupopup of menu.querySelectorAll("menupopup")) { // We fake the popupshowing and popupshown events to give the menupopups // an opportunity to fully populate themselves. We don't actually open // the menupopups because this is not possible on macOS. menupopup.dispatchEvent( new MouseEvent("popupshowing", { bubbles: true }) ); menupopup.dispatchEvent(new MouseEvent("popupshown", { bubbles: true })); yield menupopup; // Just for good measure, we'll fire the popuphiding/popuphidden events // after we close the menupopups. menupopup.dispatchEvent(new MouseEvent("popuphiding", { bubbles: true })); menupopup.dispatchEvent(new MouseEvent("popuphidden", { bubbles: true })); } } } /** * Given a , checks all of the child elements with label * properties to see if those labels are Title Cased. Skips any elements that * have an empty or undefined label property. * * @param {} menupopup The to check. */ function checkMenuItems(menupopup) { info("Checking menupopup with id " + menupopup.id); for (let child of menupopup.children) { if (child.label) { info("Checking menupopup child with id " + child.id); checkTitleCase(child.label, child.id); } } } /** * Given a string, checks that the string is in Title Case. * * @param {String} string The string to check. * @param {String} elementID The ID of the element associated with the string. * This is included in the assertion message. */ function checkTitleCase(string, elementID) { if (!string || !elementID /* document this */) { return; } let words = string.trim().split(/\s+/); // We extract the first word, and always expect it to be capitalized, // even if it's a short word like one of MINOR_WORDS. let firstWord = words.shift(); let result = hasExpectedCapitalization(firstWord, true); if (result) { for (let word of words) { if (word) { let expectCapitalized = !MINOR_WORDS.includes(word); result = hasExpectedCapitalization(word, expectCapitalized); if (!result) { break; } } } } Assert.ok(result, `${string} for ${elementID} should have Title Casing.`); } /** * On Windows, macOS and GTK/KDE Linux, menubars are expected to be in Title * Case in order to feel native. This test iterates the menuitem labels of the * main menubar to ensure the en-US strings are all in Title Case. * * We use APA-style Title Case for the menubar, rather than Photon-style Title * Case (https://design.firefox.com/photon/copy/capitalization.html) to match * the native platform conventions. */ add_task(async function apa_test_title_case_menubar() { let newWin = await BrowserTestUtils.openNewBrowserWindow(); let menuToolbar = newWin.document.getElementById("main-menubar"); for await (const menupopup of iterateMenuPopups(menuToolbar)) { checkMenuItems(menupopup); } await BrowserTestUtils.closeWindow(newWin); }); /** * This test iterates the menuitem labels of the macOS dock menu for the * application to ensure the en-US strings are all in Title Case. */ add_task(async function apa_test_title_case_macos_dock_menu() { if (AppConstants.platform != "macosx") { return; } let hiddenWindow = Services.appShell.hiddenDOMWindow; Assert.ok(hiddenWindow, "Could get at hidden window"); let menupopup = hiddenWindow.document.getElementById("menu_mac_dockmenu"); checkMenuItems(menupopup); });