From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../components/translations/tests/browser/head.js | 348 +++++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 browser/components/translations/tests/browser/head.js (limited to 'browser/components/translations/tests/browser/head.js') diff --git a/browser/components/translations/tests/browser/head.js b/browser/components/translations/tests/browser/head.js new file mode 100644 index 0000000000..56839971b7 --- /dev/null +++ b/browser/components/translations/tests/browser/head.js @@ -0,0 +1,348 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/toolkit/components/translations/tests/browser/shared-head.js", + this +); + +/** + * Assert some property about the translations button. + * + * @param {Record} visibleAssertions + * @param {string} message The message for the assertion. + * @returns {HTMLElement} + */ +async function assertTranslationsButton(visibleAssertions, message) { + const elements = { + button: document.getElementById("translations-button"), + icon: document.getElementById("translations-button-icon"), + circleArrows: document.getElementById("translations-button-circle-arrows"), + locale: document.getElementById("translations-button-locale"), + }; + + for (const [name, element] of Object.entries(elements)) { + if (!element) { + throw new Error("Could not find the " + name); + } + } + + try { + // Test that the visibilities match. + await TestUtils.waitForCondition(() => { + for (const [name, visible] of Object.entries(visibleAssertions)) { + if (elements[name].hidden === visible) { + return false; + } + } + return true; + }, message); + } catch (error) { + // On a mismatch, report it. + for (const [name, expected] of Object.entries(visibleAssertions)) { + is(!elements[name].hidden, expected, `Visibility for "${name}"`); + } + } + + ok(true, message); + + return elements; +} + +/** + * A convenience function to open the settings menu of the + * translations panel. Fails the test if the menu cannot be opened. + */ +async function openSettingsMenu() { + const { button } = await assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await waitForTranslationsPopupEvent("popupshown", () => { + click(button, "Opening the popup"); + }); + + const gearIcon = getByL10nId("translations-panel-settings-button"); + click(gearIcon, "Open the settings menu"); +} + +/** + * Simulates the effect of clicking the always-translate-language menuitem. + * Requires that the settings menu of the translations panel is open, + * otherwise the test will fail. + */ +async function toggleAlwaysTranslateLanguage() { + const alwaysTranslateLanguage = getByL10nId( + "translations-panel-settings-always-translate-language" + ); + info("Toggle the always-translate-language menuitem"); + await alwaysTranslateLanguage.doCommand(); +} + +/** + * Simulates the effect of clicking the never-translate-language menuitem. + * Requires that the settings menu of the translations panel is open, + * otherwise the test will fail. + */ +async function toggleNeverTranslateLanguage() { + const neverTranslateLanguage = getByL10nId( + "translations-panel-settings-never-translate-language" + ); + info("Toggle the never-translate-language menuitem"); + await neverTranslateLanguage.doCommand(); +} + +/** + * Simulates the effect of clicking the never-translate-site menuitem. + * Requires that the settings menu of the translations panel is open, + * otherwise the test will fail. + */ +async function toggleNeverTranslateSite() { + const neverTranslateSite = getByL10nId( + "translations-panel-settings-never-translate-site" + ); + info("Toggle the never-translate-site menuitem"); + await neverTranslateSite.doCommand(); +} + +/** + * Asserts that the always-translate-language checkbox matches the expected checked state. + * + * @param {string} langTag - A BCP-47 language tag + * @param {boolean} expectChecked - Whether the checkbox should be checked + */ +async function assertIsAlwaysTranslateLanguage(langTag, expectChecked) { + await assertCheckboxState( + "translations-panel-settings-always-translate-language", + expectChecked + ); +} + +/** + * Asserts that the never-translate-language checkbox matches the expected checked state. + * + * @param {string} langTag - A BCP-47 language tag + * @param {boolean} expectChecked - Whether the checkbox should be checked + */ +async function assertIsNeverTranslateLanguage(langTag, expectChecked) { + await assertCheckboxState( + "translations-panel-settings-never-translate-language", + expectChecked + ); +} + +/** + * Asserts that the never-translate-site checkbox matches the expected checked state. + * + * @param {string} url - The url of a website + * @param {boolean} expectChecked - Whether the checkbox should be checked + */ +async function assertIsNeverTranslateSite(url, expectChecked) { + await assertCheckboxState( + "translations-panel-settings-never-translate-site", + expectChecked + ); +} + +/** + * Asserts that the state of a checkbox with a given dataL10nId is + * checked or not, based on the value of expected being true or false. + * + * @param {string} dataL10nId - The data-l10n-id of the checkbox. + * @param {boolean} expectChecked - Whether the checkbox should be checked. + */ +async function assertCheckboxState(dataL10nId, expectChecked) { + const menuItems = getAllByL10nId(dataL10nId); + for (const menuItem of menuItems) { + await TestUtils.waitForCondition( + () => + menuItem.getAttribute("checked") === (expectChecked ? "true" : "false"), + "Waiting for checkbox state" + ); + is( + menuItem.getAttribute("checked"), + expectChecked ? "true" : "false", + `Should match expected checkbox state for ${dataL10nId}` + ); + } +} + +/** + * Navigate to a URL and indicate a message as to why. + */ +async function navigate(url, message) { + info(message); + + // Load a blank page first to ensure that tests don't hang. + // I don't know why this is needed, but it appears to be necessary. + BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, BLANK_PAGE); + await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + + BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, url); + await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); +} + +/** + * Add a tab to the page + * + * @param {string} url + */ +async function addTab(url) { + info(`Adding tab for ` + url); + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + url, + true // Wait for laod + ); + return { + tab, + removeTab() { + BrowserTestUtils.removeTab(tab); + }, + }; +} + +async function switchTab(tab) { + info("Switching tabs"); + await BrowserTestUtils.switchTab(gBrowser, tab); +} + +function click(button, message) { + info(message); + EventUtils.synthesizeMouseAtCenter(button, {}); +} + +/** + * @param {Element} element + * @returns {boolean} + */ +function isVisible(element) { + const win = element.ownerDocument.ownerGlobal; + const { visibility, display } = win.getComputedStyle(element); + return visibility === "visible" && display !== "none"; +} + +/** + * Get an element by its l10n id, as this is a user-visible way to find an element. + * The `l10nId` represents the text that a user would actually see. + * + * @param {string} l10nId + * @param {Document} doc + * @returns {Element} + */ +function getByL10nId(l10nId, doc = document) { + const elements = doc.querySelectorAll(`[data-l10n-id="${l10nId}"]`); + if (elements.length === 0) { + throw new Error("Could not find the element by l10n id: " + l10nId); + } + for (const element of elements) { + if (isVisible(element)) { + return element; + } + } + throw new Error("The element is not visible in the DOM: " + l10nId); +} + +/** + * Get all elements that match the l10n id. + * + * @param {string} l10nId + * @param {Document} doc + * @returns {Element} + */ +function getAllByL10nId(l10nId, doc = document) { + const elements = doc.querySelectorAll(`[data-l10n-id="${l10nId}"]`); + if (elements.length === 0) { + throw new Error("Could not find the element by l10n id: " + l10nId); + } + return elements; +} + +/** + * @param {string} id + * @param {Document} [doc] + * @returns {Element} + */ +function getById(id, doc = document) { + const element = doc.getElementById(id); + if (!element) { + throw new Error("Could not find the element by id: #" + id); + } + if (isVisible(element)) { + return element; + } + throw new Error("The element is not visible in the DOM: #" + id); +} + +/** + * A non-throwing version of `getByL10nId`. + * + * @param {string} l10nId + * @returns {Element | null} + */ +function maybeGetByL10nId(l10nId, doc = document) { + const selector = `[data-l10n-id="${l10nId}"]`; + const elements = doc.querySelectorAll(selector); + for (const element of elements) { + if (isVisible(element)) { + return element; + } + } + return null; +} + +/** + * XUL popups will fire the popupshown and popuphidden events. These will fire for + * any type of popup in the browser. This function waits for one of those events, and + * checks that the viewId of the popup is PanelUI-profiler + * + * @param {"popupshown" | "popuphidden"} eventName + * @param {Function} callback + * @returns {Promise} + */ +async function waitForTranslationsPopupEvent(eventName, callback) { + const panel = document.getElementById("translations-panel"); + if (!panel) { + throw new Error("Unable to find the translations panel element."); + } + const promise = BrowserTestUtils.waitForEvent(panel, eventName); + callback(); + info("Waiting for the translations panel popup to be shown"); + await promise; + // Wait a single tick on the event loop. + await new Promise(resolve => setTimeout(resolve, 0)); +} + +/** + * When switching between between views in the popup panel, wait for the view to + * be fully shown. + * + * @param {Function} callback + */ +async function waitForViewShown(callback) { + const panel = document.getElementById("translations-panel"); + if (!panel) { + throw new Error("Unable to find the translations panel element."); + } + const promise = BrowserTestUtils.waitForEvent(panel, "ViewShown"); + callback(); + info("Waiting for the translations panel view to be shown"); + await promise; + await new Promise(resolve => setTimeout(resolve, 0)); +} + +const ENGLISH_PAGE_URL = TRANSLATIONS_TESTER_EN; +const SPANISH_PAGE_URL = TRANSLATIONS_TESTER_ES; +const SPANISH_PAGE_URL_2 = TRANSLATIONS_TESTER_ES_2; +const SPANISH_PAGE_URL_DOT_ORG = TRANSLATIONS_TESTER_ES_DOT_ORG; +const LANGUAGE_PAIRS = [ + { fromLang: "es", toLang: "en", isBeta: false }, + { fromLang: "en", toLang: "es", isBeta: false }, + { fromLang: "fr", toLang: "en", isBeta: false }, + { fromLang: "en", toLang: "fr", isBeta: false }, + { fromLang: "en", toLang: "uk", isBeta: true }, + { fromLang: "uk", toLang: "en", isBeta: true }, +]; -- cgit v1.2.3