From 086c044dc34dfc0f74fbe41f4ecb402b2cd34884 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:33 +0200 Subject: Merging upstream version 125.0.1. Signed-off-by: Daniel Baumann --- .../content/TranslationsPanelShared.sys.mjs | 122 ++ .../content/fullPageTranslationsPanel.inc.xhtml | 146 ++ .../content/fullPageTranslationsPanel.js | 1542 ++++++++++++++++++ .../content/selectTranslationsPanel.inc.xhtml | 102 ++ .../content/selectTranslationsPanel.js | 220 +++ .../content/translationsPanel.inc.xhtml | 145 -- .../translations/content/translationsPanel.js | 1630 -------------------- browser/components/translations/jar.mn | 4 +- .../translations/tests/browser/browser.toml | 96 +- ...wser_translations_full_page_panel_a11y_focus.js | 32 + ...age_panel_always_translate_language_bad_data.js | 39 + ...l_page_panel_always_translate_language_basic.js | 79 + ..._page_panel_always_translate_language_manual.js | 80 + ...page_panel_always_translate_language_restore.js | 101 ++ ...page_panel_app_menu_never_translate_language.js | 40 + ...ull_page_panel_app_menu_never_translate_site.js | 140 ++ ...ns_full_page_panel_auto_translate_error_view.js | 86 ++ ..._full_page_panel_auto_translate_revisit_view.js | 86 ++ .../browser_translations_full_page_panel_basics.js | 69 + .../browser_translations_full_page_panel_button.js | 77 + .../browser_translations_full_page_panel_cancel.js | 27 + ..._translate_language_with_translations_active.js | 147 ++ ...ranslate_language_with_translations_inactive.js | 93 ++ ..._page_panel_close_panel_never_translate_site.js | 159 ++ ..._translations_full_page_panel_engine_destroy.js | 55 + ...tions_full_page_panel_engine_destroy_pending.js | 72 + ...nslations_full_page_panel_engine_unsupported.js | 59 + ...ions_full_page_panel_engine_unsupported_lang.js | 28 + ...rowser_translations_full_page_panel_firstrun.js | 33 + ...ranslations_full_page_panel_firstrun_revisit.js | 57 + ...browser_translations_full_page_panel_fuzzing.js | 240 +++ .../browser_translations_full_page_panel_gear.js | 32 + ...ons_full_page_panel_never_translate_language.js | 186 +++ ...lations_full_page_panel_never_translate_site.js | 247 +++ ...ns_full_page_panel_never_translate_site_auto.js | 109 ++ ...s_full_page_panel_never_translate_site_basic.js | 62 + ..._full_page_panel_never_translate_site_manual.js | 84 + .../browser_translations_full_page_panel_retry.js | 54 + ...ns_full_page_panel_settings_unsupported_lang.js | 74 + ...ranslations_full_page_panel_switch_languages.js | 70 + .../browser_translations_full_page_reader_mode.js | 115 ++ ..._full_page_telemetry_firstrun_auto_translate.js | 117 ++ ...slations_full_page_telemetry_firstrun_basics.js | 93 ++ ..._page_telemetry_firstrun_translation_failure.js | 149 ++ ...ull_page_telemetry_firstrun_unsupported_lang.js | 122 ++ ..._translations_full_page_telemetry_open_panel.js | 85 + ...lations_full_page_telemetry_panel_auto_offer.js | 83 + ...ull_page_telemetry_panel_auto_offer_settings.js | 110 ++ ...lations_full_page_telemetry_switch_languages.js | 156 ++ ...ions_full_page_telemetry_translation_failure.js | 212 +++ ...ions_full_page_telemetry_translation_request.js | 170 ++ .../browser_translations_panel_a11y_focus.js | 32 - ...ons_panel_always_translate_language_bad_data.js | 40 - ...ations_panel_always_translate_language_basic.js | 79 - ...tions_panel_always_translate_language_manual.js | 80 - ...ions_panel_always_translate_language_restore.js | 101 -- ...ions_panel_app_menu_never_translate_language.js | 40 - ...slations_panel_app_menu_never_translate_site.js | 140 -- ...translations_panel_auto_translate_error_view.js | 86 -- ...anslations_panel_auto_translate_revisit_view.js | 86 -- .../browser/browser_translations_panel_basics.js | 69 - .../browser/browser_translations_panel_button.js | 77 - .../browser/browser_translations_panel_cancel.js | 27 - ..._translate_language_with_translations_active.js | 147 -- ...ranslate_language_with_translations_inactive.js | 93 -- ...tions_panel_close_panel_never_translate_site.js | 159 -- .../browser_translations_panel_engine_destroy.js | 55 - ...er_translations_panel_engine_destroy_pending.js | 72 - ...rowser_translations_panel_engine_unsupported.js | 59 - ...r_translations_panel_engine_unsupported_lang.js | 28 - .../browser/browser_translations_panel_firstrun.js | 33 - .../browser_translations_panel_firstrun_revisit.js | 57 - .../browser/browser_translations_panel_fuzzing.js | 240 --- .../browser/browser_translations_panel_gear.js | 32 - ..._translations_panel_never_translate_language.js | 186 --- ...wser_translations_panel_never_translate_site.js | 247 --- ...translations_panel_never_translate_site_auto.js | 109 -- ...ranslations_panel_never_translate_site_basic.js | 62 - ...anslations_panel_never_translate_site_manual.js | 84 - .../browser/browser_translations_panel_retry.js | 54 - ...translations_panel_settings_unsupported_lang.js | 74 - .../browser_translations_panel_switch_languages.js | 70 - .../browser/browser_translations_reader_mode.js | 115 -- ...text_menu_with_full_page_translations_active.js | 8 +- ...translations_select_panel_language_selectors.js | 54 + ...rowser_translations_select_panel_mainview_ui.js | 36 + ...anslations_telemetry_firstrun_auto_translate.js | 117 -- ...owser_translations_telemetry_firstrun_basics.js | 93 -- ...tions_telemetry_firstrun_translation_failure.js | 149 -- ...slations_telemetry_firstrun_unsupported_lang.js | 122 -- .../browser_translations_telemetry_open_panel.js | 85 - ...wser_translations_telemetry_panel_auto_offer.js | 83 - ...slations_telemetry_panel_auto_offer_settings.js | 110 -- ...wser_translations_telemetry_switch_languages.js | 156 -- ...r_translations_telemetry_translation_failure.js | 212 --- ...r_translations_telemetry_translation_request.js | 170 -- .../components/translations/tests/browser/head.js | 604 ++++++-- 97 files changed, 6877 insertions(+), 6091 deletions(-) create mode 100644 browser/components/translations/content/TranslationsPanelShared.sys.mjs create mode 100644 browser/components/translations/content/fullPageTranslationsPanel.inc.xhtml create mode 100644 browser/components/translations/content/fullPageTranslationsPanel.js create mode 100644 browser/components/translations/content/selectTranslationsPanel.inc.xhtml create mode 100644 browser/components/translations/content/selectTranslationsPanel.js delete mode 100644 browser/components/translations/content/translationsPanel.inc.xhtml delete mode 100644 browser/components/translations/content/translationsPanel.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_a11y_focus.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_bad_data.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_basic.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_manual.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_restore.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_app_menu_never_translate_language.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_app_menu_never_translate_site.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_auto_translate_error_view.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_auto_translate_revisit_view.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_basics.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_button.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_cancel.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_active.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_inactive.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_site.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_destroy.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_destroy_pending.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_unsupported.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_unsupported_lang.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_firstrun.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_firstrun_revisit.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_fuzzing.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_gear.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_language.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_auto.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_basic.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_manual.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_retry.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_settings_unsupported_lang.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_panel_switch_languages.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_reader_mode.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_auto_translate.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_basics.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_translation_failure.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_unsupported_lang.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_open_panel.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_panel_auto_offer.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_panel_auto_offer_settings.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_switch_languages.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_translation_failure.js create mode 100644 browser/components/translations/tests/browser/browser_translations_full_page_telemetry_translation_request.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_a11y_focus.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_bad_data.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_basic.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_manual.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_restore.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_app_menu_never_translate_language.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_app_menu_never_translate_site.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_auto_translate_error_view.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_auto_translate_revisit_view.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_basics.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_button.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_cancel.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_language_with_translations_active.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_language_with_translations_inactive.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_site.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_engine_destroy.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_engine_destroy_pending.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_engine_unsupported.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_engine_unsupported_lang.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_firstrun.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_firstrun_revisit.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_fuzzing.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_gear.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_never_translate_language.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_never_translate_site.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_auto.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_basic.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_manual.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_retry.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_settings_unsupported_lang.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_panel_switch_languages.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_reader_mode.js create mode 100644 browser/components/translations/tests/browser/browser_translations_select_panel_language_selectors.js create mode 100644 browser/components/translations/tests/browser/browser_translations_select_panel_mainview_ui.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_auto_translate.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_basics.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_translation_failure.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_unsupported_lang.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_open_panel.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_panel_auto_offer.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_panel_auto_offer_settings.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_switch_languages.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_translation_failure.js delete mode 100644 browser/components/translations/tests/browser/browser_translations_telemetry_translation_request.js (limited to 'browser/components/translations') diff --git a/browser/components/translations/content/TranslationsPanelShared.sys.mjs b/browser/components/translations/content/TranslationsPanelShared.sys.mjs new file mode 100644 index 0000000000..570528df3f --- /dev/null +++ b/browser/components/translations/content/TranslationsPanelShared.sys.mjs @@ -0,0 +1,122 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + TranslationsParent: "resource://gre/actors/TranslationsParent.sys.mjs", +}); + +/** + * A class containing static functionality that is shared by both + * the FullPageTranslationsPanel and SelectTranslationsPanel classes. + */ +export class TranslationsPanelShared { + static #langListsInitState = new Map(); + + /** + * Defines lazy getters for accessing elements in the document based on provided entries. + * + * @param {Document} document - The document object. + * @param {object} lazyElements - An object where lazy getters will be defined. + * @param {object} entries - An object of key/value pairs for which to define lazy getters. + */ + static defineLazyElements(document, lazyElements, entries) { + for (const [name, discriminator] of Object.entries(entries)) { + let element; + Object.defineProperty(lazyElements, name, { + get: () => { + if (!element) { + if (discriminator[0] === ".") { + // Lookup by class + element = document.querySelector(discriminator); + } else { + // Lookup by id + element = document.getElementById(discriminator); + } + } + if (!element) { + throw new Error(`Could not find "${name}" at "#${discriminator}".`); + } + return element; + }, + }); + } + } + + /** + * Retrieves the initialization state of language lists for the specified panel. + * + * @param {FullPageTranslationsPanel | SelectTranslationsPanel} panel + * - The panel for which to look up the state. + */ + static getLangListsInitState(panel) { + return TranslationsPanelShared.#langListsInitState.get(panel.id); + } + + /** + * Builds the of languages for both the "from" and "to". This can be + * called every time the popup is shown, as it will retry when there is an error + * (such as a network error) or be a noop if it's already initialized. + * + * @param {Document} document - The document object. + * @param {FullPageTranslationsPanel | SelectTranslationsPanel} panel + * - The panel for which to ensure language lists are built. + */ + static async ensureLangListsBuilt(document, panel, innerWindowId) { + const { id } = panel; + switch ( + TranslationsPanelShared.#langListsInitState.get(`${id}-${innerWindowId}`) + ) { + case "initialized": + // This has already been initialized. + return; + case "error": + case undefined: + // attempt to initialize + break; + default: + throw new Error( + `Unknown langList phase ${ + TranslationsPanelShared.#langListsInitState + }` + ); + } + /** @type {SupportedLanguages} */ + const { languagePairs, fromLanguages, toLanguages } = + await lazy.TranslationsParent.getSupportedLanguages(); + + // Verify that we are in a proper state. + if (languagePairs.length === 0) { + throw new Error("No translation languages were retrieved."); + } + + const fromPopups = panel.querySelectorAll( + ".translations-panel-language-menupopup-from" + ); + const toPopups = panel.querySelectorAll( + ".translations-panel-language-menupopup-to" + ); + + for (const popup of fromPopups) { + for (const { langTag, displayName } of fromLanguages) { + const fromMenuItem = document.createXULElement("menuitem"); + fromMenuItem.setAttribute("value", langTag); + fromMenuItem.setAttribute("label", displayName); + popup.appendChild(fromMenuItem); + } + } + + for (const popup of toPopups) { + for (const { langTag, displayName } of toLanguages) { + const toMenuItem = document.createXULElement("menuitem"); + toMenuItem.setAttribute("value", langTag); + toMenuItem.setAttribute("label", displayName); + popup.appendChild(toMenuItem); + } + } + + TranslationsPanelShared.#langListsInitState.set(id, "initialized"); + } +} diff --git a/browser/components/translations/content/fullPageTranslationsPanel.inc.xhtml b/browser/components/translations/content/fullPageTranslationsPanel.inc.xhtml new file mode 100644 index 0000000000..bc0c5b319f --- /dev/null +++ b/browser/components/translations/content/fullPageTranslationsPanel.inc.xhtml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browser/components/translations/content/fullPageTranslationsPanel.js b/browser/components/translations/content/fullPageTranslationsPanel.js new file mode 100644 index 0000000000..2e35440160 --- /dev/null +++ b/browser/components/translations/content/fullPageTranslationsPanel.js @@ -0,0 +1,1542 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* eslint-env mozilla/browser-window */ + +/* eslint-disable jsdoc/valid-types */ +/** + * @typedef {import("../../../../toolkit/components/translations/translations").LangTags} LangTags + */ +/* eslint-enable jsdoc/valid-types */ + +ChromeUtils.defineESModuleGetters(this, { + PageActions: "resource:///modules/PageActions.sys.mjs", + TranslationsTelemetry: + "chrome://browser/content/translations/TranslationsTelemetry.sys.mjs", + TranslationsPanelShared: + "chrome://browser/content/translations/TranslationsPanelShared.sys.mjs", +}); + +/** + * The set of actions that can occur from interaction with the + * translations panel. + */ +const PageAction = Object.freeze({ + NO_CHANGE: "NO_CHANGE", + RESTORE_PAGE: "RESTORE_PAGE", + TRANSLATE_PAGE: "TRANSLATE_PAGE", + CLOSE_PANEL: "CLOSE_PANEL", +}); + +/** + * A mechanism for determining the next relevant page action + * based on the current translated state of the page and the state + * of the persistent options in the translations panel settings. + */ +class CheckboxPageAction { + /** + * Whether or not translations is active on the page. + * + * @type {boolean} + */ + #translationsActive = false; + + /** + * Whether the always-translate-language menuitem is checked + * in the translations panel settings menu. + * + * @type {boolean} + */ + #alwaysTranslateLanguage = false; + + /** + * Whether the never-translate-language menuitem is checked + * in the translations panel settings menu. + * + * @type {boolean} + */ + #neverTranslateLanguage = false; + + /** + * Whether the never-translate-site menuitem is checked + * in the translations panel settings menu. + * + * @type {boolean} + */ + #neverTranslateSite = false; + + /** + * @param {boolean} translationsActive + * @param {boolean} alwaysTranslateLanguage + * @param {boolean} neverTranslateLanguage + * @param {boolean} neverTranslateSite + */ + constructor( + translationsActive, + alwaysTranslateLanguage, + neverTranslateLanguage, + neverTranslateSite + ) { + this.#translationsActive = translationsActive; + this.#alwaysTranslateLanguage = alwaysTranslateLanguage; + this.#neverTranslateLanguage = neverTranslateLanguage; + this.#neverTranslateSite = neverTranslateSite; + } + + /** + * Accepts four integers that are either 0 or 1 and returns + * a single, unique number for each possible combination of + * values. + * + * @param {number} translationsActive + * @param {number} alwaysTranslateLanguage + * @param {number} neverTranslateLanguage + * @param {number} neverTranslateSite + * + * @returns {number} - An integer representation of the state + */ + static #computeState( + translationsActive, + alwaysTranslateLanguage, + neverTranslateLanguage, + neverTranslateSite + ) { + return ( + (translationsActive << 3) | + (alwaysTranslateLanguage << 2) | + (neverTranslateLanguage << 1) | + neverTranslateSite + ); + } + + /** + * Returns the current state of the data members as a single number. + * + * @returns {number} - An integer representation of the state + */ + #state() { + return CheckboxPageAction.#computeState( + Number(this.#translationsActive), + Number(this.#alwaysTranslateLanguage), + Number(this.#neverTranslateLanguage), + Number(this.#neverTranslateSite) + ); + } + + /** + * Returns the next page action to take when the always-translate-language + * menuitem is toggled in the translations panel settings menu. + * + * @returns {PageAction} + */ + alwaysTranslateLanguage() { + switch (this.#state()) { + case CheckboxPageAction.#computeState(1, 1, 0, 1): + case CheckboxPageAction.#computeState(1, 1, 0, 0): + return PageAction.RESTORE_PAGE; + case CheckboxPageAction.#computeState(0, 0, 1, 0): + case CheckboxPageAction.#computeState(0, 0, 0, 0): + return PageAction.TRANSLATE_PAGE; + } + return PageAction.NO_CHANGE; + } + + /** + * Returns the next page action to take when the never-translate-language + * menuitem is toggled in the translations panel settings menu. + * + * @returns {PageAction} + */ + neverTranslateLanguage() { + switch (this.#state()) { + case CheckboxPageAction.#computeState(1, 1, 0, 1): + case CheckboxPageAction.#computeState(1, 1, 0, 0): + case CheckboxPageAction.#computeState(1, 0, 0, 1): + case CheckboxPageAction.#computeState(1, 0, 0, 0): + return PageAction.RESTORE_PAGE; + case CheckboxPageAction.#computeState(0, 1, 0, 0): + case CheckboxPageAction.#computeState(0, 0, 0, 1): + case CheckboxPageAction.#computeState(0, 1, 0, 1): + case CheckboxPageAction.#computeState(0, 0, 0, 0): + return PageAction.CLOSE_PANEL; + } + return PageAction.NO_CHANGE; + } + + /** + * Returns the next page action to take when the never-translate-site + * menuitem is toggled in the translations panel settings menu. + * + * @returns {PageAction} + */ + neverTranslateSite() { + switch (this.#state()) { + case CheckboxPageAction.#computeState(1, 1, 0, 0): + case CheckboxPageAction.#computeState(1, 0, 1, 0): + case CheckboxPageAction.#computeState(1, 0, 0, 0): + return PageAction.RESTORE_PAGE; + case CheckboxPageAction.#computeState(0, 1, 0, 1): + return PageAction.TRANSLATE_PAGE; + case CheckboxPageAction.#computeState(0, 0, 1, 0): + case CheckboxPageAction.#computeState(0, 1, 0, 0): + case CheckboxPageAction.#computeState(0, 0, 0, 0): + return PageAction.CLOSE_PANEL; + } + return PageAction.NO_CHANGE; + } +} + +/** + * This singleton class controls the Translations popup panel. + * + * This component is a `/browser` component, and the actor is a `/toolkit` actor, so care + * must be taken to keep the presentation (this component) from the state management + * (the Translations actor). This class reacts to state changes coming from the + * Translations actor. + */ +var FullPageTranslationsPanel = new (class { + /** @type {Console?} */ + #console; + + /** + * The cached detected languages for both the document and the user. + * + * @type {null | LangTags} + */ + detectedLanguages = null; + + /** + * Lazily get a console instance. Note that this script is loaded in very early to + * the browser loading process, and may run before the console is avialable. In + * this case the console will return as `undefined`. + * + * @returns {Console | void} + */ + get console() { + if (!this.#console) { + try { + this.#console = console.createInstance({ + maxLogLevelPref: "browser.translations.logLevel", + prefix: "Translations", + }); + } catch { + // The console may not be initialized yet. + } + } + return this.#console; + } + + /** + * Tracks if the popup is open, or scheduled to be open. + * + * @type {boolean} + */ + #isPopupOpen = false; + + /** + * Where the lazy elements are stored. + * + * @type {Record?} + */ + #lazyElements; + + /** + * Lazily creates the dom elements, and lazily selects them. + * + * @returns {Record} + */ + get elements() { + if (!this.#lazyElements) { + // Lazily turn the template into a DOM element. + /** @type {HTMLTemplateElement} */ + const wrapper = document.getElementById("template-translations-panel"); + const panel = wrapper.content.firstElementChild; + wrapper.replaceWith(wrapper.content); + + const settingsButton = document.getElementById( + "translations-panel-settings" + ); + // Clone the settings toolbarbutton across all the views. + for (const header of panel.querySelectorAll(".panel-header")) { + if (header.contains(settingsButton)) { + continue; + } + const settingsButtonClone = settingsButton.cloneNode(true); + settingsButtonClone.removeAttribute("id"); + header.appendChild(settingsButtonClone); + } + + // Lazily select the elements. + this.#lazyElements = { + panel, + settingsButton, + // The rest of the elements are set by the getter below. + }; + + TranslationsPanelShared.defineLazyElements(document, this.#lazyElements, { + alwaysTranslateLanguageMenuItem: ".always-translate-language-menuitem", + appMenuButton: "PanelUI-menu-button", + cancelButton: "full-page-translations-panel-cancel", + changeSourceLanguageButton: + "full-page-translations-panel-change-source-language", + dismissErrorButton: "full-page-translations-panel-dismiss-error", + error: "full-page-translations-panel-error", + errorMessage: "full-page-translations-panel-error-message", + errorMessageHint: "full-page-translations-panel-error-message-hint", + errorHintAction: "full-page-translations-panel-translate-hint-action", + fromMenuList: "full-page-translations-panel-from", + fromLabel: "full-page-translations-panel-from-label", + header: "full-page-translations-panel-header", + intro: "full-page-translations-panel-intro", + introLearnMoreLink: + "full-page-translations-panel-intro-learn-more-link", + langSelection: "full-page-translations-panel-lang-selection", + manageLanguagesMenuItem: ".manage-languages-menuitem", + multiview: "full-page-translations-panel-multiview", + neverTranslateLanguageMenuItem: ".never-translate-language-menuitem", + neverTranslateSiteMenuItem: ".never-translate-site-menuitem", + restoreButton: "full-page-translations-panel-restore-button", + toLabel: "full-page-translations-panel-to-label", + toMenuList: "full-page-translations-panel-to", + translateButton: "full-page-translations-panel-translate", + unsupportedHeader: + "full-page-translations-panel-unsupported-language-header", + unsupportedHint: "full-page-translations-panel-error-unsupported-hint", + unsupportedLearnMoreLink: + "full-page-translations-panel-unsupported-learn-more-link", + }); + } + + return this.#lazyElements; + } + + #lazyButtonElements = null; + + /** + * When accessing `this.elements` the first time, it de-lazifies the custom components + * that are needed for the popup. Avoid that by having a second element lookup + * just for modifying the button. + */ + get buttonElements() { + if (!this.#lazyButtonElements) { + this.#lazyButtonElements = { + button: document.getElementById("translations-button"), + buttonLocale: document.getElementById("translations-button-locale"), + buttonCircleArrows: document.getElementById( + "translations-button-circle-arrows" + ), + }; + } + return this.#lazyButtonElements; + } + + /** + * Cache the last command used for error hints so that it can be later removed. + */ + #lastHintCommand = null; + + /** + * @param {object} options + * @param {string} options.message - l10n id + * @param {string} options.hint - l10n id + * @param {string} options.actionText - l10n id + * @param {Function} options.actionCommand - The action to perform. + */ + #showError({ + message, + hint, + actionText: hintCommandText, + actionCommand: hintCommand, + }) { + const { error, errorMessage, errorMessageHint, errorHintAction, intro } = + this.elements; + error.hidden = false; + intro.hidden = true; + document.l10n.setAttributes(errorMessage, message); + + if (hint) { + errorMessageHint.hidden = false; + document.l10n.setAttributes(errorMessageHint, hint); + } else { + errorMessageHint.hidden = true; + } + + if (hintCommand && hintCommandText) { + errorHintAction.removeEventListener("command", this.#lastHintCommand); + this.#lastHintCommand = hintCommand; + errorHintAction.addEventListener("command", hintCommand); + errorHintAction.hidden = false; + document.l10n.setAttributes(errorHintAction, hintCommandText); + } else { + errorHintAction.hidden = true; + } + } + + /** + * @returns {TranslationsParent} + */ + #getTranslationsActor() { + const actor = + gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.getActor( + "Translations" + ); + + if (!actor) { + throw new Error("Unable to get the TranslationsParent"); + } + return actor; + } + + /** + * Fetches the language tags for the document and the user and caches the results + * Use `#getCachedDetectedLanguages` when the lang tags do not need to be re-fetched. + * This requires a bit of work to do, so prefer the cached version when possible. + * + * @returns {Promise} + */ + async #fetchDetectedLanguages() { + this.detectedLanguages = + await this.#getTranslationsActor().getDetectedLanguages(); + return this.detectedLanguages; + } + + /** + * If the detected language tags have been retrieved previously, return the cached + * version. Otherwise do a fresh lookup of the document's language tag. + * + * @returns {Promise} + */ + async #getCachedDetectedLanguages() { + if (!this.detectedLanguages) { + return this.#fetchDetectedLanguages(); + } + return this.detectedLanguages; + } + + /** + * Builds the of languages for both the "from" and "to". This can be + * called every time the popup is shown, as it will retry when there is an error + * (such as a network error) or be a noop if it's already initialized. + */ + async #ensureLangListsBuilt() { + try { + await TranslationsPanelShared.ensureLangListsBuilt( + document, + this.elements.panel, + gBrowser.selectedBrowser.innerWindowID + ); + } catch (error) { + this.console?.error(error); + } + } + + /** + * Reactively sets the views based on the async state changes of the engine, and + * other component state changes. + * + * @param {TranslationsLanguageState} languageState + */ + #updateViewFromTranslationStatus( + languageState = this.#getTranslationsActor().languageState + ) { + const { translateButton, toMenuList, fromMenuList, header, cancelButton } = + this.elements; + const { requestedTranslationPair, isEngineReady } = languageState; + + if ( + requestedTranslationPair && + !isEngineReady && + toMenuList.value === requestedTranslationPair.toLanguage && + fromMenuList.value === requestedTranslationPair.fromLanguage + ) { + // A translation has been requested, but is not ready yet. + document.l10n.setAttributes( + translateButton, + "translations-panel-translate-button-loading" + ); + translateButton.disabled = true; + cancelButton.hidden = false; + this.updateUIForReTranslation(false /* isReTranslation */); + } else { + document.l10n.setAttributes( + translateButton, + "translations-panel-translate-button" + ); + translateButton.disabled = + // The translation languages are the same, don't allow this translation. + toMenuList.value === fromMenuList.value || + // No "to" language was provided. + !toMenuList.value || + // No "from" language was provided. + !fromMenuList.value || + // This is the requested translation pair. + (requestedTranslationPair && + requestedTranslationPair.fromLanguage === fromMenuList.value && + requestedTranslationPair.toLanguage === toMenuList.value); + } + + if (requestedTranslationPair && isEngineReady) { + const { fromLanguage, toLanguage } = requestedTranslationPair; + const displayNames = new Services.intl.DisplayNames(undefined, { + type: "language", + }); + cancelButton.hidden = true; + this.updateUIForReTranslation(true /* isReTranslation */); + + document.l10n.setAttributes(header, "translations-panel-revisit-header", { + fromLanguage: displayNames.of(fromLanguage), + toLanguage: displayNames.of(toLanguage), + }); + } else { + document.l10n.setAttributes(header, "translations-panel-header"); + } + } + + /** + * @param {boolean} isReTranslation + */ + updateUIForReTranslation(isReTranslation) { + const { restoreButton, fromLabel, fromMenuList, toLabel } = this.elements; + restoreButton.hidden = !isReTranslation; + // When offering to re-translate a page, hide the "from" language so users don't + // get confused. + fromLabel.hidden = isReTranslation; + fromMenuList.hidden = isReTranslation; + if (isReTranslation) { + fromLabel.style.marginBlockStart = ""; + toLabel.style.marginBlockStart = 0; + } else { + fromLabel.style.marginBlockStart = 0; + toLabel.style.marginBlockStart = ""; + } + } + + /** + * Returns true if the panel is currently showing the default view, otherwise false. + * + * @returns {boolean} + */ + #isShowingDefaultView() { + if (!this.#lazyElements) { + // Nothing has been initialized. + return false; + } + const { multiview } = this.elements; + return ( + multiview.getAttribute("mainViewId") === + "full-page-translations-panel-view-default" + ); + } + + /** + * Show the default view of choosing a source and target language. + * + * @param {TranslationsParent} actor + * @param {boolean} force - Force the page to show translation options. + */ + async #showDefaultView(actor, force = false) { + const { + fromMenuList, + multiview, + panel, + error, + toMenuList, + translateButton, + langSelection, + intro, + header, + } = this.elements; + + this.#updateViewFromTranslationStatus(); + + // Unconditionally hide the intro text in case the panel is re-shown. + intro.hidden = true; + + if (TranslationsPanelShared.getLangListsInitState(panel) === "error") { + // There was an error, display it in the view rather than the language + // dropdowns. + const { cancelButton, errorHintAction } = this.elements; + + this.#showError({ + message: "translations-panel-error-load-languages", + hint: "translations-panel-error-load-languages-hint", + actionText: "translations-panel-error-load-languages-hint-button", + actionCommand: () => this.#reloadLangList(actor), + }); + + translateButton.disabled = true; + this.updateUIForReTranslation(false /* isReTranslation */); + cancelButton.hidden = false; + langSelection.hidden = true; + errorHintAction.disabled = false; + return; + } + + // Remove any old selected values synchronously before asking for new ones. + fromMenuList.value = ""; + error.hidden = true; + langSelection.hidden = false; + + /** @type {null | LangTags} */ + const langTags = await this.#fetchDetectedLanguages(); + if (langTags?.isDocLangTagSupported || force) { + // Show the default view with the language selection + const { cancelButton } = this.elements; + + if (langTags?.isDocLangTagSupported) { + fromMenuList.value = langTags?.docLangTag ?? ""; + } else { + fromMenuList.value = ""; + } + toMenuList.value = langTags?.userLangTag ?? ""; + + this.onChangeLanguages(); + + this.updateUIForReTranslation(false /* isReTranslation */); + cancelButton.hidden = false; + multiview.setAttribute( + "mainViewId", + "full-page-translations-panel-view-default" + ); + + if (!this._hasShownPanel) { + actor.firstShowUriSpec = gBrowser.currentURI.spec; + } + + if ( + this._hasShownPanel && + gBrowser.currentURI.spec !== actor.firstShowUriSpec + ) { + document.l10n.setAttributes(header, "translations-panel-header"); + actor.firstShowUriSpec = null; + intro.hidden = true; + } else { + Services.prefs.setBoolPref("browser.translations.panelShown", true); + intro.hidden = false; + document.l10n.setAttributes(header, "translations-panel-intro-header"); + } + } else { + // Show the "unsupported language" view. + const { unsupportedHint } = this.elements; + multiview.setAttribute( + "mainViewId", + "full-page-translations-panel-view-unsupported-language" + ); + let language; + if (langTags?.docLangTag) { + const displayNames = new Intl.DisplayNames(undefined, { + type: "language", + fallback: "none", + }); + language = displayNames.of(langTags.docLangTag); + } + if (language) { + document.l10n.setAttributes( + unsupportedHint, + "translations-panel-error-unsupported-hint-known", + { language } + ); + } else { + document.l10n.setAttributes( + unsupportedHint, + "translations-panel-error-unsupported-hint-unknown" + ); + } + } + + // Focus the "from" language, as it is the only field not set. + panel.addEventListener( + "ViewShown", + () => { + if (!fromMenuList.value) { + fromMenuList.focus(); + } + if (!toMenuList.value) { + toMenuList.focus(); + } + }, + { once: true } + ); + } + + /** + * Updates the checked states of the settings menu checkboxes that + * pertain to languages. + */ + async #updateSettingsMenuLanguageCheckboxStates() { + const langTags = await this.#getCachedDetectedLanguages(); + const { docLangTag, isDocLangTagSupported } = langTags; + + const { panel } = this.elements; + const alwaysTranslateMenuItems = panel.ownerDocument.querySelectorAll( + ".always-translate-language-menuitem" + ); + const neverTranslateMenuItems = panel.ownerDocument.querySelectorAll( + ".never-translate-language-menuitem" + ); + const alwaysOfferTranslationsMenuItems = + panel.ownerDocument.querySelectorAll( + ".always-offer-translations-menuitem" + ); + + const alwaysOfferTranslations = + TranslationsParent.shouldAlwaysOfferTranslations(); + const alwaysTranslateLanguage = + TranslationsParent.shouldAlwaysTranslateLanguage(langTags); + const neverTranslateLanguage = + TranslationsParent.shouldNeverTranslateLanguage(docLangTag); + const shouldDisable = + !docLangTag || + !isDocLangTagSupported || + docLangTag === new Intl.Locale(Services.locale.appLocaleAsBCP47).language; + + for (const menuitem of alwaysOfferTranslationsMenuItems) { + menuitem.setAttribute( + "checked", + alwaysOfferTranslations ? "true" : "false" + ); + } + for (const menuitem of alwaysTranslateMenuItems) { + menuitem.setAttribute( + "checked", + alwaysTranslateLanguage ? "true" : "false" + ); + menuitem.disabled = shouldDisable; + } + for (const menuitem of neverTranslateMenuItems) { + menuitem.setAttribute( + "checked", + neverTranslateLanguage ? "true" : "false" + ); + menuitem.disabled = shouldDisable; + } + } + + /** + * Updates the checked states of the settings menu checkboxes that + * pertain to site permissions. + */ + async #updateSettingsMenuSiteCheckboxStates() { + const { panel } = this.elements; + const neverTranslateSiteMenuItems = panel.ownerDocument.querySelectorAll( + ".never-translate-site-menuitem" + ); + const neverTranslateSite = + await this.#getTranslationsActor().shouldNeverTranslateSite(); + + for (const menuitem of neverTranslateSiteMenuItems) { + menuitem.setAttribute("checked", neverTranslateSite ? "true" : "false"); + } + } + + /** + * Populates the language-related settings menuitems by adding the + * localized display name of the document's detected language tag. + */ + async #populateSettingsMenuItems() { + const { docLangTag } = await this.#getCachedDetectedLanguages(); + + const { panel } = this.elements; + + const alwaysTranslateMenuItems = panel.ownerDocument.querySelectorAll( + ".always-translate-language-menuitem" + ); + const neverTranslateMenuItems = panel.ownerDocument.querySelectorAll( + ".never-translate-language-menuitem" + ); + + /** @type {string | undefined} */ + let docLangDisplayName; + if (docLangTag) { + const displayNames = new Services.intl.DisplayNames(undefined, { + type: "language", + fallback: "none", + }); + // The display name will still be empty if the docLangTag is not known. + docLangDisplayName = displayNames.of(docLangTag); + } + + for (const menuitem of alwaysTranslateMenuItems) { + if (docLangDisplayName) { + document.l10n.setAttributes( + menuitem, + "translations-panel-settings-always-translate-language", + { language: docLangDisplayName } + ); + } else { + document.l10n.setAttributes( + menuitem, + "translations-panel-settings-always-translate-unknown-language" + ); + } + } + + for (const menuitem of neverTranslateMenuItems) { + if (docLangDisplayName) { + document.l10n.setAttributes( + menuitem, + "translations-panel-settings-never-translate-language", + { language: docLangDisplayName } + ); + } else { + document.l10n.setAttributes( + menuitem, + "translations-panel-settings-never-translate-unknown-language" + ); + } + } + + await Promise.all([ + this.#updateSettingsMenuLanguageCheckboxStates(), + this.#updateSettingsMenuSiteCheckboxStates(), + ]); + } + + /** + * Configures the panel for the user to reset the page after it has been translated. + * + * @param {TranslationPair} translationPair + */ + async #showRevisitView({ fromLanguage, toLanguage }) { + const { fromMenuList, toMenuList, intro } = this.elements; + if (!this.#isShowingDefaultView()) { + await this.#showDefaultView(this.#getTranslationsActor()); + } + intro.hidden = true; + fromMenuList.value = fromLanguage; + toMenuList.value = toLanguage; + this.onChangeLanguages(); + } + + /** + * Handle the disable logic for when the menulist is changed for the "Translate to" + * on the "revisit" subview. + */ + onChangeRevisitTo() { + const { revisitTranslate, revisitMenuList } = this.elements; + revisitTranslate.disabled = !revisitMenuList.value; + } + + /** + * Handle logic and telemetry for changing the selected from-language option. + * + * @param {Event} event + */ + onChangeFromLanguage(event) { + const { target } = event; + if (target?.value) { + TranslationsParent.telemetry().panel().onChangeFromLanguage(target.value); + } + this.onChangeLanguages(); + } + + /** + * Handle logic and telemetry for changing the selected to-language option. + * + * @param {Event} event + */ + onChangeToLanguage(event) { + const { target } = event; + if (target?.value) { + TranslationsParent.telemetry().panel().onChangeToLanguage(target.value); + } + this.onChangeLanguages(); + } + + /** + * When changing the language selection, the translate button will need updating. + */ + onChangeLanguages() { + this.#updateViewFromTranslationStatus(); + } + + /** + * Hide the pop up (for event handlers). + */ + close() { + PanelMultiView.hidePopup(this.elements.panel); + } + + /* + * Handler for clicking the learn more link from linked text + * within the translations panel. + */ + onLearnMoreLink() { + TranslationsParent.telemetry().panel().onLearnMoreLink(); + FullPageTranslationsPanel.close(); + } + + /* + * Handler for clicking the learn more link from the gear menu. + */ + onAboutTranslations() { + TranslationsParent.telemetry().panel().onAboutTranslations(); + PanelMultiView.hidePopup(this.elements.panel); + const window = + gBrowser.selectedBrowser.browsingContext.top.embedderElement.ownerGlobal; + window.openTrustedLinkIn( + "https://support.mozilla.org/kb/website-translation", + "tab", + { + forceForeground: true, + triggeringPrincipal: + Services.scriptSecurityManager.getSystemPrincipal(), + } + ); + } + + /** + * When a language is not supported and the menu is manually invoked, an error message + * is shown. This method switches the panel back to the language selection view. + * Note that this bypasses the showSubView method since the main view doesn't support + * a subview. + */ + async onChangeSourceLanguage(event) { + const { panel } = this.elements; + PanelMultiView.hidePopup(panel); + + await this.#showDefaultView( + this.#getTranslationsActor(), + true /* force this view to be shown */ + ); + + await this.#openPanelPopup(this.elements.appMenuButton, { + event, + viewName: "defaultView", + maintainFlow: true, + }); + } + + /** + * @param {TranslationsActor} actor + */ + async #reloadLangList(actor) { + try { + await this.#ensureLangListsBuilt(); + await this.#showDefaultView(actor); + } catch (error) { + this.elements.errorHintAction.disabled = false; + } + } + + /** + * Handle telemetry events when buttons are invoked in the panel. + * + * @param {Event} event + */ + handlePanelButtonEvent(event) { + const { + cancelButton, + changeSourceLanguageButton, + dismissErrorButton, + restoreButton, + translateButton, + } = this.elements; + switch (event.target.id) { + case cancelButton.id: { + TranslationsParent.telemetry().panel().onCancelButton(); + break; + } + case changeSourceLanguageButton.id: { + TranslationsParent.telemetry().panel().onChangeSourceLanguageButton(); + break; + } + case dismissErrorButton.id: { + TranslationsParent.telemetry().panel().onDismissErrorButton(); + break; + } + case restoreButton.id: { + TranslationsParent.telemetry().panel().onRestorePageButton(); + break; + } + case translateButton.id: { + TranslationsParent.telemetry().panel().onTranslateButton(); + break; + } + } + } + + /** + * Handle telemetry events when popups are shown in the panel. + * + * @param {Event} event + */ + handlePanelPopupShownEvent(event) { + const { panel, fromMenuList, toMenuList } = this.elements; + switch (event.target.id) { + case panel.id: { + // This telemetry event is invoked externally because it requires + // extra logic about from where the panel was opened and whether + // or not the flow should be maintained or started anew. + break; + } + case fromMenuList.firstChild.id: { + TranslationsParent.telemetry().panel().onOpenFromLanguageMenu(); + break; + } + case toMenuList.firstChild.id: { + TranslationsParent.telemetry().panel().onOpenToLanguageMenu(); + break; + } + } + } + + /** + * Handle telemetry events when popups are hidden in the panel. + * + * @param {Event} event + */ + handlePanelPopupHiddenEvent(event) { + const { panel, fromMenuList, toMenuList } = this.elements; + switch (event.target.id) { + case panel.id: { + TranslationsParent.telemetry().panel().onClose(); + this.#isPopupOpen = false; + this.elements.error.hidden = true; + break; + } + case fromMenuList.firstChild.id: { + TranslationsParent.telemetry().panel().onCloseFromLanguageMenu(); + break; + } + case toMenuList.firstChild.id: { + TranslationsParent.telemetry().panel().onCloseToLanguageMenu(); + break; + } + } + } + + /** + * Handle telemetry events when the settings menu is shown. + */ + handleSettingsPopupShownEvent() { + TranslationsParent.telemetry().panel().onOpenSettingsMenu(); + } + + /** + * Handle telemetry events when the settings menu is hidden. + */ + handleSettingsPopupHiddenEvent() { + TranslationsParent.telemetry().panel().onCloseSettingsMenu(); + } + + /** + * Opens the Translations panel popup at the given target. + * + * @param {object} target - The target element at which to open the popup. + * @param {object} telemetryData + * @param {string} telemetryData.event + * The trigger event for opening the popup. + * @param {string} telemetryData.viewName + * The name of the view shown by the panel. + * @param {boolean} telemetryData.autoShow + * True if the panel was automatically opened, otherwise false. + * @param {boolean} telemetryData.maintainFlow + * Whether or not to maintain the flow of telemetry. + * @param {boolean} telemetryData.isFirstUserInteraction + * Whether or not this is the first user interaction with the panel. + */ + async #openPanelPopup( + target, + { + event = null, + viewName = null, + autoShow = false, + maintainFlow = false, + isFirstUserInteraction = null, + } + ) { + await window.ensureCustomElements("moz-button-group"); + + const { panel, appMenuButton } = this.elements; + const openedFromAppMenu = target.id === appMenuButton.id; + const { docLangTag } = await this.#getCachedDetectedLanguages(); + + TranslationsParent.telemetry().panel().onOpen({ + viewName, + autoShow, + docLangTag, + maintainFlow, + openedFromAppMenu, + isFirstUserInteraction, + }); + + this.#isPopupOpen = true; + + PanelMultiView.openPopup(panel, target, { + position: "bottomright topright", + triggerEvent: event, + }).catch(error => this.console?.error(error)); + } + + /** + * Keeps track of open requests to guard against race conditions. + * + * @type {Promise | null} + */ + #openPromise = null; + + /** + * Opens the FullPageTranslationsPanel. + * + * @param {Event} event + * @param {boolean} reportAsAutoShow + * True to report to telemetry that the panel was opened automatically, otherwise false. + */ + async open(event, reportAsAutoShow = false) { + if (this.#openPromise) { + // There is already an open event happening, do not open. + return; + } + + this.#openPromise = this.#openImpl(event, reportAsAutoShow); + this.#openPromise.finally(() => { + this.#openPromise = null; + }); + } + + /** + * Implementation function for opening the panel. Prefer FullPageTranslationsPanel.open. + * + * @param {Event} event + */ + async #openImpl(event, reportAsAutoShow) { + event.stopPropagation(); + if ( + (event.type == "click" && event.button != 0) || + (event.type == "keypress" && + event.charCode != KeyEvent.DOM_VK_SPACE && + event.keyCode != KeyEvent.DOM_VK_RETURN) + ) { + // Allow only left click, space, or enter. + return; + } + + const window = + gBrowser.selectedBrowser.browsingContext.top.embedderElement.ownerGlobal; + window.ensureCustomElements("moz-support-link"); + + const { button } = this.buttonElements; + + const { requestedTranslationPair, locationChangeId } = + this.#getTranslationsActor().languageState; + + // Store this value because it gets modified when #showDefaultView is called below. + const isFirstUserInteraction = !this._hasShownPanel; + + await this.#ensureLangListsBuilt(); + + if (requestedTranslationPair) { + await this.#showRevisitView(requestedTranslationPair).catch(error => { + this.console?.error(error); + }); + } else { + await this.#showDefaultView(this.#getTranslationsActor()).catch(error => { + this.console?.error(error); + }); + } + + this.#populateSettingsMenuItems(); + + const targetButton = + button.contains(event.target) || + event.type === "TranslationsParent:OfferTranslation" + ? button + : this.elements.appMenuButton; + + if (!TranslationsParent.isActiveLocation(locationChangeId)) { + this.console?.log(`A translation panel open request was stale.`, { + locationChangeId, + newlocationChangeId: + this.#getTranslationsActor().languageState.locationChangeId, + currentURISpec: gBrowser.currentURI.spec, + }); + return; + } + + this.console?.log(`Showing a translation panel`, gBrowser.currentURI.spec); + + await this.#openPanelPopup(targetButton, { + event, + autoShow: reportAsAutoShow, + viewName: requestedTranslationPair ? "revisitView" : "defaultView", + maintainFlow: false, + isFirstUserInteraction, + }); + } + + /** + * Returns true if translations is currently active, otherwise false. + * + * @returns {boolean} + */ + #isTranslationsActive() { + const { requestedTranslationPair } = + this.#getTranslationsActor().languageState; + return requestedTranslationPair !== null; + } + + /** + * Handle the translation button being clicked when there are two language options. + */ + async onTranslate() { + PanelMultiView.hidePopup(this.elements.panel); + + const actor = this.#getTranslationsActor(); + actor.translate( + this.elements.fromMenuList.value, + this.elements.toMenuList.value, + false // reportAsAutoTranslate + ); + } + + /** + * Handle the cancel button being clicked. + */ + onCancel() { + PanelMultiView.hidePopup(this.elements.panel); + } + + /** + * A handler for opening the settings context menu. + */ + openSettingsPopup(button) { + this.#updateSettingsMenuLanguageCheckboxStates(); + this.#updateSettingsMenuSiteCheckboxStates(); + const popup = button.ownerDocument.getElementById( + "translations-panel-settings-menupopup" + ); + popup.openPopup(button, "after_end"); + } + + /** + * Creates a new CheckboxPageAction based on the current translated + * state of the page and the state of the persistent options in the + * translations panel settings. + * + * @returns {CheckboxPageAction} + */ + getCheckboxPageActionFor() { + const { + alwaysTranslateLanguageMenuItem, + neverTranslateLanguageMenuItem, + neverTranslateSiteMenuItem, + } = this.elements; + + const alwaysTranslateLanguage = + alwaysTranslateLanguageMenuItem.getAttribute("checked") === "true"; + const neverTranslateLanguage = + neverTranslateLanguageMenuItem.getAttribute("checked") === "true"; + const neverTranslateSite = + neverTranslateSiteMenuItem.getAttribute("checked") === "true"; + + return new CheckboxPageAction( + this.#isTranslationsActive(), + alwaysTranslateLanguage, + neverTranslateLanguage, + neverTranslateSite + ); + } + + /** + * Redirect the user to about:preferences + */ + openManageLanguages() { + TranslationsParent.telemetry().panel().onManageLanguages(); + const window = + gBrowser.selectedBrowser.browsingContext.top.embedderElement.ownerGlobal; + window.openTrustedLinkIn("about:preferences#general-translations", "tab"); + } + + /** + * Performs the given page action. + * + * @param {PageAction} pageAction + */ + async #doPageAction(pageAction) { + switch (pageAction) { + case PageAction.NO_CHANGE: { + break; + } + case PageAction.RESTORE_PAGE: { + await this.onRestore(); + break; + } + case PageAction.TRANSLATE_PAGE: { + await this.onTranslate(); + break; + } + case PageAction.CLOSE_PANEL: { + PanelMultiView.hidePopup(this.elements.panel); + break; + } + } + } + + /** + * Updates the always-translate-language menuitem prefs and checked state. + * If auto-translate is currently active for the doc language, deactivates it. + * If auto-translate is currently inactive for the doc language, activates it. + */ + async onAlwaysTranslateLanguage() { + const langTags = await this.#getCachedDetectedLanguages(); + const { docLangTag } = langTags; + if (!docLangTag) { + throw new Error("Expected to have a document language tag."); + } + const pageAction = + this.getCheckboxPageActionFor().alwaysTranslateLanguage(); + const toggledOn = + TranslationsParent.toggleAlwaysTranslateLanguagePref(langTags); + TranslationsParent.telemetry() + .panel() + .onAlwaysTranslateLanguage(docLangTag, toggledOn); + this.#updateSettingsMenuLanguageCheckboxStates(); + await this.#doPageAction(pageAction); + } + + /** + * Toggle offering translations. + */ + async onAlwaysOfferTranslations() { + const toggledOn = TranslationsParent.toggleAutomaticallyPopupPref(); + TranslationsParent.telemetry().panel().onAlwaysOfferTranslations(toggledOn); + } + + /** + * Updates the never-translate-language menuitem prefs and checked state. + * If never-translate is currently active for the doc language, deactivates it. + * If never-translate is currently inactive for the doc language, activates it. + */ + async onNeverTranslateLanguage() { + const { docLangTag } = await this.#getCachedDetectedLanguages(); + if (!docLangTag) { + throw new Error("Expected to have a document language tag."); + } + const pageAction = this.getCheckboxPageActionFor().neverTranslateLanguage(); + const toggledOn = + TranslationsParent.toggleNeverTranslateLanguagePref(docLangTag); + TranslationsParent.telemetry() + .panel() + .onNeverTranslateLanguage(docLangTag, toggledOn); + this.#updateSettingsMenuLanguageCheckboxStates(); + await this.#doPageAction(pageAction); + } + + /** + * Updates the never-translate-site menuitem permissions and checked state. + * If never-translate is currently active for the site, deactivates it. + * If never-translate is currently inactive for the site, activates it. + */ + async onNeverTranslateSite() { + const pageAction = this.getCheckboxPageActionFor().neverTranslateSite(); + const toggledOn = + await this.#getTranslationsActor().toggleNeverTranslateSitePermissions(); + TranslationsParent.telemetry().panel().onNeverTranslateSite(toggledOn); + this.#updateSettingsMenuSiteCheckboxStates(); + await this.#doPageAction(pageAction); + } + + /** + * Handle the restore button being clicked. + */ + async onRestore() { + const { panel } = this.elements; + PanelMultiView.hidePopup(panel); + const { docLangTag } = await this.#getCachedDetectedLanguages(); + if (!docLangTag) { + throw new Error("Expected to have a document language tag."); + } + + this.#getTranslationsActor().restorePage(docLangTag); + } + + /** + * An event handler that allows the FullPageTranslationsPanel object + * to be compatible with the addTabsProgressListener function. + * + * @param {tabbrowser} browser + */ + onLocationChange(browser) { + if (browser.currentURI.spec.startsWith("about:reader")) { + // Hide the translations button when entering reader mode. + this.buttonElements.button.hidden = true; + } + } + + /** + * Update the view to show an error. + * + * @param {TranslationParent} actor + */ + async #showEngineError(actor) { + const { button } = this.buttonElements; + await this.#ensureLangListsBuilt(); + if (!this.#isShowingDefaultView()) { + await this.#showDefaultView(actor).catch(e => { + this.console?.error(e); + }); + } + this.elements.error.hidden = false; + this.#showError({ + message: "translations-panel-error-translating", + }); + const targetButton = button.hidden ? this.elements.appMenuButton : button; + + // Re-open the menu on an error. + await this.#openPanelPopup(targetButton, { + autoShow: true, + viewName: "errorView", + maintainFlow: true, + }); + } + + /** + * Set the state of the translations button in the URL bar. + * + * @param {CustomEvent} event + */ + handleEvent = event => { + switch (event.type) { + case "TranslationsParent:OfferTranslation": { + if (Services.wm.getMostRecentBrowserWindow()?.gBrowser === gBrowser) { + this.open(event, /* reportAsAutoShow */ true); + } + break; + } + case "TranslationsParent:LanguageState": { + const { actor } = event.detail; + const { + detectedLanguages, + requestedTranslationPair, + error, + isEngineReady, + } = actor.languageState; + + const { button, buttonLocale, buttonCircleArrows } = + this.buttonElements; + + const hasSupportedLanguage = + detectedLanguages?.docLangTag && + detectedLanguages?.userLangTag && + detectedLanguages?.isDocLangTagSupported; + + if (detectedLanguages) { + // Ensure the cached detected languages are up to date, for instance whenever + // the user switches tabs. + FullPageTranslationsPanel.detectedLanguages = detectedLanguages; + } + + if (this.#isPopupOpen) { + // Make sure to use the language state that is passed by the event.detail, and + // don't read it from the actor here, as it's possible the actor isn't available + // via the gBrowser.selectedBrowser. + this.#updateViewFromTranslationStatus(actor.languageState); + } + + if ( + // We've already requested to translate this page, so always show the icon. + requestedTranslationPair || + // There was an error translating, so always show the icon. This can happen + // when a user manually invokes the translation and we wouldn't normally show + // the icon. + error || + // Finally check that we can translate this language. + (hasSupportedLanguage && + TranslationsParent.getIsTranslationsEngineSupported()) + ) { + // Keep track if the button was originally hidden, because it will be shown now. + const wasButtonHidden = button.hidden; + + button.hidden = false; + if (requestedTranslationPair) { + // The translation is active, update the urlbar button. + button.setAttribute("translationsactive", true); + if (isEngineReady) { + const displayNames = new Services.intl.DisplayNames(undefined, { + type: "language", + }); + + document.l10n.setAttributes( + button, + "urlbar-translations-button-translated", + { + fromLanguage: displayNames.of( + requestedTranslationPair.fromLanguage + ), + toLanguage: displayNames.of( + requestedTranslationPair.toLanguage + ), + } + ); + // Show the locale of the page in the button. + buttonLocale.hidden = false; + buttonCircleArrows.hidden = true; + buttonLocale.innerText = requestedTranslationPair.toLanguage; + } else { + document.l10n.setAttributes( + button, + "urlbar-translations-button-loading" + ); + // Show the spinning circle arrows to indicate that the engine is + // still loading. + buttonCircleArrows.hidden = false; + buttonLocale.hidden = true; + } + } else { + // The translation is not active, update the urlbar button. + button.removeAttribute("translationsactive"); + buttonLocale.hidden = true; + buttonCircleArrows.hidden = true; + + // Follow the same rules for displaying the first-run intro text for the + // button's accessible tooltip label. + if ( + this._hasShownPanel && + gBrowser.currentURI.spec !== actor.firstShowUriSpec + ) { + document.l10n.setAttributes( + button, + "urlbar-translations-button2" + ); + } else { + document.l10n.setAttributes( + button, + "urlbar-translations-button-intro" + ); + } + } + + // The button was hidden, but now it is shown. + if (wasButtonHidden) { + PageActions.sendPlacedInUrlbarTrigger(button); + } + } else if (!button.hidden) { + // There are no translations visible, hide the button. + button.hidden = true; + } + + switch (error) { + case null: + break; + case "engine-load-failure": + this.#showEngineError(actor).catch(viewError => + this.console.error(viewError) + ); + break; + default: + console.error("Unknown translation error", error); + } + break; + } + } + }; +})(); + +XPCOMUtils.defineLazyPreferenceGetter( + FullPageTranslationsPanel, + "_hasShownPanel", + "browser.translations.panelShown", + false +); diff --git a/browser/components/translations/content/selectTranslationsPanel.inc.xhtml b/browser/components/translations/content/selectTranslationsPanel.inc.xhtml new file mode 100644 index 0000000000..72e2bd7095 --- /dev/null +++ b/browser/components/translations/content/selectTranslationsPanel.inc.xhtml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browser/components/translations/content/selectTranslationsPanel.js b/browser/components/translations/content/selectTranslationsPanel.js new file mode 100644 index 0000000000..b4fe3e9735 --- /dev/null +++ b/browser/components/translations/content/selectTranslationsPanel.js @@ -0,0 +1,220 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* eslint-env mozilla/browser-window */ + +ChromeUtils.defineESModuleGetters(this, { + LanguageDetector: + "resource://gre/modules/translation/LanguageDetector.sys.mjs", + TranslationsPanelShared: + "chrome://browser/content/translations/TranslationsPanelShared.sys.mjs", +}); + +/** + * This singleton class controls the Translations popup panel. + */ +var SelectTranslationsPanel = new (class { + /** @type {Console?} */ + #console; + + /** + * Lazily get a console instance. Note that this script is loaded in very early to + * the browser loading process, and may run before the console is available. In + * this case the console will return as `undefined`. + * + * @returns {Console | void} + */ + get console() { + if (!this.#console) { + try { + this.#console = console.createInstance({ + maxLogLevelPref: "browser.translations.logLevel", + prefix: "Translations", + }); + } catch { + // The console may not be initialized yet. + } + } + return this.#console; + } + + /** + * Where the lazy elements are stored. + * + * @type {Record?} + */ + #lazyElements; + + /** + * Lazily creates the dom elements, and lazily selects them. + * + * @returns {Record} + */ + get elements() { + if (!this.#lazyElements) { + // Lazily turn the template into a DOM element. + /** @type {HTMLTemplateElement} */ + const wrapper = document.getElementById( + "template-select-translations-panel" + ); + + const panel = wrapper.content.firstElementChild; + const settingsButton = document.getElementById( + "translations-panel-settings" + ); + wrapper.replaceWith(wrapper.content); + + // Lazily select the elements. + this.#lazyElements = { + panel, + settingsButton, + }; + + TranslationsPanelShared.defineLazyElements(document, this.#lazyElements, { + betaIcon: "select-translations-panel-beta-icon", + copyButton: "select-translations-panel-copy-button", + doneButton: "select-translations-panel-done-button", + fromLabel: "select-translations-panel-from-label", + fromMenuList: "select-translations-panel-from", + header: "select-translations-panel-header", + multiview: "select-translations-panel-multiview", + textArea: "select-translations-panel-translation-area", + toLabel: "select-translations-panel-to-label", + toMenuList: "select-translations-panel-to", + translateFullPageButton: + "select-translations-panel-translate-full-page-button", + }); + } + + return this.#lazyElements; + } + + /** + * Detects the language of the provided text and retrieves a language pair for translation + * based on user settings. + * + * @param {string} textToTranslate - The text for which the language detection and target language retrieval are performed. + * @returns {Promise<{fromLang?: string, toLang?: string}>} - An object containing the language pair for the translation. + * The `fromLang` property is omitted if it is a language that is not currently supported by Firefox Translations. + * The `toLang` property is omitted if it is the same as `fromLang`. + */ + async getLangPairPromise(textToTranslate) { + const [fromLang, toLang] = await Promise.all([ + LanguageDetector.detectLanguage(textToTranslate).then( + ({ language }) => language + ), + TranslationsParent.getTopPreferredSupportedToLang(), + ]); + + return { + fromLang, + // If the fromLang and toLang are the same, discard the toLang. + toLang: fromLang === toLang ? undefined : toLang, + }; + } + + /** + * Close the Select Translations Panel. + */ + close() { + PanelMultiView.hidePopup(this.elements.panel); + } + + /** + * Builds the of languages for both the "from" and "to". This can be + * called every time the popup is shown, as it will retry when there is an error + * (such as a network error) or be a noop if it's already initialized. + */ + async #ensureLangListsBuilt() { + try { + await TranslationsPanelShared.ensureLangListsBuilt( + document, + this.elements.panel + ); + } catch (error) { + this.console?.error(error); + } + } + + /** + * Updates the language dropdown based on the provided language tag. + * + * @param {string} langTag - A BCP-47 language tag. + * @param {Element} menuList - The dropdown menu element that will be updated based on language support. + * @returns {Promise} + */ + async #updateLanguageDropdown(langTag, menuList) { + const langTagIsSupported = + menuList.id === this.elements.fromMenuList.id + ? await TranslationsParent.isSupportedAsFromLang(langTag) + : await TranslationsParent.isSupportedAsToLang(langTag); + + if (langTagIsSupported) { + // Remove the data-l10n-id because the menulist label will + // be populated from the supported language's display name. + menuList.value = langTag; + menuList.removeAttribute("data-l10n-id"); + } else { + // Set the data-l10n-id placeholder because no valid + // language will be selected when the panel opens. + menuList.value = undefined; + document.l10n.setAttributes( + menuList, + "translations-panel-choose-language" + ); + await document.l10n.translateElements([menuList]); + } + } + + /** + * Updates the language selection dropdowns based on the given langPairPromise. + * + * @param {Promise<{fromLang?: string, toLang?: string}>} langPairPromise + * @returns {Promise} + */ + async #updateLanguageDropdowns(langPairPromise) { + const { fromLang, toLang } = await langPairPromise; + + this.console?.debug(`fromLang(${fromLang})`); + this.console?.debug(`toLang(${toLang})`); + + const { fromMenuList, toMenuList } = this.elements; + + await Promise.all([ + this.#updateLanguageDropdown(fromLang, fromMenuList), + this.#updateLanguageDropdown(toLang, toMenuList), + ]); + } + + /** + * Opens the panel and populates the currently selected fromLang and toLang based + * on the result of the langPairPromise. + * + * @param {Event} event - The triggering event for opening the panel. + * @param {Promise} langPairPromise - Promise resolving to language pair data for initializing dropdowns. + * @returns {Promise} + */ + async open(event, langPairPromise) { + this.console?.log("Showing a translation panel."); + + await this.#ensureLangListsBuilt(); + await this.#updateLanguageDropdowns(langPairPromise); + + // TODO(Bug 1878721) Rework the logic of where to open the panel. + // + // For the moment, the Select Translations panel opens at the + // AppMenu Button, but it will eventually need to open near + // to the selected content. + const appMenuButton = document.getElementById("PanelUI-menu-button"); + const { panel, textArea } = this.elements; + + panel.addEventListener("popupshown", () => textArea.focus(), { + once: true, + }); + await PanelMultiView.openPopup(panel, appMenuButton, { + position: "bottomright topright", + triggerEvent: event, + }).catch(error => this.console?.error(error)); + } +})(); diff --git a/browser/components/translations/content/translationsPanel.inc.xhtml b/browser/components/translations/content/translationsPanel.inc.xhtml deleted file mode 100644 index 18769eec83..0000000000 --- a/browser/components/translations/content/translationsPanel.inc.xhtml +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/browser/components/translations/content/translationsPanel.js b/browser/components/translations/content/translationsPanel.js deleted file mode 100644 index 71aaacac4f..0000000000 --- a/browser/components/translations/content/translationsPanel.js +++ /dev/null @@ -1,1630 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* eslint-env mozilla/browser-window */ - -/* eslint-disable jsdoc/valid-types */ -/** - * @typedef {import("../../../../toolkit/components/translations/translations").LangTags} LangTags - */ -/* eslint-enable jsdoc/valid-types */ - -ChromeUtils.defineESModuleGetters(this, { - PageActions: "resource:///modules/PageActions.sys.mjs", - TranslationsTelemetry: - "chrome://browser/content/translations/TranslationsTelemetry.sys.mjs", -}); - -/** - * The set of actions that can occur from interaction with the - * translations panel. - */ -const PageAction = Object.freeze({ - NO_CHANGE: "NO_CHANGE", - RESTORE_PAGE: "RESTORE_PAGE", - TRANSLATE_PAGE: "TRANSLATE_PAGE", - CLOSE_PANEL: "CLOSE_PANEL", -}); - -/** - * A mechanism for determining the next relevant page action - * based on the current translated state of the page and the state - * of the persistent options in the translations panel settings. - */ -class CheckboxPageAction { - /** - * Whether or not translations is active on the page. - * - * @type {boolean} - */ - #translationsActive = false; - - /** - * Whether the always-translate-language menuitem is checked - * in the translations panel settings menu. - * - * @type {boolean} - */ - #alwaysTranslateLanguage = false; - - /** - * Whether the never-translate-language menuitem is checked - * in the translations panel settings menu. - * - * @type {boolean} - */ - #neverTranslateLanguage = false; - - /** - * Whether the never-translate-site menuitem is checked - * in the translations panel settings menu. - * - * @type {boolean} - */ - #neverTranslateSite = false; - - /** - * @param {boolean} translationsActive - * @param {boolean} alwaysTranslateLanguage - * @param {boolean} neverTranslateLanguage - * @param {boolean} neverTranslateSite - */ - constructor( - translationsActive, - alwaysTranslateLanguage, - neverTranslateLanguage, - neverTranslateSite - ) { - this.#translationsActive = translationsActive; - this.#alwaysTranslateLanguage = alwaysTranslateLanguage; - this.#neverTranslateLanguage = neverTranslateLanguage; - this.#neverTranslateSite = neverTranslateSite; - } - - /** - * Accepts four integers that are either 0 or 1 and returns - * a single, unique number for each possible combination of - * values. - * - * @param {number} translationsActive - * @param {number} alwaysTranslateLanguage - * @param {number} neverTranslateLanguage - * @param {number} neverTranslateSite - * - * @returns {number} - An integer representation of the state - */ - static #computeState( - translationsActive, - alwaysTranslateLanguage, - neverTranslateLanguage, - neverTranslateSite - ) { - return ( - (translationsActive << 3) | - (alwaysTranslateLanguage << 2) | - (neverTranslateLanguage << 1) | - neverTranslateSite - ); - } - - /** - * Returns the current state of the data members as a single number. - * - * @returns {number} - An integer representation of the state - */ - #state() { - return CheckboxPageAction.#computeState( - Number(this.#translationsActive), - Number(this.#alwaysTranslateLanguage), - Number(this.#neverTranslateLanguage), - Number(this.#neverTranslateSite) - ); - } - - /** - * Returns the next page action to take when the always-translate-language - * menuitem is toggled in the translations panel settings menu. - * - * @returns {PageAction} - */ - alwaysTranslateLanguage() { - switch (this.#state()) { - case CheckboxPageAction.#computeState(1, 1, 0, 1): - case CheckboxPageAction.#computeState(1, 1, 0, 0): - return PageAction.RESTORE_PAGE; - case CheckboxPageAction.#computeState(0, 0, 1, 0): - case CheckboxPageAction.#computeState(0, 0, 0, 0): - return PageAction.TRANSLATE_PAGE; - } - return PageAction.NO_CHANGE; - } - - /** - * Returns the next page action to take when the never-translate-language - * menuitem is toggled in the translations panel settings menu. - * - * @returns {PageAction} - */ - neverTranslateLanguage() { - switch (this.#state()) { - case CheckboxPageAction.#computeState(1, 1, 0, 1): - case CheckboxPageAction.#computeState(1, 1, 0, 0): - case CheckboxPageAction.#computeState(1, 0, 0, 1): - case CheckboxPageAction.#computeState(1, 0, 0, 0): - return PageAction.RESTORE_PAGE; - case CheckboxPageAction.#computeState(0, 1, 0, 0): - case CheckboxPageAction.#computeState(0, 0, 0, 1): - case CheckboxPageAction.#computeState(0, 1, 0, 1): - case CheckboxPageAction.#computeState(0, 0, 0, 0): - return PageAction.CLOSE_PANEL; - } - return PageAction.NO_CHANGE; - } - - /** - * Returns the next page action to take when the never-translate-site - * menuitem is toggled in the translations panel settings menu. - * - * @returns {PageAction} - */ - neverTranslateSite() { - switch (this.#state()) { - case CheckboxPageAction.#computeState(1, 1, 0, 0): - case CheckboxPageAction.#computeState(1, 0, 1, 0): - case CheckboxPageAction.#computeState(1, 0, 0, 0): - return PageAction.RESTORE_PAGE; - case CheckboxPageAction.#computeState(0, 1, 0, 1): - return PageAction.TRANSLATE_PAGE; - case CheckboxPageAction.#computeState(0, 0, 1, 0): - case CheckboxPageAction.#computeState(0, 1, 0, 0): - case CheckboxPageAction.#computeState(0, 0, 0, 0): - return PageAction.CLOSE_PANEL; - } - return PageAction.NO_CHANGE; - } -} - -/** - * This singleton class controls the Translations popup panel. - * - * This component is a `/browser` component, and the actor is a `/toolkit` actor, so care - * must be taken to keep the presentation (this component) from the state management - * (the Translations actor). This class reacts to state changes coming from the - * Translations actor. - */ -var TranslationsPanel = new (class { - /** @type {Console?} */ - #console; - - /** - * The cached detected languages for both the document and the user. - * - * @type {null | LangTags} - */ - detectedLanguages = null; - - /** - * Lazily get a console instance. Note that this script is loaded in very early to - * the browser loading process, and may run before the console is avialable. In - * this case the console will return as `undefined`. - * - * @returns {Console | void} - */ - get console() { - if (!this.#console) { - try { - this.#console = console.createInstance({ - maxLogLevelPref: "browser.translations.logLevel", - prefix: "Translations", - }); - } catch { - // The console may not be initialized yet. - } - } - return this.#console; - } - - /** - * Tracks if the popup is open, or scheduled to be open. - * - * @type {boolean} - */ - #isPopupOpen = false; - - /** - * Where the lazy elements are stored. - * - * @type {Record?} - */ - #lazyElements; - - /** - * Lazily creates the dom elements, and lazily selects them. - * - * @returns {Record} - */ - get elements() { - if (!this.#lazyElements) { - // Lazily turn the template into a DOM element. - /** @type {HTMLTemplateElement} */ - const wrapper = document.getElementById("template-translations-panel"); - const panel = wrapper.content.firstElementChild; - wrapper.replaceWith(wrapper.content); - - const settingsButton = document.getElementById( - "translations-panel-settings" - ); - // Clone the settings toolbarbutton across all the views. - for (const header of panel.querySelectorAll(".panel-header")) { - if (header.contains(settingsButton)) { - continue; - } - const settingsButtonClone = settingsButton.cloneNode(true); - settingsButtonClone.removeAttribute("id"); - header.appendChild(settingsButtonClone); - } - - // Lazily select the elements. - this.#lazyElements = { - panel, - settingsButton, - // The rest of the elements are set by the getter below. - }; - - /** - * Define a getter on #lazyElements that gets the element by an id - * or class name. - */ - const getter = (name, discriminator) => { - let element; - Object.defineProperty(this.#lazyElements, name, { - get: () => { - if (!element) { - if (discriminator[0] === ".") { - // Lookup by class - element = document.querySelector(discriminator); - } else { - // Lookup by id - element = document.getElementById(discriminator); - } - } - if (!element) { - throw new Error( - `Could not find "${name}" at "#${discriminator}".` - ); - } - return element; - }, - }); - }; - - // Getters by id - getter("appMenuButton", "PanelUI-menu-button"); - getter("cancelButton", "translations-panel-cancel"); - getter( - "changeSourceLanguageButton", - "translations-panel-change-source-language" - ); - getter("dismissErrorButton", "translations-panel-dismiss-error"); - getter("error", "translations-panel-error"); - getter("errorMessage", "translations-panel-error-message"); - getter("errorMessageHint", "translations-panel-error-message-hint"); - getter("errorHintAction", "translations-panel-translate-hint-action"); - getter("fromMenuList", "translations-panel-from"); - getter("fromLabel", "translations-panel-from-label"); - getter("header", "translations-panel-header"); - getter("intro", "translations-panel-intro"); - getter("introLearnMoreLink", "translations-panel-intro-learn-more-link"); - getter("langSelection", "translations-panel-lang-selection"); - getter("multiview", "translations-panel-multiview"); - getter("restoreButton", "translations-panel-restore-button"); - getter("toLabel", "translations-panel-to-label"); - getter("toMenuList", "translations-panel-to"); - getter("translateButton", "translations-panel-translate"); - getter( - "unsupportedHeader", - "translations-panel-unsupported-language-header" - ); - getter("unsupportedHint", "translations-panel-error-unsupported-hint"); - getter( - "unsupportedLearnMoreLink", - "translations-panel-unsupported-learn-more-link" - ); - - // Getters by class - getter( - "alwaysTranslateLanguageMenuItem", - ".always-translate-language-menuitem" - ); - getter("manageLanguagesMenuItem", ".manage-languages-menuitem"); - getter( - "neverTranslateLanguageMenuItem", - ".never-translate-language-menuitem" - ); - getter("neverTranslateSiteMenuItem", ".never-translate-site-menuitem"); - } - - return this.#lazyElements; - } - - #lazyButtonElements = null; - - /** - * When accessing `this.elements` the first time, it de-lazifies the custom components - * that are needed for the popup. Avoid that by having a second element lookup - * just for modifying the button. - */ - get buttonElements() { - if (!this.#lazyButtonElements) { - this.#lazyButtonElements = { - button: document.getElementById("translations-button"), - buttonLocale: document.getElementById("translations-button-locale"), - buttonCircleArrows: document.getElementById( - "translations-button-circle-arrows" - ), - }; - } - return this.#lazyButtonElements; - } - - /** - * Cache the last command used for error hints so that it can be later removed. - */ - #lastHintCommand = null; - - /** - * @param {object} options - * @param {string} options.message - l10n id - * @param {string} options.hint - l10n id - * @param {string} options.actionText - l10n id - * @param {Function} options.actionCommand - The action to perform. - */ - #showError({ - message, - hint, - actionText: hintCommandText, - actionCommand: hintCommand, - }) { - const { error, errorMessage, errorMessageHint, errorHintAction, intro } = - this.elements; - error.hidden = false; - intro.hidden = true; - document.l10n.setAttributes(errorMessage, message); - - if (hint) { - errorMessageHint.hidden = false; - document.l10n.setAttributes(errorMessageHint, hint); - } else { - errorMessageHint.hidden = true; - } - - if (hintCommand && hintCommandText) { - errorHintAction.removeEventListener("command", this.#lastHintCommand); - this.#lastHintCommand = hintCommand; - errorHintAction.addEventListener("command", hintCommand); - errorHintAction.hidden = false; - document.l10n.setAttributes(errorHintAction, hintCommandText); - } else { - errorHintAction.hidden = true; - } - } - - /** - * @returns {TranslationsParent} - */ - #getTranslationsActor() { - const actor = - gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.getActor( - "Translations" - ); - - if (!actor) { - throw new Error("Unable to get the TranslationsParent"); - } - return actor; - } - - /** - * Fetches the language tags for the document and the user and caches the results - * Use `#getCachedDetectedLanguages` when the lang tags do not need to be re-fetched. - * This requires a bit of work to do, so prefer the cached version when possible. - * - * @returns {Promise} - */ - async #fetchDetectedLanguages() { - this.detectedLanguages = - await this.#getTranslationsActor().getDetectedLanguages(); - return this.detectedLanguages; - } - - /** - * If the detected language tags have been retrieved previously, return the cached - * version. Otherwise do a fresh lookup of the document's language tag. - * - * @returns {Promise} - */ - async #getCachedDetectedLanguages() { - if (!this.detectedLanguages) { - return this.#fetchDetectedLanguages(); - } - return this.detectedLanguages; - } - - /** - * @type {"initialized" | "error" | "uninitialized"} - */ - #langListsPhase = "uninitialized"; - - /** - * Builds the of languages for both the "from" and "to". This can be - * called every time the popup is shown, as it will retry when there is an error - * (such as a network error) or be a noop if it's already initialized. - * - * TODO(Bug 1813796) This needs to be updated when the supported languages change - * via RemoteSettings. - */ - async #ensureLangListsBuilt() { - switch (this.#langListsPhase) { - case "initialized": - // This has already been initialized. - return; - case "error": - // Attempt to re-initialize. - this.#langListsPhase = "uninitialized"; - break; - case "uninitialized": - // Ready to initialize. - break; - default: - this.console?.error("Unknown langList phase", this.#langListsPhase); - } - - try { - /** @type {SupportedLanguages} */ - const { languagePairs, fromLanguages, toLanguages } = - await TranslationsParent.getSupportedLanguages(); - - // Verify that we are in a proper state. - if (languagePairs.length === 0) { - throw new Error("No translation languages were retrieved."); - } - - const { panel } = this.elements; - const fromPopups = panel.querySelectorAll( - ".translations-panel-language-menupopup-from" - ); - const toPopups = panel.querySelectorAll( - ".translations-panel-language-menupopup-to" - ); - - for (const popup of fromPopups) { - for (const { langTag, displayName } of fromLanguages) { - const fromMenuItem = document.createXULElement("menuitem"); - fromMenuItem.setAttribute("value", langTag); - fromMenuItem.setAttribute("label", displayName); - popup.appendChild(fromMenuItem); - } - } - - for (const popup of toPopups) { - for (const { langTag, displayName } of toLanguages) { - const toMenuItem = document.createXULElement("menuitem"); - toMenuItem.setAttribute("value", langTag); - toMenuItem.setAttribute("label", displayName); - popup.appendChild(toMenuItem); - } - } - - this.#langListsPhase = "initialized"; - } catch (error) { - this.console?.error(error); - this.#langListsPhase = "error"; - } - } - - /** - * Reactively sets the views based on the async state changes of the engine, and - * other component state changes. - * - * @param {TranslationsLanguageState} languageState - */ - #updateViewFromTranslationStatus( - languageState = this.#getTranslationsActor().languageState - ) { - const { translateButton, toMenuList, fromMenuList, header, cancelButton } = - this.elements; - const { requestedTranslationPair, isEngineReady } = languageState; - - if ( - requestedTranslationPair && - !isEngineReady && - toMenuList.value === requestedTranslationPair.toLanguage && - fromMenuList.value === requestedTranslationPair.fromLanguage - ) { - // A translation has been requested, but is not ready yet. - document.l10n.setAttributes( - translateButton, - "translations-panel-translate-button-loading" - ); - translateButton.disabled = true; - cancelButton.hidden = false; - this.updateUIForReTranslation(false /* isReTranslation */); - } else { - document.l10n.setAttributes( - translateButton, - "translations-panel-translate-button" - ); - translateButton.disabled = - // The translation languages are the same, don't allow this translation. - toMenuList.value === fromMenuList.value || - // No "to" language was provided. - !toMenuList.value || - // No "from" language was provided. - !fromMenuList.value || - // This is the requested translation pair. - (requestedTranslationPair && - requestedTranslationPair.fromLanguage === fromMenuList.value && - requestedTranslationPair.toLanguage === toMenuList.value); - } - - if (requestedTranslationPair && isEngineReady) { - const { fromLanguage, toLanguage } = requestedTranslationPair; - const displayNames = new Services.intl.DisplayNames(undefined, { - type: "language", - }); - cancelButton.hidden = true; - this.updateUIForReTranslation(true /* isReTranslation */); - - document.l10n.setAttributes(header, "translations-panel-revisit-header", { - fromLanguage: displayNames.of(fromLanguage), - toLanguage: displayNames.of(toLanguage), - }); - } else { - document.l10n.setAttributes(header, "translations-panel-header"); - } - } - - /** - * @param {boolean} isReTranslation - */ - updateUIForReTranslation(isReTranslation) { - const { restoreButton, fromLabel, fromMenuList, toLabel } = this.elements; - restoreButton.hidden = !isReTranslation; - // When offering to re-translate a page, hide the "from" language so users don't - // get confused. - fromLabel.hidden = isReTranslation; - fromMenuList.hidden = isReTranslation; - if (isReTranslation) { - fromLabel.style.marginBlockStart = ""; - toLabel.style.marginBlockStart = 0; - } else { - fromLabel.style.marginBlockStart = 0; - toLabel.style.marginBlockStart = ""; - } - } - - /** - * Returns true if the panel is currently showing the default view, otherwise false. - * - * @returns {boolean} - */ - #isShowingDefaultView() { - if (!this.#lazyElements) { - // Nothing has been initialized. - return false; - } - const { multiview } = this.elements; - return ( - multiview.getAttribute("mainViewId") === "translations-panel-view-default" - ); - } - - /** - * Show the default view of choosing a source and target language. - * - * @param {TranslationsParent} actor - * @param {boolean} force - Force the page to show translation options. - */ - async #showDefaultView(actor, force = false) { - const { - fromMenuList, - multiview, - panel, - error, - toMenuList, - translateButton, - langSelection, - intro, - header, - } = this.elements; - - this.#updateViewFromTranslationStatus(); - - // Unconditionally hide the intro text in case the panel is re-shown. - intro.hidden = true; - - if (this.#langListsPhase === "error") { - // There was an error, display it in the view rather than the language - // dropdowns. - const { cancelButton, errorHintAction } = this.elements; - - this.#showError({ - message: "translations-panel-error-load-languages", - hint: "translations-panel-error-load-languages-hint", - actionText: "translations-panel-error-load-languages-hint-button", - actionCommand: () => this.#reloadLangList(actor), - }); - - translateButton.disabled = true; - this.updateUIForReTranslation(false /* isReTranslation */); - cancelButton.hidden = false; - langSelection.hidden = true; - errorHintAction.disabled = false; - return; - } - - // Remove any old selected values synchronously before asking for new ones. - fromMenuList.value = ""; - error.hidden = true; - langSelection.hidden = false; - - /** @type {null | LangTags} */ - const langTags = await this.#fetchDetectedLanguages(); - if (langTags?.isDocLangTagSupported || force) { - // Show the default view with the language selection - const { cancelButton } = this.elements; - - if (langTags?.isDocLangTagSupported) { - fromMenuList.value = langTags?.docLangTag ?? ""; - } else { - fromMenuList.value = ""; - } - toMenuList.value = langTags?.userLangTag ?? ""; - - this.onChangeLanguages(); - - this.updateUIForReTranslation(false /* isReTranslation */); - cancelButton.hidden = false; - multiview.setAttribute("mainViewId", "translations-panel-view-default"); - - if (!this._hasShownPanel) { - actor.firstShowUriSpec = gBrowser.currentURI.spec; - } - - if ( - this._hasShownPanel && - gBrowser.currentURI.spec !== actor.firstShowUriSpec - ) { - document.l10n.setAttributes(header, "translations-panel-header"); - actor.firstShowUriSpec = null; - intro.hidden = true; - } else { - Services.prefs.setBoolPref("browser.translations.panelShown", true); - intro.hidden = false; - document.l10n.setAttributes(header, "translations-panel-intro-header"); - } - } else { - // Show the "unsupported language" view. - const { unsupportedHint } = this.elements; - multiview.setAttribute( - "mainViewId", - "translations-panel-view-unsupported-language" - ); - let language; - if (langTags?.docLangTag) { - const displayNames = new Intl.DisplayNames(undefined, { - type: "language", - fallback: "none", - }); - language = displayNames.of(langTags.docLangTag); - } - if (language) { - document.l10n.setAttributes( - unsupportedHint, - "translations-panel-error-unsupported-hint-known", - { language } - ); - } else { - document.l10n.setAttributes( - unsupportedHint, - "translations-panel-error-unsupported-hint-unknown" - ); - } - } - - // Focus the "from" language, as it is the only field not set. - panel.addEventListener( - "ViewShown", - () => { - if (!fromMenuList.value) { - fromMenuList.focus(); - } - if (!toMenuList.value) { - toMenuList.focus(); - } - }, - { once: true } - ); - } - - /** - * Updates the checked states of the settings menu checkboxes that - * pertain to languages. - */ - async #updateSettingsMenuLanguageCheckboxStates() { - const langTags = await this.#getCachedDetectedLanguages(); - const { docLangTag, isDocLangTagSupported } = langTags; - - const { panel } = this.elements; - const alwaysTranslateMenuItems = panel.ownerDocument.querySelectorAll( - ".always-translate-language-menuitem" - ); - const neverTranslateMenuItems = panel.ownerDocument.querySelectorAll( - ".never-translate-language-menuitem" - ); - const alwaysOfferTranslationsMenuItems = - panel.ownerDocument.querySelectorAll( - ".always-offer-translations-menuitem" - ); - - const alwaysOfferTranslations = - TranslationsParent.shouldAlwaysOfferTranslations(); - const alwaysTranslateLanguage = - TranslationsParent.shouldAlwaysTranslateLanguage(langTags); - const neverTranslateLanguage = - TranslationsParent.shouldNeverTranslateLanguage(docLangTag); - const shouldDisable = - !docLangTag || - !isDocLangTagSupported || - docLangTag === new Intl.Locale(Services.locale.appLocaleAsBCP47).language; - - for (const menuitem of alwaysOfferTranslationsMenuItems) { - menuitem.setAttribute( - "checked", - alwaysOfferTranslations ? "true" : "false" - ); - } - for (const menuitem of alwaysTranslateMenuItems) { - menuitem.setAttribute( - "checked", - alwaysTranslateLanguage ? "true" : "false" - ); - menuitem.disabled = shouldDisable; - } - for (const menuitem of neverTranslateMenuItems) { - menuitem.setAttribute( - "checked", - neverTranslateLanguage ? "true" : "false" - ); - menuitem.disabled = shouldDisable; - } - } - - /** - * Updates the checked states of the settings menu checkboxes that - * pertain to site permissions. - */ - async #updateSettingsMenuSiteCheckboxStates() { - const { panel } = this.elements; - const neverTranslateSiteMenuItems = panel.ownerDocument.querySelectorAll( - ".never-translate-site-menuitem" - ); - const neverTranslateSite = - await this.#getTranslationsActor().shouldNeverTranslateSite(); - - for (const menuitem of neverTranslateSiteMenuItems) { - menuitem.setAttribute("checked", neverTranslateSite ? "true" : "false"); - } - } - - /** - * Populates the language-related settings menuitems by adding the - * localized display name of the document's detected language tag. - */ - async #populateSettingsMenuItems() { - const { docLangTag } = await this.#getCachedDetectedLanguages(); - - const { panel } = this.elements; - - const alwaysTranslateMenuItems = panel.ownerDocument.querySelectorAll( - ".always-translate-language-menuitem" - ); - const neverTranslateMenuItems = panel.ownerDocument.querySelectorAll( - ".never-translate-language-menuitem" - ); - - /** @type {string | undefined} */ - let docLangDisplayName; - if (docLangTag) { - const displayNames = new Services.intl.DisplayNames(undefined, { - type: "language", - fallback: "none", - }); - // The display name will still be empty if the docLangTag is not known. - docLangDisplayName = displayNames.of(docLangTag); - } - - for (const menuitem of alwaysTranslateMenuItems) { - if (docLangDisplayName) { - document.l10n.setAttributes( - menuitem, - "translations-panel-settings-always-translate-language", - { language: docLangDisplayName } - ); - } else { - document.l10n.setAttributes( - menuitem, - "translations-panel-settings-always-translate-unknown-language" - ); - } - } - - for (const menuitem of neverTranslateMenuItems) { - if (docLangDisplayName) { - document.l10n.setAttributes( - menuitem, - "translations-panel-settings-never-translate-language", - { language: docLangDisplayName } - ); - } else { - document.l10n.setAttributes( - menuitem, - "translations-panel-settings-never-translate-unknown-language" - ); - } - } - - await Promise.all([ - this.#updateSettingsMenuLanguageCheckboxStates(), - this.#updateSettingsMenuSiteCheckboxStates(), - ]); - } - - /** - * Configures the panel for the user to reset the page after it has been translated. - * - * @param {TranslationPair} translationPair - */ - async #showRevisitView({ fromLanguage, toLanguage }) { - const { fromMenuList, toMenuList, intro } = this.elements; - if (!this.#isShowingDefaultView()) { - await this.#showDefaultView(this.#getTranslationsActor()); - } - intro.hidden = true; - fromMenuList.value = fromLanguage; - toMenuList.value = toLanguage; - this.onChangeLanguages(); - } - - /** - * Handle the disable logic for when the menulist is changed for the "Translate to" - * on the "revisit" subview. - */ - onChangeRevisitTo() { - const { revisitTranslate, revisitMenuList } = this.elements; - revisitTranslate.disabled = !revisitMenuList.value; - } - - /** - * Handle logic and telemetry for changing the selected from-language option. - * - * @param {Event} event - */ - onChangeFromLanguage(event) { - const { target } = event; - if (target?.value) { - TranslationsParent.telemetry().panel().onChangeFromLanguage(target.value); - } - this.onChangeLanguages(); - } - - /** - * Handle logic and telemetry for changing the selected to-language option. - * - * @param {Event} event - */ - onChangeToLanguage(event) { - const { target } = event; - if (target?.value) { - TranslationsParent.telemetry().panel().onChangeToLanguage(target.value); - } - this.onChangeLanguages(); - } - - /** - * When changing the language selection, the translate button will need updating. - */ - onChangeLanguages() { - this.#updateViewFromTranslationStatus(); - } - - /** - * Hide the pop up (for event handlers). - */ - close() { - PanelMultiView.hidePopup(this.elements.panel); - } - - /* - * Handler for clicking the learn more link from linked text - * within the translations panel. - */ - onLearnMoreLink() { - TranslationsParent.telemetry().panel().onLearnMoreLink(); - TranslationsPanel.close(); - } - - /* - * Handler for clicking the learn more link from the gear menu. - */ - onAboutTranslations() { - TranslationsParent.telemetry().panel().onAboutTranslations(); - PanelMultiView.hidePopup(this.elements.panel); - const window = - gBrowser.selectedBrowser.browsingContext.top.embedderElement.ownerGlobal; - window.openTrustedLinkIn( - "https://support.mozilla.org/kb/website-translation", - "tab", - { - forceForeground: true, - triggeringPrincipal: - Services.scriptSecurityManager.getSystemPrincipal(), - } - ); - } - - /** - * When a language is not supported and the menu is manually invoked, an error message - * is shown. This method switches the panel back to the language selection view. - * Note that this bypasses the showSubView method since the main view doesn't support - * a subview. - */ - async onChangeSourceLanguage(event) { - const { panel } = this.elements; - PanelMultiView.hidePopup(panel); - - await this.#showDefaultView( - this.#getTranslationsActor(), - true /* force this view to be shown */ - ); - - await this.#openPanelPopup(this.elements.appMenuButton, { - event, - viewName: "defaultView", - maintainFlow: true, - }); - } - - /** - * @param {TranslationsActor} actor - */ - async #reloadLangList(actor) { - try { - await this.#ensureLangListsBuilt(); - await this.#showDefaultView(actor); - } catch (error) { - this.elements.errorHintAction.disabled = false; - } - } - - /** - * Handle telemetry events when buttons are invoked in the panel. - * - * @param {Event} event - */ - handlePanelButtonEvent(event) { - const { - cancelButton, - changeSourceLanguageButton, - dismissErrorButton, - restoreButton, - translateButton, - } = this.elements; - switch (event.target.id) { - case cancelButton.id: { - TranslationsParent.telemetry().panel().onCancelButton(); - break; - } - case changeSourceLanguageButton.id: { - TranslationsParent.telemetry().panel().onChangeSourceLanguageButton(); - break; - } - case dismissErrorButton.id: { - TranslationsParent.telemetry().panel().onDismissErrorButton(); - break; - } - case restoreButton.id: { - TranslationsParent.telemetry().panel().onRestorePageButton(); - break; - } - case translateButton.id: { - TranslationsParent.telemetry().panel().onTranslateButton(); - break; - } - } - } - - /** - * Handle telemetry events when popups are shown in the panel. - * - * @param {Event} event - */ - handlePanelPopupShownEvent(event) { - const { panel, fromMenuList, toMenuList } = this.elements; - switch (event.target.id) { - case panel.id: { - // This telemetry event is invoked externally because it requires - // extra logic about from where the panel was opened and whether - // or not the flow should be maintained or started anew. - break; - } - case fromMenuList.firstChild.id: { - TranslationsParent.telemetry().panel().onOpenFromLanguageMenu(); - break; - } - case toMenuList.firstChild.id: { - TranslationsParent.telemetry().panel().onOpenToLanguageMenu(); - break; - } - } - } - - /** - * Handle telemetry events when popups are hidden in the panel. - * - * @param {Event} event - */ - handlePanelPopupHiddenEvent(event) { - const { panel, fromMenuList, toMenuList } = this.elements; - switch (event.target.id) { - case panel.id: { - TranslationsParent.telemetry().panel().onClose(); - this.#isPopupOpen = false; - this.elements.error.hidden = true; - break; - } - case fromMenuList.firstChild.id: { - TranslationsParent.telemetry().panel().onCloseFromLanguageMenu(); - break; - } - case toMenuList.firstChild.id: { - TranslationsParent.telemetry().panel().onCloseToLanguageMenu(); - break; - } - } - } - - /** - * Handle telemetry events when the settings menu is shown. - */ - handleSettingsPopupShownEvent() { - TranslationsParent.telemetry().panel().onOpenSettingsMenu(); - } - - /** - * Handle telemetry events when the settings menu is hidden. - */ - handleSettingsPopupHiddenEvent() { - TranslationsParent.telemetry().panel().onCloseSettingsMenu(); - } - - /** - * Opens the Translations panel popup at the given target. - * - * @param {object} target - The target element at which to open the popup. - * @param {object} telemetryData - * @param {string} telemetryData.event - * The trigger event for opening the popup. - * @param {string} telemetryData.viewName - * The name of the view shown by the panel. - * @param {boolean} telemetryData.autoShow - * True if the panel was automatically opened, otherwise false. - * @param {boolean} telemetryData.maintainFlow - * Whether or not to maintain the flow of telemetry. - * @param {boolean} telemetryData.isFirstUserInteraction - * Whether or not this is the first user interaction with the panel. - */ - async #openPanelPopup( - target, - { - event = null, - viewName = null, - autoShow = false, - maintainFlow = false, - isFirstUserInteraction = null, - } - ) { - await window.ensureCustomElements("moz-button-group"); - - const { panel, appMenuButton } = this.elements; - const openedFromAppMenu = target.id === appMenuButton.id; - const { docLangTag } = await this.#getCachedDetectedLanguages(); - - TranslationsParent.telemetry().panel().onOpen({ - viewName, - autoShow, - docLangTag, - maintainFlow, - openedFromAppMenu, - isFirstUserInteraction, - }); - - this.#isPopupOpen = true; - - PanelMultiView.openPopup(panel, target, { - position: "bottomright topright", - triggerEvent: event, - }).catch(error => this.console?.error(error)); - } - - /** - * Keeps track of open requests to guard against race conditions. - * - * @type {Promise | null} - */ - #openPromise = null; - - /** - * Opens the TranslationsPanel. - * - * @param {Event} event - * @param {boolean} reportAsAutoShow - * True to report to telemetry that the panel was opened automatically, otherwise false. - */ - async open(event, reportAsAutoShow = false) { - if (this.#openPromise) { - // There is already an open event happening, do not open. - return; - } - - this.#openPromise = this.#openImpl(event, reportAsAutoShow); - this.#openPromise.finally(() => { - this.#openPromise = null; - }); - } - - /** - * Implementation function for opening the panel. Prefer TranslationsPanel.open. - * - * @param {Event} event - */ - async #openImpl(event, reportAsAutoShow) { - event.stopPropagation(); - if ( - (event.type == "click" && event.button != 0) || - (event.type == "keypress" && - event.charCode != KeyEvent.DOM_VK_SPACE && - event.keyCode != KeyEvent.DOM_VK_RETURN) - ) { - // Allow only left click, space, or enter. - return; - } - - const window = - gBrowser.selectedBrowser.browsingContext.top.embedderElement.ownerGlobal; - window.ensureCustomElements("moz-support-link"); - - const { button } = this.buttonElements; - - const { requestedTranslationPair, locationChangeId } = - this.#getTranslationsActor().languageState; - - // Store this value because it gets modified when #showDefaultView is called below. - const isFirstUserInteraction = !this._hasShownPanel; - - await this.#ensureLangListsBuilt(); - - if (requestedTranslationPair) { - await this.#showRevisitView(requestedTranslationPair).catch(error => { - this.console?.error(error); - }); - } else { - await this.#showDefaultView(this.#getTranslationsActor()).catch(error => { - this.console?.error(error); - }); - } - - this.#populateSettingsMenuItems(); - - const targetButton = - button.contains(event.target) || - event.type === "TranslationsParent:OfferTranslation" - ? button - : this.elements.appMenuButton; - - if (!TranslationsParent.isActiveLocation(locationChangeId)) { - this.console?.log(`A translation panel open request was stale.`, { - locationChangeId, - newlocationChangeId: - this.#getTranslationsActor().languageState.locationChangeId, - currentURISpec: gBrowser.currentURI.spec, - }); - return; - } - - this.console?.log(`Showing a translation panel`, gBrowser.currentURI.spec); - - await this.#openPanelPopup(targetButton, { - event, - autoShow: reportAsAutoShow, - viewName: requestedTranslationPair ? "revisitView" : "defaultView", - maintainFlow: false, - isFirstUserInteraction, - }); - } - - /** - * Returns true if translations is currently active, otherwise false. - * - * @returns {boolean} - */ - #isTranslationsActive() { - const { requestedTranslationPair } = - this.#getTranslationsActor().languageState; - return requestedTranslationPair !== null; - } - - /** - * Handle the translation button being clicked when there are two language options. - */ - async onTranslate() { - PanelMultiView.hidePopup(this.elements.panel); - - const actor = this.#getTranslationsActor(); - actor.translate( - this.elements.fromMenuList.value, - this.elements.toMenuList.value, - false // reportAsAutoTranslate - ); - } - - /** - * Handle the cancel button being clicked. - */ - onCancel() { - PanelMultiView.hidePopup(this.elements.panel); - } - - /** - * A handler for opening the settings context menu. - */ - openSettingsPopup(button) { - this.#updateSettingsMenuLanguageCheckboxStates(); - this.#updateSettingsMenuSiteCheckboxStates(); - const popup = button.ownerDocument.getElementById( - "translations-panel-settings-menupopup" - ); - popup.openPopup(button, "after_end"); - } - - /** - * Creates a new CheckboxPageAction based on the current translated - * state of the page and the state of the persistent options in the - * translations panel settings. - * - * @returns {CheckboxPageAction} - */ - getCheckboxPageActionFor() { - const { - alwaysTranslateLanguageMenuItem, - neverTranslateLanguageMenuItem, - neverTranslateSiteMenuItem, - } = this.elements; - - const alwaysTranslateLanguage = - alwaysTranslateLanguageMenuItem.getAttribute("checked") === "true"; - const neverTranslateLanguage = - neverTranslateLanguageMenuItem.getAttribute("checked") === "true"; - const neverTranslateSite = - neverTranslateSiteMenuItem.getAttribute("checked") === "true"; - - return new CheckboxPageAction( - this.#isTranslationsActive(), - alwaysTranslateLanguage, - neverTranslateLanguage, - neverTranslateSite - ); - } - - /** - * Redirect the user to about:preferences - */ - openManageLanguages() { - TranslationsParent.telemetry().panel().onManageLanguages(); - const window = - gBrowser.selectedBrowser.browsingContext.top.embedderElement.ownerGlobal; - window.openTrustedLinkIn("about:preferences#general-translations", "tab"); - } - - /** - * Performs the given page action. - * - * @param {PageAction} pageAction - */ - async #doPageAction(pageAction) { - switch (pageAction) { - case PageAction.NO_CHANGE: { - break; - } - case PageAction.RESTORE_PAGE: { - await this.onRestore(); - break; - } - case PageAction.TRANSLATE_PAGE: { - await this.onTranslate(); - break; - } - case PageAction.CLOSE_PANEL: { - PanelMultiView.hidePopup(this.elements.panel); - break; - } - } - } - - /** - * Updates the always-translate-language menuitem prefs and checked state. - * If auto-translate is currently active for the doc language, deactivates it. - * If auto-translate is currently inactive for the doc language, activates it. - */ - async onAlwaysTranslateLanguage() { - const langTags = await this.#getCachedDetectedLanguages(); - const { docLangTag } = langTags; - if (!docLangTag) { - throw new Error("Expected to have a document language tag."); - } - const pageAction = - this.getCheckboxPageActionFor().alwaysTranslateLanguage(); - const toggledOn = - TranslationsParent.toggleAlwaysTranslateLanguagePref(langTags); - TranslationsParent.telemetry() - .panel() - .onAlwaysTranslateLanguage(docLangTag, toggledOn); - this.#updateSettingsMenuLanguageCheckboxStates(); - await this.#doPageAction(pageAction); - } - - /** - * Toggle offering translations. - */ - async onAlwaysOfferTranslations() { - const toggledOn = TranslationsParent.toggleAutomaticallyPopupPref(); - TranslationsParent.telemetry().panel().onAlwaysOfferTranslations(toggledOn); - } - - /** - * Updates the never-translate-language menuitem prefs and checked state. - * If never-translate is currently active for the doc language, deactivates it. - * If never-translate is currently inactive for the doc language, activates it. - */ - async onNeverTranslateLanguage() { - const { docLangTag } = await this.#getCachedDetectedLanguages(); - if (!docLangTag) { - throw new Error("Expected to have a document language tag."); - } - const pageAction = this.getCheckboxPageActionFor().neverTranslateLanguage(); - const toggledOn = - TranslationsParent.toggleNeverTranslateLanguagePref(docLangTag); - TranslationsParent.telemetry() - .panel() - .onNeverTranslateLanguage(docLangTag, toggledOn); - this.#updateSettingsMenuLanguageCheckboxStates(); - await this.#doPageAction(pageAction); - } - - /** - * Updates the never-translate-site menuitem permissions and checked state. - * If never-translate is currently active for the site, deactivates it. - * If never-translate is currently inactive for the site, activates it. - */ - async onNeverTranslateSite() { - const pageAction = this.getCheckboxPageActionFor().neverTranslateSite(); - const toggledOn = - await this.#getTranslationsActor().toggleNeverTranslateSitePermissions(); - TranslationsParent.telemetry().panel().onNeverTranslateSite(toggledOn); - this.#updateSettingsMenuSiteCheckboxStates(); - await this.#doPageAction(pageAction); - } - - /** - * Handle the restore button being clicked. - */ - async onRestore() { - const { panel } = this.elements; - PanelMultiView.hidePopup(panel); - const { docLangTag } = await this.#getCachedDetectedLanguages(); - if (!docLangTag) { - throw new Error("Expected to have a document language tag."); - } - - this.#getTranslationsActor().restorePage(docLangTag); - } - - /** - * An event handler that allows the TranslationsPanel object - * to be compatible with the addTabsProgressListener function. - * - * @param {tabbrowser} browser - */ - onLocationChange(browser) { - if (browser.currentURI.spec.startsWith("about:reader")) { - // Hide the translations button when entering reader mode. - this.buttonElements.button.hidden = true; - } - } - - /** - * Update the view to show an error. - * - * @param {TranslationParent} actor - */ - async #showEngineError(actor) { - const { button } = this.buttonElements; - await this.#ensureLangListsBuilt(); - if (!this.#isShowingDefaultView()) { - await this.#showDefaultView(actor).catch(e => { - this.console?.error(e); - }); - } - this.elements.error.hidden = false; - this.#showError({ - message: "translations-panel-error-translating", - }); - const targetButton = button.hidden ? this.elements.appMenuButton : button; - - // Re-open the menu on an error. - await this.#openPanelPopup(targetButton, { - autoShow: true, - viewName: "errorView", - maintainFlow: true, - }); - } - - /** - * Set the state of the translations button in the URL bar. - * - * @param {CustomEvent} event - */ - handleEvent = event => { - switch (event.type) { - case "TranslationsParent:OfferTranslation": { - if (Services.wm.getMostRecentBrowserWindow()?.gBrowser === gBrowser) { - this.open(event, /* reportAsAutoShow */ true); - } - break; - } - case "TranslationsParent:LanguageState": { - const { actor } = event.detail; - const { - detectedLanguages, - requestedTranslationPair, - error, - isEngineReady, - } = actor.languageState; - - const { button, buttonLocale, buttonCircleArrows } = - this.buttonElements; - - const hasSupportedLanguage = - detectedLanguages?.docLangTag && - detectedLanguages?.userLangTag && - detectedLanguages?.isDocLangTagSupported; - - if (detectedLanguages) { - // Ensure the cached detected languages are up to date, for instance whenever - // the user switches tabs. - TranslationsPanel.detectedLanguages = detectedLanguages; - } - - if (this.#isPopupOpen) { - // Make sure to use the language state that is passed by the event.detail, and - // don't read it from the actor here, as it's possible the actor isn't available - // via the gBrowser.selectedBrowser. - this.#updateViewFromTranslationStatus(actor.languageState); - } - - if ( - // We've already requested to translate this page, so always show the icon. - requestedTranslationPair || - // There was an error translating, so always show the icon. This can happen - // when a user manually invokes the translation and we wouldn't normally show - // the icon. - error || - // Finally check that we can translate this language. - (hasSupportedLanguage && - TranslationsParent.getIsTranslationsEngineSupported()) - ) { - // Keep track if the button was originally hidden, because it will be shown now. - const wasButtonHidden = button.hidden; - - button.hidden = false; - if (requestedTranslationPair) { - // The translation is active, update the urlbar button. - button.setAttribute("translationsactive", true); - if (isEngineReady) { - const displayNames = new Services.intl.DisplayNames(undefined, { - type: "language", - }); - - document.l10n.setAttributes( - button, - "urlbar-translations-button-translated", - { - fromLanguage: displayNames.of( - requestedTranslationPair.fromLanguage - ), - toLanguage: displayNames.of( - requestedTranslationPair.toLanguage - ), - } - ); - // Show the locale of the page in the button. - buttonLocale.hidden = false; - buttonCircleArrows.hidden = true; - buttonLocale.innerText = requestedTranslationPair.toLanguage; - } else { - document.l10n.setAttributes( - button, - "urlbar-translations-button-loading" - ); - // Show the spinning circle arrows to indicate that the engine is - // still loading. - buttonCircleArrows.hidden = false; - buttonLocale.hidden = true; - } - } else { - // The translation is not active, update the urlbar button. - button.removeAttribute("translationsactive"); - buttonLocale.hidden = true; - buttonCircleArrows.hidden = true; - - // Follow the same rules for displaying the first-run intro text for the - // button's accessible tooltip label. - if ( - this._hasShownPanel && - gBrowser.currentURI.spec !== actor.firstShowUriSpec - ) { - document.l10n.setAttributes( - button, - "urlbar-translations-button2" - ); - } else { - document.l10n.setAttributes( - button, - "urlbar-translations-button-intro" - ); - } - } - - // The button was hidden, but now it is shown. - if (wasButtonHidden) { - PageActions.sendPlacedInUrlbarTrigger(button); - } - } else if (!button.hidden) { - // There are no translations visible, hide the button. - button.hidden = true; - } - - switch (error) { - case null: - break; - case "engine-load-failure": - this.#showEngineError(actor).catch(viewError => - this.console.error(viewError) - ); - break; - default: - console.error("Unknown translation error", error); - } - break; - } - } - }; -})(); - -XPCOMUtils.defineLazyPreferenceGetter( - TranslationsPanel, - "_hasShownPanel", - "browser.translations.panelShown", - false -); diff --git a/browser/components/translations/jar.mn b/browser/components/translations/jar.mn index 5f30e6f73f..fe552d2c9a 100644 --- a/browser/components/translations/jar.mn +++ b/browser/components/translations/jar.mn @@ -3,4 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. browser.jar: - content/browser/translations/translationsPanel.js (content/translationsPanel.js) + content/browser/translations/selectTranslationsPanel.js (content/selectTranslationsPanel.js) + content/browser/translations/fullPageTranslationsPanel.js (content/fullPageTranslationsPanel.js) + content/browser/translations/TranslationsPanelShared.sys.mjs (content/TranslationsPanelShared.sys.mjs) diff --git a/browser/components/translations/tests/browser/browser.toml b/browser/components/translations/tests/browser/browser.toml index bc617bf2fd..a9d36363da 100644 --- a/browser/components/translations/tests/browser/browser.toml +++ b/browser/components/translations/tests/browser/browser.toml @@ -15,96 +15,100 @@ support-files = [ ["browser_translations_about_preferences_settings_ui.js"] -["browser_translations_panel_a11y_focus.js"] +["browser_translations_full_page_panel_a11y_focus.js"] -["browser_translations_panel_always_translate_language_bad_data.js"] +["browser_translations_full_page_panel_always_translate_language_bad_data.js"] -["browser_translations_panel_always_translate_language_basic.js"] +["browser_translations_full_page_panel_always_translate_language_basic.js"] -["browser_translations_panel_always_translate_language_manual.js"] +["browser_translations_full_page_panel_always_translate_language_manual.js"] -["browser_translations_panel_always_translate_language_restore.js"] +["browser_translations_full_page_panel_always_translate_language_restore.js"] -["browser_translations_panel_app_menu_never_translate_language.js"] +["browser_translations_full_page_panel_app_menu_never_translate_language.js"] -["browser_translations_panel_app_menu_never_translate_site.js"] +["browser_translations_full_page_panel_app_menu_never_translate_site.js"] -["browser_translations_panel_auto_translate_error_view.js"] +["browser_translations_full_page_panel_auto_translate_error_view.js"] -["browser_translations_panel_auto_translate_revisit_view.js"] +["browser_translations_full_page_panel_auto_translate_revisit_view.js"] -["browser_translations_panel_basics.js"] +["browser_translations_full_page_panel_basics.js"] -["browser_translations_panel_button.js"] +["browser_translations_full_page_panel_button.js"] -["browser_translations_panel_cancel.js"] +["browser_translations_full_page_panel_cancel.js"] -["browser_translations_panel_close_panel_never_translate_language_with_translations_active.js"] +["browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_active.js"] -["browser_translations_panel_close_panel_never_translate_language_with_translations_inactive.js"] +["browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_inactive.js"] -["browser_translations_panel_close_panel_never_translate_site.js"] +["browser_translations_full_page_panel_close_panel_never_translate_site.js"] -["browser_translations_panel_engine_destroy.js"] +["browser_translations_full_page_panel_engine_destroy.js"] -["browser_translations_panel_engine_destroy_pending.js"] +["browser_translations_full_page_panel_engine_destroy_pending.js"] -["browser_translations_panel_engine_unsupported.js"] +["browser_translations_full_page_panel_engine_unsupported.js"] -["browser_translations_panel_engine_unsupported_lang.js"] +["browser_translations_full_page_panel_engine_unsupported_lang.js"] -["browser_translations_panel_firstrun.js"] +["browser_translations_full_page_panel_firstrun.js"] -["browser_translations_panel_firstrun_revisit.js"] +["browser_translations_full_page_panel_firstrun_revisit.js"] -["browser_translations_panel_fuzzing.js"] +["browser_translations_full_page_panel_fuzzing.js"] skip-if = ["true"] -["browser_translations_panel_gear.js"] +["browser_translations_full_page_panel_gear.js"] -["browser_translations_panel_never_translate_language.js"] +["browser_translations_full_page_panel_never_translate_language.js"] -["browser_translations_panel_never_translate_site_auto.js"] +["browser_translations_full_page_panel_never_translate_site_auto.js"] -["browser_translations_panel_never_translate_site_basic.js"] +["browser_translations_full_page_panel_never_translate_site_basic.js"] -["browser_translations_panel_never_translate_site_manual.js"] +["browser_translations_full_page_panel_never_translate_site_manual.js"] -["browser_translations_panel_retry.js"] +["browser_translations_full_page_panel_retry.js"] skip-if = ["os == 'linux' && !debug"] # Bug 1863227 -["browser_translations_panel_settings_unsupported_lang.js"] +["browser_translations_full_page_panel_settings_unsupported_lang.js"] -["browser_translations_panel_switch_languages.js"] +["browser_translations_full_page_panel_switch_languages.js"] -["browser_translations_reader_mode.js"] +["browser_translations_full_page_reader_mode.js"] -["browser_translations_select_context_menu_feature_disabled.js"] +["browser_translations_full_page_telemetry_firstrun_auto_translate.js"] -["browser_translations_select_context_menu_with_full_page_translations_active.js"] +["browser_translations_full_page_telemetry_firstrun_basics.js"] -["browser_translations_select_context_menu_with_hyperlink.js"] +["browser_translations_full_page_telemetry_firstrun_translation_failure.js"] -["browser_translations_select_context_menu_with_no_text_selected.js"] +["browser_translations_full_page_telemetry_firstrun_unsupported_lang.js"] -["browser_translations_select_context_menu_with_text_selected.js"] +["browser_translations_full_page_telemetry_open_panel.js"] + +["browser_translations_full_page_telemetry_panel_auto_offer.js"] -["browser_translations_telemetry_firstrun_auto_translate.js"] +["browser_translations_full_page_telemetry_panel_auto_offer_settings.js"] -["browser_translations_telemetry_firstrun_basics.js"] +["browser_translations_full_page_telemetry_switch_languages.js"] -["browser_translations_telemetry_firstrun_translation_failure.js"] +["browser_translations_full_page_telemetry_translation_failure.js"] -["browser_translations_telemetry_firstrun_unsupported_lang.js"] +["browser_translations_full_page_telemetry_translation_request.js"] -["browser_translations_telemetry_open_panel.js"] +["browser_translations_select_context_menu_feature_disabled.js"] + +["browser_translations_select_context_menu_with_full_page_translations_active.js"] -["browser_translations_telemetry_panel_auto_offer.js"] +["browser_translations_select_context_menu_with_hyperlink.js"] -["browser_translations_telemetry_panel_auto_offer_settings.js"] +["browser_translations_select_context_menu_with_no_text_selected.js"] -["browser_translations_telemetry_switch_languages.js"] +["browser_translations_select_context_menu_with_text_selected.js"] -["browser_translations_telemetry_translation_failure.js"] +["browser_translations_select_panel_language_selectors.js"] -["browser_translations_telemetry_translation_request.js"] +["browser_translations_select_panel_mainview_ui.js"] diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_a11y_focus.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_a11y_focus.js new file mode 100644 index 0000000000..433861c05a --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_a11y_focus.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the a11y focus behavior. + */ +add_task(async function test_translations_panel_a11y_focus() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.openPanel({ + openWithKeyboard: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + is( + document.activeElement.getAttribute("data-l10n-id"), + "translations-panel-settings-button", + "The settings button is focused." + ); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_bad_data.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_bad_data.js new file mode 100644 index 0000000000..144488ac7b --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_bad_data.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that having an "always translate" set to your app locale doesn't break things. + */ +add_task(async function test_always_translate_with_bad_data() { + const { cleanup, runInPage } = await loadTestPage({ + page: ENGLISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.alwaysTranslateLanguages", "en,fr"]], + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + openFromAppMenu: true, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("en", { + checked: false, + disabled: true, + }); + await closeAllOpenPanelsAndMenus(); + + info("Checking that the page is untranslated"); + await runInPage(async TranslationsTest => { + const { getH1 } = TranslationsTest.getSelectors(); + await TranslationsTest.assertTranslationResult( + "The page's H1 is untranslated and in the original English.", + getH1, + '"The Wonderful Wizard of Oz" by L. Frank Baum' + ); + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_basic.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_basic.js new file mode 100644 index 0000000000..bd9a8a7756 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_basic.js @@ -0,0 +1,79 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of toggling the always-translate-language menuitem. + * Checking the box on an untranslated page should immediately translate the page. + * Unchecking the box on a translated page should immediately restore the page. + */ +add_task(async function test_toggle_always_translate_language_menuitem() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage, + "The page should be automatically translated." + ); + + await navigate("Navigate to a different Spanish page", { + url: SPANISH_PAGE_URL_DOT_ORG, + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage, + "The page should be automatically translated." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage(); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "Only the button appears" + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_manual.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_manual.js new file mode 100644 index 0000000000..d47732aa5c --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_manual.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of toggling the always-translate-language menuitem after the page has + * been manually translated. This should not reload or retranslate the page, but just check + * the box. + */ +add_task( + async function test_activate_always_translate_language_after_manual_translation() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage(); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage(); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "Only the button appears" + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_restore.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_restore.js new file mode 100644 index 0000000000..cd3fe76c58 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_always_translate_language_restore.js @@ -0,0 +1,101 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of unchecking the always-translate language menuitem after the page has + * been manually restored to its original form. + * This should have no effect on the page, and further page loads should no longer auto-translate. + */ +add_task( + async function test_deactivate_always_translate_language_after_restore() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage, + "The page should be automatically translated." + ); + + await navigate("Navigate to a different Spanish page", { + url: SPANISH_PAGE_URL_DOT_ORG, + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage, + "The page should be automatically translated." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + + await FullPageTranslationsTestUtils.clickRestoreButton(); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is reverted to have an icon." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage(); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button shows only the icon." + ); + + await navigate("Reload the page", { url: SPANISH_PAGE_URL_DOT_ORG }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button shows only the icon." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_app_menu_never_translate_language.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_app_menu_never_translate_language.js new file mode 100644 index 0000000000..14eb88f71f --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_app_menu_never_translate_language.js @@ -0,0 +1,40 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of unchecking the never-translate-language menuitem, removing + * the language from the never-translate languages list. + * The translations button should reappear. + */ +add_task(async function test_uncheck_never_translate_language_shows_button() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.neverTranslateLanguages", "es"]], + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is available" + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_app_menu_never_translate_site.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_app_menu_never_translate_site.js new file mode 100644 index 0000000000..3670bb7ba1 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_app_menu_never_translate_site.js @@ -0,0 +1,140 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of unchecking the never-translate-site menuitem, + * regranting translations permissions to this page. + * The translations button should reappear. + */ +add_task(async function test_uncheck_never_translate_site_shows_button() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await cleanup(); +}); + +/** + * Tests the effect of unchecking the never-translate-site menuitem while + * the current language is in the always-translate languages list, regranting + * translations permissions to this page. + * The page should automatically translate. + */ +add_task( + async function test_uncheck_never_translate_site_with_always_translate_language() { + const { cleanup, runInPage, resolveDownloads } = await loadTestPage({ + page: BLANK_PAGE, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.alwaysTranslateLanguages", "es"]], + }); + + await navigate("Navigate to a Spanish page", { + url: SPANISH_PAGE_URL, + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_auto_translate_error_view.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_auto_translate_error_view.js new file mode 100644 index 0000000000..9470133dd0 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_auto_translate_error_view.js @@ -0,0 +1,86 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { PromiseTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PromiseTestUtils.sys.mjs" +); + +/** + * This tests a specific defect where the error view was not showing properly + * when navigating to an auto-translated page after visiting a page in an unsupported + * language and viewing the panel. + * + * This test case tests the case where the auto translate fails and the panel + * automatically opens the panel to show the error view. + * + * See https://bugzilla.mozilla.org/show_bug.cgi?id=1845611 for more information. + */ +add_task( + async function test_revisit_view_updates_with_auto_translate_failure() { + const { cleanup, resolveDownloads, rejectDownloads, runInPage } = + await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: [ + // Do not include French. + { fromLang: "en", toLang: "es" }, + { fromLang: "es", toLang: "en" }, + ], + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await navigate("Navigate to a page in an unsupported language", { + url: FRENCH_PAGE_URL, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: false }, + "The translations button should be unavailable." + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: + FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, + }); + + info("Destroy the engine process so that an error will happen."); + await EngineProcess.destroyTranslationsEngine(); + + await navigate("Navigate back to a Spanish page.", { + url: SPANISH_PAGE_URL_DOT_ORG, + downloadHandler: rejectDownloads, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewError, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_auto_translate_revisit_view.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_auto_translate_revisit_view.js new file mode 100644 index 0000000000..f898300038 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_auto_translate_revisit_view.js @@ -0,0 +1,86 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * This tests a specific defect where the revisit view was not showing properly + * when navigating to an auto-translated page after visiting a page in an unsupported + * language and viewing the panel. + * + * This test case tests the case where the auto translate succeeds and the user + * manually opens the panel to show the revisit view. + * + * See https://bugzilla.mozilla.org/show_bug.cgi?id=1845611 for more information. + */ +add_task( + async function test_revisit_view_updates_with_auto_translate_success() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: [ + // Do not include French. + { fromLang: "en", toLang: "es" }, + { fromLang: "es", toLang: "en" }, + ], + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await navigate("Navigate to a page in an unsupported language", { + url: FRENCH_PAGE_URL, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: false }, + "The translations button should be unavailable." + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: + FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, + }); + + await navigate("Navigate back to the Spanish page.", { + url: SPANISH_PAGE_URL_DOT_ORG, + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_basics.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_basics.js new file mode 100644 index 0000000000..30880553f0 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_basics.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests a basic panel open, translation, and restoration to the original language. + */ +add_task(async function test_translations_panel_basics() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + const { button } = + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + is(button.getAttribute("data-l10n-id"), "urlbar-translations-button2"); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + const panel = document.getElementById("full-page-translations-panel"); + const label = document.getElementById(panel.getAttribute("aria-labelledby")); + ok(label, "The a11y label for the panel can be found."); + assertVisibility({ visible: { label } }); + + await FullPageTranslationsTestUtils.clickTranslateButton(); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: true, locale: false, icon: true }, + "The icon presents the loading indicator." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewLoading, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await resolveDownloads(1); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + + await FullPageTranslationsTestUtils.clickRestoreButton(); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is reverted to have an icon." + ); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_button.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_button.js new file mode 100644 index 0000000000..209cfc18a6 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_button.js @@ -0,0 +1,77 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Test that the translations button is correctly visible when navigating between pages. + */ +add_task(async function test_button_visible_navigation() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button should be visible since the page can be translated from Spanish." + ); + + await navigate("Navigate to an English page.", { url: ENGLISH_PAGE_URL }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: false }, + "The button should be invisible since the page is in English." + ); + + await navigate("Navigate back to a Spanish page.", { url: SPANISH_PAGE_URL }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button should be visible again since the page is in Spanish." + ); + + await cleanup(); +}); + +/** + * Test that the translations button is correctly visible when opening and switch tabs. + */ +add_task(async function test_button_visible() { + const { cleanup, tab: spanishTab } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button should be visible since the page can be translated from Spanish." + ); + + const { removeTab, tab: englishTab } = await addTab( + ENGLISH_PAGE_URL, + "Creating a new tab for a page in English." + ); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: false }, + "The button should be invisible since the tab is in English." + ); + + await switchTab(spanishTab, "spanish tab"); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button should be visible again since the page is in Spanish." + ); + + await switchTab(englishTab, "english tab"); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: false }, + "Don't show for english pages" + ); + + await removeTab(); + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_cancel.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_cancel.js new file mode 100644 index 0000000000..9a0a3ebccb --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_cancel.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests a panel open, and hitting the cancel button. + */ +add_task(async function test_translations_panel_cancel() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_active.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_active.js new file mode 100644 index 0000000000..e76c771ed9 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_active.js @@ -0,0 +1,147 @@ +"use strict"; + +/** + * Tests the effect of checking the never-translate-language menuitem on a page where + * translations are active (always-translate-language is enabled). + * Checking the box on the page automatically closes/hides the translations panel. + */ +add_task( + async function test_panel_closes_on_toggle_never_translate_language_with_translations_active() { + const { cleanup, runInPage, resolveDownloads } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is available" + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage, + "The page should be automatically translated." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( + "popuphidden", + async () => { + await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); + } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + await cleanup(); + } +); + +/** + * Tests the effect of checking the never-translate-language menuitem on + * a page where translations are active through always-translate-language + * and inactive on a site through never-translate-site. + * Checking the box on the page automatically closes/hides the translations panel. + */ +add_task( + async function test_panel_closes_on_toggle_never_translate_language_with_always_translate_language_and_never_translate_site_active() { + const { cleanup, runInPage, resolveDownloads } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is available" + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage, + "The page should be automatically translated." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( + "popuphidden", + async () => { + await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); + } + ); + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_inactive.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_inactive.js new file mode 100644 index 0000000000..95ff86ba7f --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_language_with_translations_inactive.js @@ -0,0 +1,93 @@ +"use strict"; + +/** + * Tests the effect of checking the never-translate-language menuitem on a page where + * translations and never translate site are inactive. + * Checking the box on the page automatically closes/hides the translations panel. + */ +add_task(async function test_panel_closes_on_toggle_never_translate_language() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is available" + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( + "popuphidden", + async () => { + await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); + } + ); + await cleanup(); +}); + +/** + * Tests the effect of checking the never-translate-language menuitem on a page where + * translations are inactive (never-translate-site is enabled). + * Checking the box on the page automatically closes/hides the translations panel. + */ +add_task( + async function test_panel_closes_on_toggle_never_translate_language_with_never_translate_site_enabled() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is available" + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( + "popuphidden", + async () => { + await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); + } + ); + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_site.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_site.js new file mode 100644 index 0000000000..c3d1458525 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_close_panel_never_translate_site.js @@ -0,0 +1,159 @@ +"use strict"; + +/** + * Tests the effect of checking the never-translate-site menuitem on a page where + * always-translate-language and never-translate-language are inactive. + * Checking the box on the page automatically closes/hides the translations panel. + */ +add_task(async function test_panel_closes_on_toggle_never_translate_site() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is available" + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( + "popuphidden", + async () => { + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + } + ); + + await cleanup(); +}); + +/** + * Tests the effect of checking the never-translate-site menuitem on a page where + * translations are active (always-translate-language is enabled). + * Checking the box on the page automatically restores the page and closes/hides the translations panel. + */ +add_task( + async function test_panel_closes_on_toggle_never_translate_site_with_translations_active() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is available" + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage, + "The page should be automatically translated." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( + "popuphidden", + async () => { + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + } + ); + + await cleanup(); + } +); + +/** + * Tests the effect of checking the never-translate-site menuitem on a page where + * translations are inactive (never-translate-language is active). + * Checking the box on the page automatically closes/hides the translations panel. + */ +add_task( + async function test_panel_closes_on_toggle_never_translate_site_with_translations_inactive() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is available" + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( + "popuphidden", + async () => { + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + } + ); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_destroy.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_destroy.js new file mode 100644 index 0000000000..1b498f9b07 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_destroy.js @@ -0,0 +1,55 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Manually destroy the engine, and test that the page is still translated afterwards. + */ +add_task(async function test_translations_engine_destroy() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + info("Destroy the engine process"); + await EngineProcess.destroyTranslationsEngine(); + + info("Mutate the page's content to re-trigger a translation."); + await runInPage(async TranslationsTest => { + const { getH1 } = TranslationsTest.getSelectors(); + getH1().innerText = "New text for the H1"; + }); + + info("The engine downloads should be requested again."); + resolveDownloads(1); + + await runInPage(async TranslationsTest => { + const { getH1 } = TranslationsTest.getSelectors(); + await TranslationsTest.assertTranslationResult( + "The mutated content should be translated.", + getH1, + "NEW TEXT FOR THE H1 [es to en]" + ); + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_destroy_pending.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_destroy_pending.js new file mode 100644 index 0000000000..cfe1997093 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_destroy_pending.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Manually destroy the engine while a page is in the background, and test that the page + * is still translated after switching back to it. + */ +add_task(async function test_translations_engine_destroy_pending() { + const { + cleanup, + resolveDownloads, + runInPage, + tab: spanishTab, + } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + const { removeTab: removeEnglishTab } = await addTab( + ENGLISH_PAGE_URL, + "Creating a new tab for a page in English." + ); + + info("Destroy the engine process"); + await EngineProcess.destroyTranslationsEngine(); + + info("Mutate the page's content to re-trigger a translation."); + await runInPage(async TranslationsTest => { + const { getH1 } = TranslationsTest.getSelectors(); + getH1().innerText = "New text for the H1"; + }); + + info("Wait for a second to ensure the mutation takes."); + await TestUtils.waitForTick(); + + await switchTab(spanishTab, "spanish tab"); + + info("The engine downloads should be requested again."); + resolveDownloads(1); + + await runInPage(async TranslationsTest => { + const { getH1 } = TranslationsTest.getSelectors(); + await TranslationsTest.assertTranslationResult( + "The mutated content should be translated.", + getH1, + "NEW TEXT FOR THE H1 [es to en]" + ); + }); + + await removeEnglishTab(); + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_unsupported.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_unsupported.js new file mode 100644 index 0000000000..f0804f35aa --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_unsupported.js @@ -0,0 +1,59 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that the translations button does not appear when the translations + * engine is not supported. + */ +add_task(async function test_translations_button_hidden_when_cpu_unsupported() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.simulateUnsupportedEngine", true]], + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: false }, + "The button is not available." + ); + + await cleanup(); +}); + +/** + * Tests that the translate-page menuitem is not available in the app menu + * when the translations engine is not supported. + */ +add_task( + async function test_translate_page_app_menu_item_hidden_when_cpu_unsupported() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.simulateUnsupportedEngine", true]], + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + const appMenuButton = getById("PanelUI-menu-button"); + + click(appMenuButton, "Opening the app menu"); + await BrowserTestUtils.waitForEvent(window.PanelUI.mainView, "ViewShown"); + + const translateSiteButton = document.getElementById( + "appMenu-translate-button" + ); + is( + translateSiteButton.hidden, + true, + "The app-menu translate button should be hidden because when the engine is not supported." + ); + + click(appMenuButton, "Closing the app menu"); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_unsupported_lang.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_unsupported_lang.js new file mode 100644 index 0000000000..21f7e8fdb7 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_engine_unsupported_lang.js @@ -0,0 +1,28 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests how the unsupported language flow works. + */ +add_task(async function test_unsupported_lang() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: [ + // Do not include Spanish. + { fromLang: "fr", toLang: "en" }, + { fromLang: "en", toLang: "fr" }, + ], + }); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: + FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, + }); + + await FullPageTranslationsTestUtils.clickChangeSourceLanguageButton(); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_firstrun.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_firstrun.js new file mode 100644 index 0000000000..ef807b9ac6 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_firstrun.js @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that the first run message is displayed. + */ +add_task(async function test_translations_panel_firstrun() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.panelShown", false]], + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await navigate("Load a different page on the same site", { + url: SPANISH_PAGE_URL_2, + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_firstrun_revisit.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_firstrun_revisit.js new file mode 100644 index 0000000000..998a7653c8 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_firstrun_revisit.js @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that the first-show intro message message is displayed + * when viewing the panel subsequent times on the same URL, + * but is no longer displayed after navigating to new URL, + * or when returning to the first URL after navigating away. + */ +add_task(async function test_translations_panel_firstrun() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.panelShown", false]], + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await navigate("Navigate to a different website", { + url: SPANISH_PAGE_URL_DOT_ORG, + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await navigate("Navigate back to the first website", { + url: SPANISH_PAGE_URL, + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_fuzzing.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_fuzzing.js new file mode 100644 index 0000000000..0accc3db60 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_fuzzing.js @@ -0,0 +1,240 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Manually destroy the engine while a page is in the background, and test that the page + * is still translated after switching back to it. + */ +add_task(async function test_translations_panel_fuzzing() { + const { + cleanup, + runInPage: runInSpanishPage, + tab: spanishTab, + } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + autoDownloadFromRemoteSettings: true, + }); + + /** + * @typedef {object} Tab + */ + + /** @type {Tab?} */ + let englishTab; + /** @type {Function?} */ + let removeEnglishTab; + /** @type {boolean} */ + let isSpanishPageTranslated = false; + /** @type {"spanish" | "english"} */ + let activeTab = "spanish"; + /** @type {boolean} */ + let isEngineMaybeDestroyed = true; + /** @type {boolean} */ + let isTitleMutated = false; + /** @type {boolean} */ + let hasVerifiedMutation = true; + + function reportOperation(name) { + info( + `\n\nOperation: ${name} ` + + JSON.stringify({ + activeTab, + englishTab: !!englishTab, + isSpanishPageTranslated, + isEngineMaybeDestroyed, + isTitleMutated, + }) + ); + } + + /** + * A list of fuzzing operations. They return false when they are a noop given the + * conditions. + * + * @type {object} - Record Promise> + */ + const operations = { + async addEnglishTab() { + if (!englishTab) { + reportOperation("addEnglishTab"); + const { removeTab, tab } = await addTab( + ENGLISH_PAGE_URL, + "Creating a new tab for a page in English." + ); + + englishTab = tab; + removeEnglishTab = removeTab; + activeTab = "english"; + return true; + } + return false; + }, + + async removeEnglishTab() { + if (removeEnglishTab) { + reportOperation("removeEnglishTab"); + await removeEnglishTab(); + + englishTab = null; + removeEnglishTab = null; + activeTab = "spanish"; + return true; + } + return false; + }, + + async translateSpanishPage() { + if (!isSpanishPageTranslated) { + reportOperation("translateSpanishPage"); + if (activeTab === "english") { + await switchTab(spanishTab, "spanish tab"); + } + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton(); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: true, icon: true }, + "Translations button is fully loaded." + ); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInSpanishPage + ); + + isSpanishPageTranslated = true; + isEngineMaybeDestroyed = false; + activeTab = "spanish"; + return true; + } + return false; + }, + + async destroyEngineProcess() { + if ( + !isEngineMaybeDestroyed && + // Don't destroy the engine process until the mutation has been verified. + // There is an artifical race (e.g. only in tests) that happens from a new + // engine being requested, and forcefully destroyed before the it can be + // initialized. + hasVerifiedMutation + ) { + reportOperation("destroyEngineProcess"); + await EngineProcess.destroyTranslationsEngine(); + isEngineMaybeDestroyed = true; + } + return true; + }, + + async mutateSpanishPage() { + if (isSpanishPageTranslated && !isTitleMutated) { + reportOperation("mutateSpanishPage"); + + info("Mutate the page's content to re-trigger a translation."); + await runInSpanishPage(async TranslationsTest => { + const { getH1 } = TranslationsTest.getSelectors(); + getH1().innerText = "New text for the H1"; + }); + + if (isEngineMaybeDestroyed) { + info("The engine may be recreated now."); + } + + isEngineMaybeDestroyed = false; + isTitleMutated = true; + hasVerifiedMutation = false; + return true; + } + return false; + }, + + async switchToSpanishTab() { + if (activeTab !== "spanish") { + reportOperation("switchToSpanishTab"); + await switchTab(spanishTab, "spanish tab"); + activeTab = "spanish"; + + if (isTitleMutated) { + await runInSpanishPage(async TranslationsTest => { + const { getH1 } = TranslationsTest.getSelectors(); + await TranslationsTest.assertTranslationResult( + "The mutated content should be translated.", + getH1, + "NEW TEXT FOR THE H1 [es to en]" + ); + }); + hasVerifiedMutation = true; + } + + return true; + } + return false; + }, + + async switchToEnglishTab() { + if (activeTab !== "english" && englishTab) { + reportOperation("switchToEnglishTab"); + await switchTab(englishTab, "english tab"); + activeTab = "english"; + return true; + } + return false; + }, + + async restoreSpanishPage() { + if (activeTab === "spanish" && isSpanishPageTranslated) { + reportOperation("restoreSpanishPage"); + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + + await FullPageTranslationsTestUtils.clickRestoreButton(); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated( + runInSpanishPage + ); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is reverted to have an icon." + ); + + isSpanishPageTranslated = false; + isTitleMutated = false; + return true; + } + return false; + }, + }; + + const fuzzSteps = 100; + info(`Starting the fuzzing with ${fuzzSteps} operations.`); + const opsArray = Object.values(operations); + + for (let i = 0; i < fuzzSteps; i++) { + // Pick a random operation and check if that it was not a noop, otherwise continue + // trying to find a valid operation. + while (true) { + const operation = opsArray[Math.floor(Math.random() * opsArray.length)]; + if (await operation()) { + break; + } + } + } + + if (removeEnglishTab) { + await removeEnglishTab(); + } + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_gear.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_gear.js new file mode 100644 index 0000000000..0b9ce3ad3b --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_gear.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Test managing the languages menu item. + */ +add_task(async function test_translations_panel_manage_languages() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.clickManageLanguages(); + + await waitForCondition( + () => gBrowser.currentURI.spec === "about:preferences#general", + "Waiting for about:preferences to be opened." + ); + + info("Remove the about:preferences tab"); + gBrowser.removeCurrentTab(); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_language.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_language.js new file mode 100644 index 0000000000..52cab172e7 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_language.js @@ -0,0 +1,186 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of toggling the never-translate-language menuitem. + * Checking the box on an untranslated page should immediately hide the button. + * The button should not appear again for sites in the disabled language. + */ +add_task(async function test_toggle_never_translate_language_menuitem() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Reload the page", { url: SPANISH_PAGE_URL }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Navigate to a different Spanish page", { + url: SPANISH_PAGE_URL_DOT_ORG, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); +}); + +/** + * Tests the effect of toggling the never-translate-language menuitem on a page where + * where translation is already active. + * Checking the box on a translated page should restore the page and hide the button. + * The button should not appear again for sites in the disabled language. + */ +add_task( + async function test_toggle_never_translate_language_menuitem_with_active_translations() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Reload the page", { url: SPANISH_PAGE_URL }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); + } +); + +/** + * Tests the effect of toggling the never-translate-language menuitem on a page where + * where translation is already active via always-translate. + * Checking the box on a translated page should restore the page and hide the button. + * The language should be moved from always-translate to never-translate. + * The button should not appear again for sites in the disabled language. + */ +add_task( + async function test_toggle_never_translate_language_menuitem_with_always_translate_active() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: false, + }); + + await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Reload the page", { url: SPANISH_PAGE_URL }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site.js new file mode 100644 index 0000000000..9d64da5b38 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site.js @@ -0,0 +1,247 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of toggling the never-translate-site menuitem. + * Checking the box on an untranslated page should immediately hide the button. + * The button should not appear again for sites that share the same content principal + * of the disabled site. + */ +add_task(async function test_toggle_never_translate_site_menuitem() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Navigate to a Spanish page with the same content principal", { + url: SPANISH_PAGE_URL_2, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with a different content principal", + { url: SPANISH_PAGE_URL_DOT_ORG } + ); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button should be visible, because this content principal " + + "has not been denied translations permissions" + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); +}); + +/** + * Tests the effect of toggling the never-translate-site menuitem on a page where + * where translation is already active. + * Checking the box on a translated page should restore the page and hide the button. + * The button should not appear again for sites that share the same content principal + * of the disabled site. + */ +add_task( + async function test_toggle_never_translate_site_menuitem_with_active_translations() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Reload the page", { url: SPANISH_PAGE_URL }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with the same content principal", + { url: SPANISH_PAGE_URL_2 } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with a different content principal", + { url: SPANISH_PAGE_URL_DOT_ORG } + ); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button should be visible, because this content principal " + + "has not been denied translations permissions" + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); + } +); + +/** + * Tests the effect of toggling the never-translate-site menuitem on a page where + * where translation is already active via always-translate. + * Checking the box on a translated page should restore the page and hide the button. + * The button should not appear again for sites that share the same content principal + * of the disabled site, and no auto-translation should occur. + * Other sites should still auto-translate for this language. + */ +add_task( + async function test_toggle_never_translate_site_menuitem_with_always_translate_active() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Reload the page", { url: SPANISH_PAGE_URL }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with the same content principal", + { url: SPANISH_PAGE_URL_2 } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with a different content principal", + { + url: SPANISH_PAGE_URL_DOT_ORG, + downloadHandler: resolveDownloads, + } + ); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_auto.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_auto.js new file mode 100644 index 0000000000..faa425c403 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_auto.js @@ -0,0 +1,109 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of toggling the never-translate-site menuitem on a page where + * where translation is already active via always-translate. + * Checking the box on a translated page should restore the page and hide the button. + * The button should not appear again for sites that share the same content principal + * of the disabled site, and no auto-translation should occur. + * Other sites should still auto-translate for this language. + */ +add_task( + async function test_toggle_never_translate_site_menuitem_with_always_translate_active() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Reload the page", { url: SPANISH_PAGE_URL }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with the same content principal", + { url: SPANISH_PAGE_URL_2 } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with a different content principal", + { + url: SPANISH_PAGE_URL_DOT_ORG, + downloadHandler: resolveDownloads, + } + ); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_basic.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_basic.js new file mode 100644 index 0000000000..048e002f45 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_basic.js @@ -0,0 +1,62 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of toggling the never-translate-site menuitem. + * Checking the box on an untranslated page should immediately hide the button. + * The button should not appear again for sites that share the same content principal + * of the disabled site. + */ +add_task(async function test_toggle_never_translate_site_menuitem() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Navigate to a Spanish page with the same content principal", { + url: SPANISH_PAGE_URL_2, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with a different content principal", + { url: SPANISH_PAGE_URL_DOT_ORG } + ); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button should be visible, because this content principal " + + "has not been denied translations permissions" + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_manual.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_manual.js new file mode 100644 index 0000000000..425e202546 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_never_translate_site_manual.js @@ -0,0 +1,84 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the effect of toggling the never-translate-site menuitem on a page where + * where translation is already active. + * Checking the box on a translated page should restore the page and hide the button. + * The button should not appear again for sites that share the same content principal + * of the disabled site. + */ +add_task( + async function test_toggle_never_translate_site_menuitem_with_active_translations() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: false } + ); + await FullPageTranslationsTestUtils.clickNeverTranslateSite(); + await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( + SPANISH_PAGE_URL, + { checked: true } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate("Reload the page", { url: SPANISH_PAGE_URL }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with the same content principal", + { url: SPANISH_PAGE_URL_2 } + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await navigate( + "Navigate to a Spanish page with a different content principal", + { url: SPANISH_PAGE_URL_DOT_ORG } + ); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button should be visible, because this content principal " + + "has not been denied translations permissions" + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_retry.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_retry.js new file mode 100644 index 0000000000..74d92381b9 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_retry.js @@ -0,0 +1,54 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests translating, and then immediately translating to a new language. + */ +add_task(async function test_translations_panel_retry() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + + FullPageTranslationsTestUtils.switchSelectedToLanguage("fr"); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + pivotTranslation: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "fr", + runInPage + ); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_settings_unsupported_lang.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_settings_unsupported_lang.js new file mode 100644 index 0000000000..d371e9ed22 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_settings_unsupported_lang.js @@ -0,0 +1,74 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * This tests a specific defect where the language checkbox states were not being + * updated correctly when visiting a web page in an unsupported language after + * previously enabling always-translate-language or never-translate-language + * on a site with a supported language. + * + * See https://bugzilla.mozilla.org/show_bug.cgi?id=1845611 for more information. + */ +add_task(async function test_unsupported_language_settings_menu_checkboxes() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: [ + // Do not include French. + { fromLang: "en", toLang: "es" }, + { fromLang: "es", toLang: "en" }, + ], + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: false, + }); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { + checked: true, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await navigate("Navigate to a page in an unsupported language.", { + url: FRENCH_PAGE_URL, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: false }, + "The translations button should be unavailable." + ); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: + FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("fr", { + checked: false, + disabled: true, + }); + await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("fr", { + checked: false, + disabled: true, + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_panel_switch_languages.js b/browser/components/translations/tests/browser/browser_translations_full_page_panel_switch_languages.js new file mode 100644 index 0000000000..0c5db67b20 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_panel_switch_languages.js @@ -0,0 +1,70 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests switching the language. + */ +add_task(async function test_translations_panel_switch_language() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + const { translateButton } = FullPageTranslationsPanel.elements; + + ok(!translateButton.disabled, "The translate button starts as enabled"); + + FullPageTranslationsTestUtils.assertSelectedFromLanguage({ langTag: "es" }); + FullPageTranslationsTestUtils.assertSelectedToLanguage({ langTag: "en" }); + + FullPageTranslationsTestUtils.switchSelectedFromLanguage("en"); + + ok( + translateButton.disabled, + "The translate button is disabled when the languages are the same" + ); + + FullPageTranslationsTestUtils.switchSelectedFromLanguage("es"); + + ok( + !translateButton.disabled, + "When the languages are different it can be translated" + ); + + FullPageTranslationsTestUtils.switchSelectedFromLanguage(""); + + ok( + translateButton.disabled, + "The translate button is disabled nothing is selected." + ); + + FullPageTranslationsTestUtils.switchSelectedFromLanguage("en"); + FullPageTranslationsTestUtils.switchSelectedToLanguage("fr"); + + ok(!translateButton.disabled, "The translate button can now be used"); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "en", + "fr", + runInPage + ); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_reader_mode.js b/browser/components/translations/tests/browser/browser_translations_full_page_reader_mode.js new file mode 100644 index 0000000000..1a6ea9d2ec --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_reader_mode.js @@ -0,0 +1,115 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that the translations button becomes hidden when entering reader mode. + */ +add_task(async function test_translations_button_hidden_in_reader_mode() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await toggleReaderMode(); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: false }, + "The translations button is now hidden in reader mode." + ); + + await runInPage(async TranslationsTest => { + const { getH1 } = TranslationsTest.getSelectors(); + await TranslationsTest.assertTranslationResult( + "The page's H1 is now the reader-mode header", + getH1, + "Translations Test" + ); + }); + + await runInPage(async TranslationsTest => { + const { getLastParagraph } = TranslationsTest.getSelectors(); + await TranslationsTest.assertTranslationResult( + "The page's last paragraph is in Spanish.", + getLastParagraph, + "— Pues, aunque mováis más brazos que los del gigante Briareo, me lo habéis de pagar." + ); + }); + + await toggleReaderMode(); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is visible again outside of reader mode." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); +}); + +/** + * Tests that translations persist when entering reader mode after translating. + */ +add_task(async function test_translations_persist_in_reader_mode() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is visible." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await toggleReaderMode(); + + await runInPage(async TranslationsTest => { + const { getH1 } = TranslationsTest.getSelectors(); + await TranslationsTest.assertTranslationResult( + "The page's H1 is now the translated reader-mode header", + getH1, + "TRANSLATIONS TEST [es to en, html]" + ); + }); + + await runInPage(async TranslationsTest => { + const { getLastParagraph } = TranslationsTest.getSelectors(); + await TranslationsTest.assertTranslationResult( + "The page's last paragraph is in Spanish.", + getLastParagraph, + "— PUES, AUNQUE MOVÁIS MÁS BRAZOS QUE LOS DEL GIGANTE BRIAREO, ME LO HABÉIS DE PAGAR. [es to en, html]" + ); + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: false }, + "The translations button is now hidden in reader mode." + ); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_auto_translate.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_auto_translate.js new file mode 100644 index 0000000000..d26bcad77b --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_auto_translate.js @@ -0,0 +1,117 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the entire flow of opening the translation settings menu and initiating + * an auto-translate request on the first panel interaction. + */ +add_task(async function test_translations_telemetry_firstrun_auto_translate() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.panelShown", false]], + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + expectFirstInteraction: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.alwaysTranslateLanguage, + { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + finalValuePredicates: [value => value.extra.language === "es"], + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + }); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translations.translationRequest, + { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + } + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, + }); + + await FullPageTranslationsTestUtils.clickRestoreButton(); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 2, + expectNewFlowId: true, + expectFirstInteraction: false, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "revisitView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.restorePageButton, + { + expectedEventCount: 1, + expectFirstInteraction: false, + expectNewFlowId: false, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 2, + expectFirstInteraction: false, + expectNewFlowId: false, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_basics.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_basics.js new file mode 100644 index 0000000000..db6d2e3b6c --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_basics.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that events in the first panel session are marked as first-interaction events + * and that events in the subsequent panel session are not marked as first-interaction events. + */ +add_task(async function test_translations_telemetry_firstrun_basics() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.panelShown", false]], + }); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 0, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + expectFirstInteraction: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 2, + expectNewFlowId: true, + expectFirstInteraction: false, + allValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 2, + expectNewFlowId: false, + expectFirstInteraction: false, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 2, + expectNewFlowId: false, + expectFirstInteraction: false, + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_translation_failure.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_translation_failure.js new file mode 100644 index 0000000000..75f58ab229 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_translation_failure.js @@ -0,0 +1,149 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { PromiseTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PromiseTestUtils.sys.mjs" +); + +/** + * Tests that the first-interaction event status is maintained across a subsequent panel + * open, if re-opening the panel is due to a translation failure. + */ +add_task(async function test_translations_telemetry_firstrun_failure() { + const { cleanup, rejectDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.panelShown", false]], + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, + }); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + expectFirstInteraction: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: rejectDownloads, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShowError, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 2, + expectNewFlowId: false, + expectFirstInteraction: true, + finalValuePredicates: [ + value => value.extra.auto_show === "true", + value => value.extra.view_name === "errorView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.translateButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + }); + await TestTranslationsTelemetry.assertEvent(Glean.translations.error, { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + finalValuePredicates: [ + value => + value.extra.reason === "Error: Intentionally rejecting downloads.", + ], + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translations.translationRequest, + { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + finalValuePredicates: [ + value => value.extra.from_language === "es", + value => value.extra.to_language === "en", + value => value.extra.auto_translate === "false", + value => value.extra.document_language === "es", + value => value.extra.top_preferred_language === "en", + ], + } + ); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 2, + expectNewFlowId: false, + expectFirstInteraction: true, + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, + }); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 3, + expectNewFlowId: true, + expectFirstInteraction: false, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 2, + expectNewFlowId: false, + expectFirstInteraction: false, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 3, + expectNewFlowId: false, + expectFirstInteraction: false, + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_unsupported_lang.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_unsupported_lang.js new file mode 100644 index 0000000000..86ae21e9ed --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_firstrun_unsupported_lang.js @@ -0,0 +1,122 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that the first-interaction event status is maintained across a subsequent panel + * open, if re-opening the panel is due to requesting to change the source language. + */ +add_task( + async function test_translations_telemetry_firstrun_unsupported_lang() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: [ + // Do not include Spanish. + { fromLang: "fr", toLang: "en" }, + { fromLang: "en", toLang: "fr" }, + ], + prefs: [["browser.translations.panelShown", false]], + }); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: + FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, + }); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + expectFirstInteraction: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "appMenu", + value => value.extra.document_language === "es", + ], + }); + + await FullPageTranslationsTestUtils.clickChangeSourceLanguageButton({ + firstShow: true, + }); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.changeSourceLanguageButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + }); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 2, + expectNewFlowId: false, + expectFirstInteraction: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "appMenu", + value => value.extra.document_language === "es", + ], + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: true, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 2, + expectNewFlowId: false, + expectFirstInteraction: true, + }); + + await FullPageTranslationsTestUtils.openPanel({ + openFromAppMenu: true, + onOpenPanel: + FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, + }); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 3, + expectNewFlowId: true, + expectFirstInteraction: false, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "appMenu", + value => value.extra.document_language === "es", + ], + }); + + await FullPageTranslationsTestUtils.clickDismissErrorButton(); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.dismissErrorButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + expectFirstInteraction: false, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 3, + expectNewFlowId: false, + expectFirstInteraction: false, + }); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_open_panel.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_open_panel.js new file mode 100644 index 0000000000..a49059f78f --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_open_panel.js @@ -0,0 +1,85 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the telemetry event for opening the translations panel. + */ +add_task(async function test_translations_telemetry_open_panel() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 0, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 2, + expectNewFlowId: true, + allValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 2, + expectNewFlowId: false, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 2, + expectNewFlowId: false, + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_panel_auto_offer.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_panel_auto_offer.js new file mode 100644 index 0000000000..93ff473851 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_panel_auto_offer.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that the popup is automatically offered. + */ +add_task(async function test_translations_panel_auto_offer() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + autoOffer: true, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + allValuePredicates: [ + value => value.extra.auto_show === "true", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + }); + + await navigate("Navigate to another page on the same domain.", { + url: SPANISH_PAGE_URL_2, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is still shown." + ); + + await navigate("Navigate to a page on a different domain.", { + url: SPANISH_PAGE_URL_DOT_ORG, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 2, + expectNewFlowId: true, + allValuePredicates: [ + value => value.extra.auto_show === "true", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 2, + expectNewFlowId: false, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 2, + expectNewFlowId: false, + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_panel_auto_offer_settings.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_panel_auto_offer_settings.js new file mode 100644 index 0000000000..4a2959f58e --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_panel_auto_offer_settings.js @@ -0,0 +1,110 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests that the automatic offering of the popup can be disabled. + */ +add_task(async function test_translations_panel_auto_offer_settings() { + const { cleanup } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + // Use the auto offer mechanics, but default the pref to the off position. + autoOffer: true, + prefs: [["browser.translations.automaticallyPopup", false]], + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The translations button is shown." + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 0, + }); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); + await FullPageTranslationsTestUtils.assertIsAlwaysOfferTranslationsEnabled( + false + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + allValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await FullPageTranslationsTestUtils.clickAlwaysOfferTranslations(); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.alwaysOfferTranslations, + { + expectedEventCount: 1, + expectNewFlowId: false, + allValuePredicates: [value => value.extra.toggled_on === "true"], + } + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + await FullPageTranslationsTestUtils.assertIsAlwaysOfferTranslationsEnabled( + true + ); + + await FullPageTranslationsTestUtils.clickCancelButton(); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 2, + expectNewFlowId: true, + allValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 2, + expectNewFlowId: false, + }); + + await navigate( + "Wait for the popup to be shown when navigating to a different host.", + { + url: SPANISH_PAGE_URL_DOT_ORG, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + } + ); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 3, + expectNewFlowId: true, + finalValuePredicates: [ + value => value.extra.auto_show === "true", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_switch_languages.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_switch_languages.js new file mode 100644 index 0000000000..ef13940b3f --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_switch_languages.js @@ -0,0 +1,156 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the telemetry events for switching the from-language. + */ +add_task(async function test_translations_telemetry_switch_from_language() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + FullPageTranslationsTestUtils.assertSelectedFromLanguage({ langTag: "es" }); + FullPageTranslationsTestUtils.switchSelectedFromLanguage("en"); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.changeFromLanguage, + { + expectedEventCount: 1, + expectNewFlowId: false, + finalValuePredicates: [value => value.extra.language === "en"], + } + ); + + FullPageTranslationsTestUtils.switchSelectedFromLanguage("es"); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.changeFromLanguage, + { + expectedEventCount: 2, + expectNewFlowId: false, + finalValuePredicates: [value => value.extra.language === "es"], + } + ); + + FullPageTranslationsTestUtils.switchSelectedFromLanguage(""); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.changeFromLanguage, + { + expectedEventCount: 2, + } + ); + + FullPageTranslationsTestUtils.switchSelectedFromLanguage("en"); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.changeFromLanguage, + { + expectedEventCount: 3, + expectNewFlowId: false, + finalValuePredicates: [value => value.extra.language === "en"], + } + ); + + await cleanup(); +}); + +/** + * Tests the telemetry events for switching the to-language. + */ +add_task(async function test_translations_telemetry_switch_to_language() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + FullPageTranslationsTestUtils.assertSelectedToLanguage({ langTag: "en" }); + FullPageTranslationsTestUtils.switchSelectedToLanguage("fr"); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.changeToLanguage, + { + expectedEventCount: 1, + expectNewFlowId: false, + finalValuePredicates: [value => value.extra.language === "fr"], + } + ); + + FullPageTranslationsTestUtils.switchSelectedToLanguage("en"); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.changeToLanguage, + { + expectedEventCount: 2, + expectNewFlowId: false, + finalValuePredicates: [value => value.extra.language === "en"], + } + ); + + FullPageTranslationsTestUtils.switchSelectedToLanguage(""); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.changeToLanguage, + { + expectedEventCount: 2, + } + ); + + FullPageTranslationsTestUtils.switchSelectedToLanguage("en"); + + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.changeToLanguage, + { + expectedEventCount: 3, + expectNewFlowId: false, + finalValuePredicates: [value => value.extra.language === "en"], + } + ); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_translation_failure.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_translation_failure.js new file mode 100644 index 0000000000..7a9f58970a --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_translation_failure.js @@ -0,0 +1,212 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { PromiseTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PromiseTestUtils.sys.mjs" +); + +/** + * Tests the telemetry event for a manual translation request failure. + */ +add_task( + async function test_translations_telemetry_manual_translation_failure() { + const { cleanup, rejectDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await TestTranslationsTelemetry.assertCounter( + "RequestCount", + Glean.translations.requestsCount, + 0 + ); + await TestTranslationsTelemetry.assertRate( + "ErrorRate", + Glean.translations.errorRate, + { + expectedNumerator: 0, + expectedDenominator: 0, + } + ); + await TestTranslationsTelemetry.assertEvent( + Glean.translations.translationRequest, + { + expectedEventCount: 0, + } + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: rejectDownloads, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewError, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 2, + expectNewFlowId: false, + finalValuePredicates: [ + value => value.extra.auto_show === "true", + value => value.extra.view_name === "errorView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.translateButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + }); + await TestTranslationsTelemetry.assertCounter( + "RequestCount", + Glean.translations.requestsCount, + 1 + ); + await TestTranslationsTelemetry.assertRate( + "ErrorRate", + Glean.translations.errorRate, + { + expectedNumerator: 1, + expectedDenominator: 1, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translations.error, { + expectedEventCount: 1, + expectNewFlowId: false, + finalValuePredicates: [ + value => + value.extra.reason === "Error: Intentionally rejecting downloads.", + ], + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translations.translationRequest, + { + expectedEventCount: 1, + expectNewFlowId: false, + finalValuePredicates: [ + value => value.extra.from_language === "es", + value => value.extra.to_language === "en", + value => value.extra.auto_translate === "false", + value => value.extra.document_language === "es", + value => value.extra.top_preferred_language === "en", + ], + } + ); + + await cleanup(); + } +); + +/** + * Tests the telemetry event for an automatic translation request failure. + */ +add_task(async function test_translations_telemetry_auto_translation_failure() { + const { cleanup, rejectDownloads, runInPage } = await loadTestPage({ + page: BLANK_PAGE, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.alwaysTranslateLanguages", "es"]], + }); + + await navigate("Navigate to a Spanish page", { + url: SPANISH_PAGE_URL, + downloadHandler: rejectDownloads, + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewError, + }); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await TestTranslationsTelemetry.assertCounter( + "RequestCount", + Glean.translations.requestsCount, + 1 + ); + await TestTranslationsTelemetry.assertRate( + "ErrorRate", + Glean.translations.errorRate, + { + expectedNumerator: 1, + expectedDenominator: 1, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + finalValuePredicates: [ + value => value.extra.auto_show === "true", + value => value.extra.view_name === "errorView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 0, + expectNewFlowId: false, + }); + await TestTranslationsTelemetry.assertEvent(Glean.translations.error, { + expectedEventCount: 1, + expectNewFlowId: false, + finalValuePredicates: [ + value => + value.extra.reason === "Error: Intentionally rejecting downloads.", + ], + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translations.translationRequest, + { + expectedEventCount: 1, + expectNewFlowId: false, + finalValuePredicates: [ + value => value.extra.from_language === "es", + value => value.extra.to_language === "en", + value => value.extra.auto_translate === "true", + value => value.extra.document_language === "es", + value => value.extra.top_preferred_language === "en", + ], + } + ); + + await FullPageTranslationsTestUtils.clickCancelButton(); + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.cancelButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + }); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_translation_request.js b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_translation_request.js new file mode 100644 index 0000000000..e671f5e0da --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_full_page_telemetry_translation_request.js @@ -0,0 +1,170 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests the telemetry event for a manual translation request. + */ +add_task(async function test_translations_telemetry_manual_translation() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await TestTranslationsTelemetry.assertCounter( + "RequestCount", + Glean.translations.requestsCount, + 0 + ); + await TestTranslationsTelemetry.assertRate( + "ErrorRate", + Glean.translations.errorRate, + { + expectedNumerator: 0, + expectedDenominator: 0, + } + ); + await TestTranslationsTelemetry.assertEvent( + Glean.translations.translationRequest, + { + expectedEventCount: 0, + } + ); + + await FullPageTranslationsTestUtils.openPanel({ + onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, + }); + + await FullPageTranslationsTestUtils.clickTranslateButton({ + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await TestTranslationsTelemetry.assertCounter( + "RequestCount", + Glean.translations.requestsCount, + 1 + ); + await TestTranslationsTelemetry.assertRate( + "ErrorRate", + Glean.translations.errorRate, + { + expectedNumerator: 0, + expectedDenominator: 1, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 1, + expectNewFlowId: true, + finalValuePredicates: [ + value => value.extra.auto_show === "false", + value => value.extra.view_name === "defaultView", + value => value.extra.opened_from === "translationsButton", + value => value.extra.document_language === "es", + ], + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.translateButton, + { + expectedEventCount: 1, + expectNewFlowId: false, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 1, + expectNewFlowId: false, + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translations.translationRequest, + { + expectedEventCount: 1, + expectNewFlowId: false, + finalValuePredicates: [ + value => value.extra.from_language === "es", + value => value.extra.to_language === "en", + value => value.extra.auto_translate === "false", + value => value.extra.document_language === "es", + value => value.extra.top_preferred_language === "en", + ], + } + ); + + await cleanup(); +}); + +/** + * Tests the telemetry event for an automatic translation request. + */ +add_task(async function test_translations_telemetry_auto_translation() { + const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ + page: BLANK_PAGE, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.alwaysTranslateLanguages", "es"]], + }); + + await navigate("Navigate to a Spanish page", { + url: SPANISH_PAGE_URL, + downloadHandler: resolveDownloads, + }); + + await FullPageTranslationsTestUtils.assertPageIsTranslated( + "es", + "en", + runInPage + ); + + await TestTranslationsTelemetry.assertCounter( + "RequestCount", + Glean.translations.requestsCount, + 1 + ); + await TestTranslationsTelemetry.assertRate( + "ErrorRate", + Glean.translations.errorRate, + { + expectedNumerator: 0, + expectedDenominator: 1, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { + expectedEventCount: 0, + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translationsPanel.translateButton, + { + expectedEventCount: 0, + } + ); + await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { + expectedEventCount: 0, + }); + await TestTranslationsTelemetry.assertEvent( + Glean.translations.translationRequest, + { + expectedEventCount: 1, + expectNewFlowId: true, + finalValuePredicates: [ + value => value.extra.from_language === "es", + value => value.extra.to_language === "en", + value => value.extra.auto_translate === "true", + value => value.extra.document_language === "es", + value => value.extra.top_preferred_language === "en", + ], + } + ); + + await cleanup(); +}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_a11y_focus.js b/browser/components/translations/tests/browser/browser_translations_panel_a11y_focus.js deleted file mode 100644 index e2e8663f6d..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_a11y_focus.js +++ /dev/null @@ -1,32 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the a11y focus behavior. - */ -add_task(async function test_translations_panel_a11y_focus() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openWithKeyboard: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - is( - document.activeElement.getAttribute("data-l10n-id"), - "translations-panel-settings-button", - "The settings button is focused." - ); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_bad_data.js b/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_bad_data.js deleted file mode 100644 index ac026fb78f..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_bad_data.js +++ /dev/null @@ -1,40 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests that having an "always translate" set to your app locale doesn't break things. - */ -add_task(async function test_always_translate_with_bad_data() { - const { cleanup, runInPage } = await loadTestPage({ - page: ENGLISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.alwaysTranslateLanguages", "en,fr"]], - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - openFromAppMenu: true, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("en", { - checked: false, - disabled: true, - }); - await closeSettingsMenuIfOpen(); - await closeTranslationsPanelIfOpen(); - - info("Checking that the page is untranslated"); - await runInPage(async TranslationsTest => { - const { getH1 } = TranslationsTest.getSelectors(); - await TranslationsTest.assertTranslationResult( - "The page's H1 is untranslated and in the original English.", - getH1, - '"The Wonderful Wizard of Oz" by L. Frank Baum' - ); - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_basic.js b/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_basic.js deleted file mode 100644 index 2644d78f33..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_basic.js +++ /dev/null @@ -1,79 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of toggling the always-translate-language menuitem. - * Checking the box on an untranslated page should immediately translate the page. - * Unchecking the box on a translated page should immediately restore the page. - */ -add_task(async function test_toggle_always_translate_language_menuitem() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage, - "The page should be automatically translated." - ); - - await navigate("Navigate to a different Spanish page", { - url: SPANISH_PAGE_URL_DOT_ORG, - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage, - "The page should be automatically translated." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage(); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "Only the button appears" - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_manual.js b/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_manual.js deleted file mode 100644 index 8456b4cc08..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_manual.js +++ /dev/null @@ -1,80 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of toggling the always-translate-language menuitem after the page has - * been manually translated. This should not reload or retranslate the page, but just check - * the box. - */ -add_task( - async function test_activate_always_translate_language_after_manual_translation() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage(); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage(); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "Only the button appears" - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_restore.js b/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_restore.js deleted file mode 100644 index 6cf89d2a03..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language_restore.js +++ /dev/null @@ -1,101 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of unchecking the always-translate language menuitem after the page has - * been manually restored to its original form. - * This should have no effect on the page, and further page loads should no longer auto-translate. - */ -add_task( - async function test_deactivate_always_translate_language_after_restore() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage, - "The page should be automatically translated." - ); - - await navigate("Navigate to a different Spanish page", { - url: SPANISH_PAGE_URL_DOT_ORG, - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage, - "The page should be automatically translated." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - - await FullPageTranslationsTestUtils.clickRestoreButton(); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is reverted to have an icon." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage(); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button shows only the icon." - ); - - await navigate("Reload the page", { url: SPANISH_PAGE_URL_DOT_ORG }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button shows only the icon." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_app_menu_never_translate_language.js b/browser/components/translations/tests/browser/browser_translations_panel_app_menu_never_translate_language.js deleted file mode 100644 index ee2905ab99..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_app_menu_never_translate_language.js +++ /dev/null @@ -1,40 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of unchecking the never-translate-language menuitem, removing - * the language from the never-translate languages list. - * The translations button should reappear. - */ -add_task(async function test_uncheck_never_translate_language_shows_button() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.neverTranslateLanguages", "es"]], - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is available" - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_app_menu_never_translate_site.js b/browser/components/translations/tests/browser/browser_translations_panel_app_menu_never_translate_site.js deleted file mode 100644 index 50fff4dff8..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_app_menu_never_translate_site.js +++ /dev/null @@ -1,140 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of unchecking the never-translate-site menuitem, - * regranting translations permissions to this page. - * The translations button should reappear. - */ -add_task(async function test_uncheck_never_translate_site_shows_button() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await cleanup(); -}); - -/** - * Tests the effect of unchecking the never-translate-site menuitem while - * the current language is in the always-translate languages list, regranting - * translations permissions to this page. - * The page should automatically translate. - */ -add_task( - async function test_uncheck_never_translate_site_with_always_translate_language() { - const { cleanup, runInPage, resolveDownloads } = await loadTestPage({ - page: BLANK_PAGE, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.alwaysTranslateLanguages", "es"]], - }); - - await navigate("Navigate to a Spanish page", { - url: SPANISH_PAGE_URL, - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_auto_translate_error_view.js b/browser/components/translations/tests/browser/browser_translations_panel_auto_translate_error_view.js deleted file mode 100644 index e71ee1392b..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_auto_translate_error_view.js +++ /dev/null @@ -1,86 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -const { PromiseTestUtils } = ChromeUtils.importESModule( - "resource://testing-common/PromiseTestUtils.sys.mjs" -); - -/** - * This tests a specific defect where the error view was not showing properly - * when navigating to an auto-translated page after visiting a page in an unsupported - * language and viewing the panel. - * - * This test case tests the case where the auto translate fails and the panel - * automatically opens the panel to show the error view. - * - * See https://bugzilla.mozilla.org/show_bug.cgi?id=1845611 for more information. - */ -add_task( - async function test_revisit_view_updates_with_auto_translate_failure() { - const { cleanup, resolveDownloads, rejectDownloads, runInPage } = - await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: [ - // Do not include French. - { fromLang: "en", toLang: "es" }, - { fromLang: "es", toLang: "en" }, - ], - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await navigate("Navigate to a page in an unsupported language", { - url: FRENCH_PAGE_URL, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: false }, - "The translations button should be unavailable." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: - FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, - }); - - info("Destroy the engine process so that an error will happen."); - await TranslationsParent.destroyEngineProcess(); - - await navigate("Navigate back to a Spanish page.", { - url: SPANISH_PAGE_URL_DOT_ORG, - downloadHandler: rejectDownloads, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewError, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_auto_translate_revisit_view.js b/browser/components/translations/tests/browser/browser_translations_panel_auto_translate_revisit_view.js deleted file mode 100644 index dd4ffcecfd..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_auto_translate_revisit_view.js +++ /dev/null @@ -1,86 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * This tests a specific defect where the revisit view was not showing properly - * when navigating to an auto-translated page after visiting a page in an unsupported - * language and viewing the panel. - * - * This test case tests the case where the auto translate succeeds and the user - * manually opens the panel to show the revisit view. - * - * See https://bugzilla.mozilla.org/show_bug.cgi?id=1845611 for more information. - */ -add_task( - async function test_revisit_view_updates_with_auto_translate_success() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: [ - // Do not include French. - { fromLang: "en", toLang: "es" }, - { fromLang: "es", toLang: "en" }, - ], - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await navigate("Navigate to a page in an unsupported language", { - url: FRENCH_PAGE_URL, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: false }, - "The translations button should be unavailable." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: - FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, - }); - - await navigate("Navigate back to the Spanish page.", { - url: SPANISH_PAGE_URL_DOT_ORG, - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_basics.js b/browser/components/translations/tests/browser/browser_translations_panel_basics.js deleted file mode 100644 index ef2e2c4708..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_basics.js +++ /dev/null @@ -1,69 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests a basic panel open, translation, and restoration to the original language. - */ -add_task(async function test_translations_panel_basics() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - const { button } = - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - is(button.getAttribute("data-l10n-id"), "urlbar-translations-button2"); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - const panel = document.getElementById("translations-panel"); - const label = document.getElementById(panel.getAttribute("aria-labelledby")); - ok(label, "The a11y label for the panel can be found."); - assertVisibility({ visible: { label } }); - - await FullPageTranslationsTestUtils.clickTranslateButton(); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: true, locale: false, icon: true }, - "The icon presents the loading indicator." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewLoading, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await resolveDownloads(1); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - - await FullPageTranslationsTestUtils.clickRestoreButton(); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is reverted to have an icon." - ); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_button.js b/browser/components/translations/tests/browser/browser_translations_panel_button.js deleted file mode 100644 index 209cfc18a6..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_button.js +++ /dev/null @@ -1,77 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Test that the translations button is correctly visible when navigating between pages. - */ -add_task(async function test_button_visible_navigation() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button should be visible since the page can be translated from Spanish." - ); - - await navigate("Navigate to an English page.", { url: ENGLISH_PAGE_URL }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: false }, - "The button should be invisible since the page is in English." - ); - - await navigate("Navigate back to a Spanish page.", { url: SPANISH_PAGE_URL }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button should be visible again since the page is in Spanish." - ); - - await cleanup(); -}); - -/** - * Test that the translations button is correctly visible when opening and switch tabs. - */ -add_task(async function test_button_visible() { - const { cleanup, tab: spanishTab } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button should be visible since the page can be translated from Spanish." - ); - - const { removeTab, tab: englishTab } = await addTab( - ENGLISH_PAGE_URL, - "Creating a new tab for a page in English." - ); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: false }, - "The button should be invisible since the tab is in English." - ); - - await switchTab(spanishTab, "spanish tab"); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button should be visible again since the page is in Spanish." - ); - - await switchTab(englishTab, "english tab"); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: false }, - "Don't show for english pages" - ); - - await removeTab(); - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_cancel.js b/browser/components/translations/tests/browser/browser_translations_panel_cancel.js deleted file mode 100644 index 17e680dd87..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_cancel.js +++ /dev/null @@ -1,27 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests a panel open, and hitting the cancel button. - */ -add_task(async function test_translations_panel_cancel() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_language_with_translations_active.js b/browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_language_with_translations_active.js deleted file mode 100644 index 0fbffd891a..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_language_with_translations_active.js +++ /dev/null @@ -1,147 +0,0 @@ -"use strict"; - -/** - * Tests the effect of checking the never-translate-language menuitem on a page where - * translations are active (always-translate-language is enabled). - * Checking the box on the page automatically closes/hides the translations panel. - */ -add_task( - async function test_panel_closes_on_toggle_never_translate_language_with_translations_active() { - const { cleanup, runInPage, resolveDownloads } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is available" - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage, - "The page should be automatically translated." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( - "popuphidden", - async () => { - await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); - } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - await cleanup(); - } -); - -/** - * Tests the effect of checking the never-translate-language menuitem on - * a page where translations are active through always-translate-language - * and inactive on a site through never-translate-site. - * Checking the box on the page automatically closes/hides the translations panel. - */ -add_task( - async function test_panel_closes_on_toggle_never_translate_language_with_always_translate_language_and_never_translate_site_active() { - const { cleanup, runInPage, resolveDownloads } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is available" - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage, - "The page should be automatically translated." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( - "popuphidden", - async () => { - await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); - } - ); - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_language_with_translations_inactive.js b/browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_language_with_translations_inactive.js deleted file mode 100644 index 5df2468646..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_language_with_translations_inactive.js +++ /dev/null @@ -1,93 +0,0 @@ -"use strict"; - -/** - * Tests the effect of checking the never-translate-language menuitem on a page where - * translations and never translate site are inactive. - * Checking the box on the page automatically closes/hides the translations panel. - */ -add_task(async function test_panel_closes_on_toggle_never_translate_language() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is available" - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( - "popuphidden", - async () => { - await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); - } - ); - await cleanup(); -}); - -/** - * Tests the effect of checking the never-translate-language menuitem on a page where - * translations are inactive (never-translate-site is enabled). - * Checking the box on the page automatically closes/hides the translations panel. - */ -add_task( - async function test_panel_closes_on_toggle_never_translate_language_with_never_translate_site_enabled() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is available" - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( - "popuphidden", - async () => { - await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); - } - ); - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_site.js b/browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_site.js deleted file mode 100644 index 78679a046a..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_close_panel_never_translate_site.js +++ /dev/null @@ -1,159 +0,0 @@ -"use strict"; - -/** - * Tests the effect of checking the never-translate-site menuitem on a page where - * always-translate-language and never-translate-language are inactive. - * Checking the box on the page automatically closes/hides the translations panel. - */ -add_task(async function test_panel_closes_on_toggle_never_translate_site() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is available" - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( - "popuphidden", - async () => { - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - } - ); - - await cleanup(); -}); - -/** - * Tests the effect of checking the never-translate-site menuitem on a page where - * translations are active (always-translate-language is enabled). - * Checking the box on the page automatically restores the page and closes/hides the translations panel. - */ -add_task( - async function test_panel_closes_on_toggle_never_translate_site_with_translations_active() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is available" - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage, - "The page should be automatically translated." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( - "popuphidden", - async () => { - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - } - ); - - await cleanup(); - } -); - -/** - * Tests the effect of checking the never-translate-site menuitem on a page where - * translations are inactive (never-translate-language is active). - * Checking the box on the page automatically closes/hides the translations panel. - */ -add_task( - async function test_panel_closes_on_toggle_never_translate_site_with_translations_inactive() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is available" - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( - "popuphidden", - async () => { - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - } - ); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_engine_destroy.js b/browser/components/translations/tests/browser/browser_translations_panel_engine_destroy.js deleted file mode 100644 index 0a58dd7fa6..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_engine_destroy.js +++ /dev/null @@ -1,55 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Manually destroy the engine, and test that the page is still translated afterwards. - */ -add_task(async function test_translations_engine_destroy() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - info("Destroy the engine process"); - await TranslationsParent.destroyEngineProcess(); - - info("Mutate the page's content to re-trigger a translation."); - await runInPage(async TranslationsTest => { - const { getH1 } = TranslationsTest.getSelectors(); - getH1().innerText = "New text for the H1"; - }); - - info("The engine downloads should be requested again."); - resolveDownloads(1); - - await runInPage(async TranslationsTest => { - const { getH1 } = TranslationsTest.getSelectors(); - await TranslationsTest.assertTranslationResult( - "The mutated content should be translated.", - getH1, - "NEW TEXT FOR THE H1 [es to en]" - ); - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_engine_destroy_pending.js b/browser/components/translations/tests/browser/browser_translations_panel_engine_destroy_pending.js deleted file mode 100644 index ace1a845df..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_engine_destroy_pending.js +++ /dev/null @@ -1,72 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Manually destroy the engine while a page is in the background, and test that the page - * is still translated after switching back to it. - */ -add_task(async function test_translations_engine_destroy_pending() { - const { - cleanup, - resolveDownloads, - runInPage, - tab: spanishTab, - } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - const { removeTab: removeEnglishTab } = await addTab( - ENGLISH_PAGE_URL, - "Creating a new tab for a page in English." - ); - - info("Destroy the engine process"); - await TranslationsParent.destroyEngineProcess(); - - info("Mutate the page's content to re-trigger a translation."); - await runInPage(async TranslationsTest => { - const { getH1 } = TranslationsTest.getSelectors(); - getH1().innerText = "New text for the H1"; - }); - - info("Wait for a second to ensure the mutation takes."); - await TestUtils.waitForTick(); - - await switchTab(spanishTab, "spanish tab"); - - info("The engine downloads should be requested again."); - resolveDownloads(1); - - await runInPage(async TranslationsTest => { - const { getH1 } = TranslationsTest.getSelectors(); - await TranslationsTest.assertTranslationResult( - "The mutated content should be translated.", - getH1, - "NEW TEXT FOR THE H1 [es to en]" - ); - }); - - await removeEnglishTab(); - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_engine_unsupported.js b/browser/components/translations/tests/browser/browser_translations_panel_engine_unsupported.js deleted file mode 100644 index f0804f35aa..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_engine_unsupported.js +++ /dev/null @@ -1,59 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests that the translations button does not appear when the translations - * engine is not supported. - */ -add_task(async function test_translations_button_hidden_when_cpu_unsupported() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.simulateUnsupportedEngine", true]], - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: false }, - "The button is not available." - ); - - await cleanup(); -}); - -/** - * Tests that the translate-page menuitem is not available in the app menu - * when the translations engine is not supported. - */ -add_task( - async function test_translate_page_app_menu_item_hidden_when_cpu_unsupported() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.simulateUnsupportedEngine", true]], - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - const appMenuButton = getById("PanelUI-menu-button"); - - click(appMenuButton, "Opening the app menu"); - await BrowserTestUtils.waitForEvent(window.PanelUI.mainView, "ViewShown"); - - const translateSiteButton = document.getElementById( - "appMenu-translate-button" - ); - is( - translateSiteButton.hidden, - true, - "The app-menu translate button should be hidden because when the engine is not supported." - ); - - click(appMenuButton, "Closing the app menu"); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_engine_unsupported_lang.js b/browser/components/translations/tests/browser/browser_translations_panel_engine_unsupported_lang.js deleted file mode 100644 index 79e5c6b119..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_engine_unsupported_lang.js +++ /dev/null @@ -1,28 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests how the unsupported language flow works. - */ -add_task(async function test_unsupported_lang() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: [ - // Do not include Spanish. - { fromLang: "fr", toLang: "en" }, - { fromLang: "en", toLang: "fr" }, - ], - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: - FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, - }); - - await FullPageTranslationsTestUtils.clickChangeSourceLanguageButton(); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_firstrun.js b/browser/components/translations/tests/browser/browser_translations_panel_firstrun.js deleted file mode 100644 index 0c248a7837..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_firstrun.js +++ /dev/null @@ -1,33 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests that the first run message is displayed. - */ -add_task(async function test_translations_panel_firstrun() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.panelShown", false]], - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await navigate("Load a different page on the same site", { - url: SPANISH_PAGE_URL_2, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_firstrun_revisit.js b/browser/components/translations/tests/browser/browser_translations_panel_firstrun_revisit.js deleted file mode 100644 index 02c2d94db9..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_firstrun_revisit.js +++ /dev/null @@ -1,57 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests that the first-show intro message message is displayed - * when viewing the panel subsequent times on the same URL, - * but is no longer displayed after navigating to new URL, - * or when returning to the first URL after navigating away. - */ -add_task(async function test_translations_panel_firstrun() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.panelShown", false]], - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await navigate("Navigate to a different website", { - url: SPANISH_PAGE_URL_DOT_ORG, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await navigate("Navigate back to the first website", { - url: SPANISH_PAGE_URL, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_fuzzing.js b/browser/components/translations/tests/browser/browser_translations_panel_fuzzing.js deleted file mode 100644 index 2f5285ac46..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_fuzzing.js +++ /dev/null @@ -1,240 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Manually destroy the engine while a page is in the background, and test that the page - * is still translated after switching back to it. - */ -add_task(async function test_translations_panel_fuzzing() { - const { - cleanup, - runInPage: runInSpanishPage, - tab: spanishTab, - } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - autoDownloadFromRemoteSettings: true, - }); - - /** - * @typedef {object} Tab - */ - - /** @type {Tab?} */ - let englishTab; - /** @type {Function?} */ - let removeEnglishTab; - /** @type {boolean} */ - let isSpanishPageTranslated = false; - /** @type {"spanish" | "english"} */ - let activeTab = "spanish"; - /** @type {boolean} */ - let isEngineMaybeDestroyed = true; - /** @type {boolean} */ - let isTitleMutated = false; - /** @type {boolean} */ - let hasVerifiedMutation = true; - - function reportOperation(name) { - info( - `\n\nOperation: ${name} ` + - JSON.stringify({ - activeTab, - englishTab: !!englishTab, - isSpanishPageTranslated, - isEngineMaybeDestroyed, - isTitleMutated, - }) - ); - } - - /** - * A list of fuzzing operations. They return false when they are a noop given the - * conditions. - * - * @type {object} - Record Promise> - */ - const operations = { - async addEnglishTab() { - if (!englishTab) { - reportOperation("addEnglishTab"); - const { removeTab, tab } = await addTab( - ENGLISH_PAGE_URL, - "Creating a new tab for a page in English." - ); - - englishTab = tab; - removeEnglishTab = removeTab; - activeTab = "english"; - return true; - } - return false; - }, - - async removeEnglishTab() { - if (removeEnglishTab) { - reportOperation("removeEnglishTab"); - await removeEnglishTab(); - - englishTab = null; - removeEnglishTab = null; - activeTab = "spanish"; - return true; - } - return false; - }, - - async translateSpanishPage() { - if (!isSpanishPageTranslated) { - reportOperation("translateSpanishPage"); - if (activeTab === "english") { - await switchTab(spanishTab, "spanish tab"); - } - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton(); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: true, icon: true }, - "Translations button is fully loaded." - ); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInSpanishPage - ); - - isSpanishPageTranslated = true; - isEngineMaybeDestroyed = false; - activeTab = "spanish"; - return true; - } - return false; - }, - - async destroyEngineProcess() { - if ( - !isEngineMaybeDestroyed && - // Don't destroy the engine process until the mutation has been verified. - // There is an artifical race (e.g. only in tests) that happens from a new - // engine being requested, and forcefully destroyed before the it can be - // initialized. - hasVerifiedMutation - ) { - reportOperation("destroyEngineProcess"); - await TranslationsParent.destroyEngineProcess(); - isEngineMaybeDestroyed = true; - } - return true; - }, - - async mutateSpanishPage() { - if (isSpanishPageTranslated && !isTitleMutated) { - reportOperation("mutateSpanishPage"); - - info("Mutate the page's content to re-trigger a translation."); - await runInSpanishPage(async TranslationsTest => { - const { getH1 } = TranslationsTest.getSelectors(); - getH1().innerText = "New text for the H1"; - }); - - if (isEngineMaybeDestroyed) { - info("The engine may be recreated now."); - } - - isEngineMaybeDestroyed = false; - isTitleMutated = true; - hasVerifiedMutation = false; - return true; - } - return false; - }, - - async switchToSpanishTab() { - if (activeTab !== "spanish") { - reportOperation("switchToSpanishTab"); - await switchTab(spanishTab, "spanish tab"); - activeTab = "spanish"; - - if (isTitleMutated) { - await runInSpanishPage(async TranslationsTest => { - const { getH1 } = TranslationsTest.getSelectors(); - await TranslationsTest.assertTranslationResult( - "The mutated content should be translated.", - getH1, - "NEW TEXT FOR THE H1 [es to en]" - ); - }); - hasVerifiedMutation = true; - } - - return true; - } - return false; - }, - - async switchToEnglishTab() { - if (activeTab !== "english" && englishTab) { - reportOperation("switchToEnglishTab"); - await switchTab(englishTab, "english tab"); - activeTab = "english"; - return true; - } - return false; - }, - - async restoreSpanishPage() { - if (activeTab === "spanish" && isSpanishPageTranslated) { - reportOperation("restoreSpanishPage"); - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - - await FullPageTranslationsTestUtils.clickRestoreButton(); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated( - runInSpanishPage - ); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is reverted to have an icon." - ); - - isSpanishPageTranslated = false; - isTitleMutated = false; - return true; - } - return false; - }, - }; - - const fuzzSteps = 100; - info(`Starting the fuzzing with ${fuzzSteps} operations.`); - const opsArray = Object.values(operations); - - for (let i = 0; i < fuzzSteps; i++) { - // Pick a random operation and check if that it was not a noop, otherwise continue - // trying to find a valid operation. - while (true) { - const operation = opsArray[Math.floor(Math.random() * opsArray.length)]; - if (await operation()) { - break; - } - } - } - - if (removeEnglishTab) { - await removeEnglishTab(); - } - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_gear.js b/browser/components/translations/tests/browser/browser_translations_panel_gear.js deleted file mode 100644 index c24fc61e3d..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_gear.js +++ /dev/null @@ -1,32 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Test managing the languages menu item. - */ -add_task(async function test_translations_panel_manage_languages() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.clickManageLanguages(); - - await waitForCondition( - () => gBrowser.currentURI.spec === "about:preferences#general", - "Waiting for about:preferences to be opened." - ); - - info("Remove the about:preferences tab"); - gBrowser.removeCurrentTab(); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_language.js b/browser/components/translations/tests/browser/browser_translations_panel_never_translate_language.js deleted file mode 100644 index 6c1fea7754..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_language.js +++ /dev/null @@ -1,186 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of toggling the never-translate-language menuitem. - * Checking the box on an untranslated page should immediately hide the button. - * The button should not appear again for sites in the disabled language. - */ -add_task(async function test_toggle_never_translate_language_menuitem() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Reload the page", { url: SPANISH_PAGE_URL }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Navigate to a different Spanish page", { - url: SPANISH_PAGE_URL_DOT_ORG, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); -}); - -/** - * Tests the effect of toggling the never-translate-language menuitem on a page where - * where translation is already active. - * Checking the box on a translated page should restore the page and hide the button. - * The button should not appear again for sites in the disabled language. - */ -add_task( - async function test_toggle_never_translate_language_menuitem_with_active_translations() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Reload the page", { url: SPANISH_PAGE_URL }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); - } -); - -/** - * Tests the effect of toggling the never-translate-language menuitem on a page where - * where translation is already active via always-translate. - * Checking the box on a translated page should restore the page and hide the button. - * The language should be moved from always-translate to never-translate. - * The button should not appear again for sites in the disabled language. - */ -add_task( - async function test_toggle_never_translate_language_menuitem_with_always_translate_active() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: false, - }); - - await FullPageTranslationsTestUtils.clickNeverTranslateLanguage(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Reload the page", { url: SPANISH_PAGE_URL }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site.js b/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site.js deleted file mode 100644 index 858aa297df..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site.js +++ /dev/null @@ -1,247 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of toggling the never-translate-site menuitem. - * Checking the box on an untranslated page should immediately hide the button. - * The button should not appear again for sites that share the same content principal - * of the disabled site. - */ -add_task(async function test_toggle_never_translate_site_menuitem() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Navigate to a Spanish page with the same content principal", { - url: SPANISH_PAGE_URL_2, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with a different content principal", - { url: SPANISH_PAGE_URL_DOT_ORG } - ); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button should be visible, because this content principal " + - "has not been denied translations permissions" - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); -}); - -/** - * Tests the effect of toggling the never-translate-site menuitem on a page where - * where translation is already active. - * Checking the box on a translated page should restore the page and hide the button. - * The button should not appear again for sites that share the same content principal - * of the disabled site. - */ -add_task( - async function test_toggle_never_translate_site_menuitem_with_active_translations() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Reload the page", { url: SPANISH_PAGE_URL }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with the same content principal", - { url: SPANISH_PAGE_URL_2 } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with a different content principal", - { url: SPANISH_PAGE_URL_DOT_ORG } - ); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button should be visible, because this content principal " + - "has not been denied translations permissions" - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); - } -); - -/** - * Tests the effect of toggling the never-translate-site menuitem on a page where - * where translation is already active via always-translate. - * Checking the box on a translated page should restore the page and hide the button. - * The button should not appear again for sites that share the same content principal - * of the disabled site, and no auto-translation should occur. - * Other sites should still auto-translate for this language. - */ -add_task( - async function test_toggle_never_translate_site_menuitem_with_always_translate_active() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Reload the page", { url: SPANISH_PAGE_URL }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with the same content principal", - { url: SPANISH_PAGE_URL_2 } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with a different content principal", - { - url: SPANISH_PAGE_URL_DOT_ORG, - downloadHandler: resolveDownloads, - } - ); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_auto.js b/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_auto.js deleted file mode 100644 index 28f3b570c3..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_auto.js +++ /dev/null @@ -1,109 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of toggling the never-translate-site menuitem on a page where - * where translation is already active via always-translate. - * Checking the box on a translated page should restore the page and hide the button. - * The button should not appear again for sites that share the same content principal - * of the disabled site, and no auto-translation should occur. - * Other sites should still auto-translate for this language. - */ -add_task( - async function test_toggle_never_translate_site_menuitem_with_always_translate_active() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Reload the page", { url: SPANISH_PAGE_URL }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with the same content principal", - { url: SPANISH_PAGE_URL_2 } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with a different content principal", - { - url: SPANISH_PAGE_URL_DOT_ORG, - downloadHandler: resolveDownloads, - } - ); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_basic.js b/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_basic.js deleted file mode 100644 index 098ff54d6e..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_basic.js +++ /dev/null @@ -1,62 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of toggling the never-translate-site menuitem. - * Checking the box on an untranslated page should immediately hide the button. - * The button should not appear again for sites that share the same content principal - * of the disabled site. - */ -add_task(async function test_toggle_never_translate_site_menuitem() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Navigate to a Spanish page with the same content principal", { - url: SPANISH_PAGE_URL_2, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with a different content principal", - { url: SPANISH_PAGE_URL_DOT_ORG } - ); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button should be visible, because this content principal " + - "has not been denied translations permissions" - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_manual.js b/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_manual.js deleted file mode 100644 index d916342c33..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site_manual.js +++ /dev/null @@ -1,84 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the effect of toggling the never-translate-site menuitem on a page where - * where translation is already active. - * Checking the box on a translated page should restore the page and hide the button. - * The button should not appear again for sites that share the same content principal - * of the disabled site. - */ -add_task( - async function test_toggle_never_translate_site_menuitem_with_active_translations() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: false } - ); - await FullPageTranslationsTestUtils.clickNeverTranslateSite(); - await FullPageTranslationsTestUtils.assertIsNeverTranslateSite( - SPANISH_PAGE_URL, - { checked: true } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate("Reload the page", { url: SPANISH_PAGE_URL }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with the same content principal", - { url: SPANISH_PAGE_URL_2 } - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await navigate( - "Navigate to a Spanish page with a different content principal", - { url: SPANISH_PAGE_URL_DOT_ORG } - ); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button should be visible, because this content principal " + - "has not been denied translations permissions" - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_retry.js b/browser/components/translations/tests/browser/browser_translations_panel_retry.js deleted file mode 100644 index 76a6bd9429..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_retry.js +++ /dev/null @@ -1,54 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests translating, and then immediately translating to a new language. - */ -add_task(async function test_translations_panel_retry() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - - FullPageTranslationsTestUtils.switchSelectedToLanguage("fr"); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - pivotTranslation: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "fr", - runInPage - ); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_settings_unsupported_lang.js b/browser/components/translations/tests/browser/browser_translations_panel_settings_unsupported_lang.js deleted file mode 100644 index 18fcf484dd..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_settings_unsupported_lang.js +++ /dev/null @@ -1,74 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * This tests a specific defect where the language checkbox states were not being - * updated correctly when visiting a web page in an unsupported language after - * previously enabling always-translate-language or never-translate-language - * on a site with a supported language. - * - * See https://bugzilla.mozilla.org/show_bug.cgi?id=1845611 for more information. - */ -add_task(async function test_unsupported_language_settings_menu_checkboxes() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: [ - // Do not include French. - { fromLang: "en", toLang: "es" }, - { fromLang: "es", toLang: "en" }, - ], - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: false, - }); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("es", { - checked: true, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await navigate("Navigate to a page in an unsupported language.", { - url: FRENCH_PAGE_URL, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: false }, - "The translations button should be unavailable." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: - FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysTranslateLanguage("fr", { - checked: false, - disabled: true, - }); - await FullPageTranslationsTestUtils.assertIsNeverTranslateLanguage("fr", { - checked: false, - disabled: true, - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_panel_switch_languages.js b/browser/components/translations/tests/browser/browser_translations_panel_switch_languages.js deleted file mode 100644 index 3652c61d83..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_panel_switch_languages.js +++ /dev/null @@ -1,70 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests switching the language. - */ -add_task(async function test_translations_panel_switch_language() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - const { translateButton } = TranslationsPanel.elements; - - ok(!translateButton.disabled, "The translate button starts as enabled"); - - FullPageTranslationsTestUtils.assertSelectedFromLanguage("es"); - FullPageTranslationsTestUtils.assertSelectedToLanguage("en"); - - FullPageTranslationsTestUtils.switchSelectedFromLanguage("en"); - - ok( - translateButton.disabled, - "The translate button is disabled when the languages are the same" - ); - - FullPageTranslationsTestUtils.switchSelectedFromLanguage("es"); - - ok( - !translateButton.disabled, - "When the languages are different it can be translated" - ); - - FullPageTranslationsTestUtils.switchSelectedFromLanguage(""); - - ok( - translateButton.disabled, - "The translate button is disabled nothing is selected." - ); - - FullPageTranslationsTestUtils.switchSelectedFromLanguage("en"); - FullPageTranslationsTestUtils.switchSelectedToLanguage("fr"); - - ok(!translateButton.disabled, "The translate button can now be used"); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "en", - "fr", - runInPage - ); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_reader_mode.js b/browser/components/translations/tests/browser/browser_translations_reader_mode.js deleted file mode 100644 index d066257998..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_reader_mode.js +++ /dev/null @@ -1,115 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests that the translations button becomes hidden when entering reader mode. - */ -add_task(async function test_translations_button_hidden_in_reader_mode() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await toggleReaderMode(); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: false }, - "The translations button is now hidden in reader mode." - ); - - await runInPage(async TranslationsTest => { - const { getH1 } = TranslationsTest.getSelectors(); - await TranslationsTest.assertTranslationResult( - "The page's H1 is now the reader-mode header", - getH1, - "Translations Test" - ); - }); - - await runInPage(async TranslationsTest => { - const { getLastParagraph } = TranslationsTest.getSelectors(); - await TranslationsTest.assertTranslationResult( - "The page's last paragraph is in Spanish.", - getLastParagraph, - "— Pues, aunque mováis más brazos que los del gigante Briareo, me lo habéis de pagar." - ); - }); - - await toggleReaderMode(); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is visible again outside of reader mode." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); -}); - -/** - * Tests that translations persist when entering reader mode after translating. - */ -add_task(async function test_translations_persist_in_reader_mode() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is visible." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await toggleReaderMode(); - - await runInPage(async TranslationsTest => { - const { getH1 } = TranslationsTest.getSelectors(); - await TranslationsTest.assertTranslationResult( - "The page's H1 is now the translated reader-mode header", - getH1, - "TRANSLATIONS TEST [es to en, html]" - ); - }); - - await runInPage(async TranslationsTest => { - const { getLastParagraph } = TranslationsTest.getSelectors(); - await TranslationsTest.assertTranslationResult( - "The page's last paragraph is in Spanish.", - getLastParagraph, - "— PUES, AUNQUE MOVÁIS MÁS BRAZOS QUE LOS DEL GIGANTE BRIAREO, ME LO HABÉIS DE PAGAR. [es to en, html]" - ); - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: false }, - "The translations button is now hidden in reader mode." - ); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_select_context_menu_with_full_page_translations_active.js b/browser/components/translations/tests/browser/browser_translations_select_context_menu_with_full_page_translations_active.js index 58cb655e38..99cff2b4ec 100644 --- a/browser/components/translations/tests/browser/browser_translations_select_context_menu_with_full_page_translations_active.js +++ b/browser/components/translations/tests/browser/browser_translations_select_context_menu_with_full_page_translations_active.js @@ -35,7 +35,7 @@ add_task( "The translate-selection context menu item should be available while full-page translations is inactive." ); - await FullPageTranslationsTestUtils.openTranslationsPanel({ + await FullPageTranslationsTestUtils.openPanel({ onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, }); @@ -59,7 +59,7 @@ add_task( "The translate-selection context menu item should be unavailable while full-page translations is active." ); - await FullPageTranslationsTestUtils.openTranslationsPanel({ + await FullPageTranslationsTestUtils.openPanel({ onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, }); @@ -114,7 +114,7 @@ add_task( "The translate-selection context menu item should be available while full-page translations is inactive." ); - await FullPageTranslationsTestUtils.openTranslationsPanel({ + await FullPageTranslationsTestUtils.openPanel({ onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, }); @@ -138,7 +138,7 @@ add_task( "The translate-selection context menu item should be unavailable while full-page translations is active." ); - await FullPageTranslationsTestUtils.openTranslationsPanel({ + await FullPageTranslationsTestUtils.openPanel({ onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, }); diff --git a/browser/components/translations/tests/browser/browser_translations_select_panel_language_selectors.js b/browser/components/translations/tests/browser/browser_translations_select_panel_language_selectors.js new file mode 100644 index 0000000000..1dcc76450f --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_select_panel_language_selectors.js @@ -0,0 +1,54 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task( + async function test_select_translations_panel_open_spanish_language_selectors() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.select.enable", true]], + }); + + await SelectTranslationsTestUtils.openPanel(runInPage, { + selectSpanishParagraph: true, + openAtSpanishParagraph: true, + expectedTargetLanguage: "en", + onOpenPanel: SelectTranslationsTestUtils.assertPanelViewDefault, + }); + + SelectTranslationsTestUtils.assertSelectedFromLanguage({ langTag: "es" }); + SelectTranslationsTestUtils.assertSelectedToLanguage({ langTag: "en" }); + + await SelectTranslationsTestUtils.clickDoneButton(); + + await cleanup(); + } +); + +add_task( + async function test_select_translations_panel_open_english_language_selectors() { + const { cleanup, runInPage } = await loadTestPage({ + page: ENGLISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.select.enable", true]], + }); + + await SelectTranslationsTestUtils.openPanel(runInPage, { + selectFirstParagraph: true, + openAtFirstParagraph: true, + expectedTargetLanguage: "en", + onOpenPanel: SelectTranslationsTestUtils.assertPanelViewDefault, + }); + + SelectTranslationsTestUtils.assertSelectedFromLanguage({ langTag: "en" }); + SelectTranslationsTestUtils.assertSelectedToLanguage({ + l10nId: "translations-panel-choose-language", + }); + + await SelectTranslationsTestUtils.clickDoneButton(); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_select_panel_mainview_ui.js b/browser/components/translations/tests/browser/browser_translations_select_panel_mainview_ui.js new file mode 100644 index 0000000000..79d21e57d0 --- /dev/null +++ b/browser/components/translations/tests/browser/browser_translations_select_panel_mainview_ui.js @@ -0,0 +1,36 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * This test case verifies the visibility and initial state of UI elements within the + * Select Translations Panel's main-view UI. + */ +add_task( + async function test_select_translations_panel_mainview_ui_element_visibility() { + const { cleanup, runInPage } = await loadTestPage({ + page: SPANISH_PAGE_URL, + languagePairs: LANGUAGE_PAIRS, + prefs: [["browser.translations.select.enable", true]], + }); + + await FullPageTranslationsTestUtils.assertTranslationsButton( + { button: true, circleArrows: false, locale: false, icon: true }, + "The button is available." + ); + + await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); + + await SelectTranslationsTestUtils.openPanel(runInPage, { + selectSpanishParagraph: true, + openAtSpanishParagraph: true, + expectedTargetLanguage: "es", + onOpenPanel: SelectTranslationsTestUtils.assertPanelViewDefault, + }); + + await SelectTranslationsTestUtils.clickDoneButton(); + + await cleanup(); + } +); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_auto_translate.js b/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_auto_translate.js deleted file mode 100644 index abfc3dc32e..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_auto_translate.js +++ /dev/null @@ -1,117 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the entire flow of opening the translation settings menu and initiating - * an auto-translate request on the first panel interaction. - */ -add_task(async function test_translations_telemetry_firstrun_auto_translate() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.panelShown", false]], - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - await FullPageTranslationsTestUtils.clickAlwaysTranslateLanguage({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - expectFirstInteraction: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.alwaysTranslateLanguage, - { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - finalValuePredicates: [value => value.extra.language === "es"], - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - }); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translations.translationRequest, - { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - } - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewRevisit, - }); - - await FullPageTranslationsTestUtils.clickRestoreButton(); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 2, - expectNewFlowId: true, - expectFirstInteraction: false, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "revisitView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.restorePageButton, - { - expectedEventCount: 1, - expectFirstInteraction: false, - expectNewFlowId: false, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 2, - expectFirstInteraction: false, - expectNewFlowId: false, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_basics.js b/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_basics.js deleted file mode 100644 index 200e06b9ce..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_basics.js +++ /dev/null @@ -1,93 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests that events in the first panel session are marked as first-interaction events - * and that events in the subsequent panel session are not marked as first-interaction events. - */ -add_task(async function test_translations_telemetry_firstrun_basics() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.panelShown", false]], - }); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 0, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - expectFirstInteraction: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 2, - expectNewFlowId: true, - expectFirstInteraction: false, - allValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 2, - expectNewFlowId: false, - expectFirstInteraction: false, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 2, - expectNewFlowId: false, - expectFirstInteraction: false, - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_translation_failure.js b/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_translation_failure.js deleted file mode 100644 index 5397175039..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_translation_failure.js +++ /dev/null @@ -1,149 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -const { PromiseTestUtils } = ChromeUtils.importESModule( - "resource://testing-common/PromiseTestUtils.sys.mjs" -); - -/** - * Tests that the first-interaction event status is maintained across a subsequent panel - * open, if re-opening the panel is due to a translation failure. - */ -add_task(async function test_translations_telemetry_firstrun_failure() { - const { cleanup, rejectDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.panelShown", false]], - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, - }); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - expectFirstInteraction: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: rejectDownloads, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShowError, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 2, - expectNewFlowId: false, - expectFirstInteraction: true, - finalValuePredicates: [ - value => value.extra.auto_show === "true", - value => value.extra.view_name === "errorView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.translateButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - }); - await TestTranslationsTelemetry.assertEvent(Glean.translations.error, { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - finalValuePredicates: [ - value => - value.extra.reason === "Error: Intentionally rejecting downloads.", - ], - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translations.translationRequest, - { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - finalValuePredicates: [ - value => value.extra.from_language === "es", - value => value.extra.to_language === "en", - value => value.extra.auto_translate === "false", - value => value.extra.document_language === "es", - value => value.extra.top_preferred_language === "en", - ], - } - ); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 2, - expectNewFlowId: false, - expectFirstInteraction: true, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewFirstShow, - }); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 3, - expectNewFlowId: true, - expectFirstInteraction: false, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 2, - expectNewFlowId: false, - expectFirstInteraction: false, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 3, - expectNewFlowId: false, - expectFirstInteraction: false, - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_unsupported_lang.js b/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_unsupported_lang.js deleted file mode 100644 index fa9c67ee37..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_firstrun_unsupported_lang.js +++ /dev/null @@ -1,122 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests that the first-interaction event status is maintained across a subsequent panel - * open, if re-opening the panel is due to requesting to change the source language. - */ -add_task( - async function test_translations_telemetry_firstrun_unsupported_lang() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: [ - // Do not include Spanish. - { fromLang: "fr", toLang: "en" }, - { fromLang: "en", toLang: "fr" }, - ], - prefs: [["browser.translations.panelShown", false]], - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: - FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, - }); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - expectFirstInteraction: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "appMenu", - value => value.extra.document_language === "es", - ], - }); - - await FullPageTranslationsTestUtils.clickChangeSourceLanguageButton({ - firstShow: true, - }); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.changeSourceLanguageButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - }); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 2, - expectNewFlowId: false, - expectFirstInteraction: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "appMenu", - value => value.extra.document_language === "es", - ], - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: true, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 2, - expectNewFlowId: false, - expectFirstInteraction: true, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - openFromAppMenu: true, - onOpenPanel: - FullPageTranslationsTestUtils.assertPanelViewUnsupportedLanguage, - }); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 3, - expectNewFlowId: true, - expectFirstInteraction: false, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "appMenu", - value => value.extra.document_language === "es", - ], - }); - - await FullPageTranslationsTestUtils.clickDismissErrorButton(); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.dismissErrorButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - expectFirstInteraction: false, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 3, - expectNewFlowId: false, - expectFirstInteraction: false, - }); - - await cleanup(); - } -); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_open_panel.js b/browser/components/translations/tests/browser/browser_translations_telemetry_open_panel.js deleted file mode 100644 index 64a02287e8..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_open_panel.js +++ /dev/null @@ -1,85 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the telemetry event for opening the translations panel. - */ -add_task(async function test_translations_telemetry_open_panel() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 0, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 2, - expectNewFlowId: true, - allValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 2, - expectNewFlowId: false, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 2, - expectNewFlowId: false, - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_panel_auto_offer.js b/browser/components/translations/tests/browser/browser_translations_telemetry_panel_auto_offer.js deleted file mode 100644 index 93ff473851..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_panel_auto_offer.js +++ /dev/null @@ -1,83 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests that the popup is automatically offered. - */ -add_task(async function test_translations_panel_auto_offer() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - autoOffer: true, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - allValuePredicates: [ - value => value.extra.auto_show === "true", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - }); - - await navigate("Navigate to another page on the same domain.", { - url: SPANISH_PAGE_URL_2, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is still shown." - ); - - await navigate("Navigate to a page on a different domain.", { - url: SPANISH_PAGE_URL_DOT_ORG, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 2, - expectNewFlowId: true, - allValuePredicates: [ - value => value.extra.auto_show === "true", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 2, - expectNewFlowId: false, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 2, - expectNewFlowId: false, - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_panel_auto_offer_settings.js b/browser/components/translations/tests/browser/browser_translations_telemetry_panel_auto_offer_settings.js deleted file mode 100644 index 9eae81904d..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_panel_auto_offer_settings.js +++ /dev/null @@ -1,110 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests that the automatic offering of the popup can be disabled. - */ -add_task(async function test_translations_panel_auto_offer_settings() { - const { cleanup } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - // Use the auto offer mechanics, but default the pref to the off position. - autoOffer: true, - prefs: [["browser.translations.automaticallyPopup", false]], - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The translations button is shown." - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 0, - }); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.openTranslationsSettingsMenu(); - await FullPageTranslationsTestUtils.assertIsAlwaysOfferTranslationsEnabled( - false - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - allValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await FullPageTranslationsTestUtils.clickAlwaysOfferTranslations(); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.alwaysOfferTranslations, - { - expectedEventCount: 1, - expectNewFlowId: false, - allValuePredicates: [value => value.extra.toggled_on === "true"], - } - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - await FullPageTranslationsTestUtils.assertIsAlwaysOfferTranslationsEnabled( - true - ); - - await FullPageTranslationsTestUtils.clickCancelButton(); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 2, - expectNewFlowId: true, - allValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 2, - expectNewFlowId: false, - }); - - await navigate( - "Wait for the popup to be shown when navigating to a different host.", - { - url: SPANISH_PAGE_URL_DOT_ORG, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - } - ); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 3, - expectNewFlowId: true, - finalValuePredicates: [ - value => value.extra.auto_show === "true", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_switch_languages.js b/browser/components/translations/tests/browser/browser_translations_telemetry_switch_languages.js deleted file mode 100644 index 6c06abab95..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_switch_languages.js +++ /dev/null @@ -1,156 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the telemetry events for switching the from-language. - */ -add_task(async function test_translations_telemetry_switch_from_language() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - FullPageTranslationsTestUtils.assertSelectedFromLanguage("es"); - FullPageTranslationsTestUtils.switchSelectedFromLanguage("en"); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.changeFromLanguage, - { - expectedEventCount: 1, - expectNewFlowId: false, - finalValuePredicates: [value => value.extra.language === "en"], - } - ); - - FullPageTranslationsTestUtils.switchSelectedFromLanguage("es"); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.changeFromLanguage, - { - expectedEventCount: 2, - expectNewFlowId: false, - finalValuePredicates: [value => value.extra.language === "es"], - } - ); - - FullPageTranslationsTestUtils.switchSelectedFromLanguage(""); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.changeFromLanguage, - { - expectedEventCount: 2, - } - ); - - FullPageTranslationsTestUtils.switchSelectedFromLanguage("en"); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.changeFromLanguage, - { - expectedEventCount: 3, - expectNewFlowId: false, - finalValuePredicates: [value => value.extra.language === "en"], - } - ); - - await cleanup(); -}); - -/** - * Tests the telemetry events for switching the to-language. - */ -add_task(async function test_translations_telemetry_switch_to_language() { - const { cleanup, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - FullPageTranslationsTestUtils.assertSelectedToLanguage("en"); - FullPageTranslationsTestUtils.switchSelectedToLanguage("fr"); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.changeToLanguage, - { - expectedEventCount: 1, - expectNewFlowId: false, - finalValuePredicates: [value => value.extra.language === "fr"], - } - ); - - FullPageTranslationsTestUtils.switchSelectedToLanguage("en"); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.changeToLanguage, - { - expectedEventCount: 2, - expectNewFlowId: false, - finalValuePredicates: [value => value.extra.language === "en"], - } - ); - - FullPageTranslationsTestUtils.switchSelectedToLanguage(""); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.changeToLanguage, - { - expectedEventCount: 2, - } - ); - - FullPageTranslationsTestUtils.switchSelectedToLanguage("en"); - - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.changeToLanguage, - { - expectedEventCount: 3, - expectNewFlowId: false, - finalValuePredicates: [value => value.extra.language === "en"], - } - ); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_translation_failure.js b/browser/components/translations/tests/browser/browser_translations_telemetry_translation_failure.js deleted file mode 100644 index e7d0cfb4f4..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_translation_failure.js +++ /dev/null @@ -1,212 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -const { PromiseTestUtils } = ChromeUtils.importESModule( - "resource://testing-common/PromiseTestUtils.sys.mjs" -); - -/** - * Tests the telemetry event for a manual translation request failure. - */ -add_task( - async function test_translations_telemetry_manual_translation_failure() { - const { cleanup, rejectDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await TestTranslationsTelemetry.assertCounter( - "RequestCount", - Glean.translations.requestsCount, - 0 - ); - await TestTranslationsTelemetry.assertRate( - "ErrorRate", - Glean.translations.errorRate, - { - expectedNumerator: 0, - expectedDenominator: 0, - } - ); - await TestTranslationsTelemetry.assertEvent( - Glean.translations.translationRequest, - { - expectedEventCount: 0, - } - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: rejectDownloads, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewError, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 2, - expectNewFlowId: false, - finalValuePredicates: [ - value => value.extra.auto_show === "true", - value => value.extra.view_name === "errorView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.translateButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - }); - await TestTranslationsTelemetry.assertCounter( - "RequestCount", - Glean.translations.requestsCount, - 1 - ); - await TestTranslationsTelemetry.assertRate( - "ErrorRate", - Glean.translations.errorRate, - { - expectedNumerator: 1, - expectedDenominator: 1, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translations.error, { - expectedEventCount: 1, - expectNewFlowId: false, - finalValuePredicates: [ - value => - value.extra.reason === "Error: Intentionally rejecting downloads.", - ], - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translations.translationRequest, - { - expectedEventCount: 1, - expectNewFlowId: false, - finalValuePredicates: [ - value => value.extra.from_language === "es", - value => value.extra.to_language === "en", - value => value.extra.auto_translate === "false", - value => value.extra.document_language === "es", - value => value.extra.top_preferred_language === "en", - ], - } - ); - - await cleanup(); - } -); - -/** - * Tests the telemetry event for an automatic translation request failure. - */ -add_task(async function test_translations_telemetry_auto_translation_failure() { - const { cleanup, rejectDownloads, runInPage } = await loadTestPage({ - page: BLANK_PAGE, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.alwaysTranslateLanguages", "es"]], - }); - - await navigate("Navigate to a Spanish page", { - url: SPANISH_PAGE_URL, - downloadHandler: rejectDownloads, - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewError, - }); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await TestTranslationsTelemetry.assertCounter( - "RequestCount", - Glean.translations.requestsCount, - 1 - ); - await TestTranslationsTelemetry.assertRate( - "ErrorRate", - Glean.translations.errorRate, - { - expectedNumerator: 1, - expectedDenominator: 1, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - finalValuePredicates: [ - value => value.extra.auto_show === "true", - value => value.extra.view_name === "errorView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 0, - expectNewFlowId: false, - }); - await TestTranslationsTelemetry.assertEvent(Glean.translations.error, { - expectedEventCount: 1, - expectNewFlowId: false, - finalValuePredicates: [ - value => - value.extra.reason === "Error: Intentionally rejecting downloads.", - ], - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translations.translationRequest, - { - expectedEventCount: 1, - expectNewFlowId: false, - finalValuePredicates: [ - value => value.extra.from_language === "es", - value => value.extra.to_language === "en", - value => value.extra.auto_translate === "true", - value => value.extra.document_language === "es", - value => value.extra.top_preferred_language === "en", - ], - } - ); - - await FullPageTranslationsTestUtils.clickCancelButton(); - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.cancelButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - }); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/browser_translations_telemetry_translation_request.js b/browser/components/translations/tests/browser/browser_translations_telemetry_translation_request.js deleted file mode 100644 index 90bd81a8ed..0000000000 --- a/browser/components/translations/tests/browser/browser_translations_telemetry_translation_request.js +++ /dev/null @@ -1,170 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -/** - * Tests the telemetry event for a manual translation request. - */ -add_task(async function test_translations_telemetry_manual_translation() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: SPANISH_PAGE_URL, - languagePairs: LANGUAGE_PAIRS, - }); - - await FullPageTranslationsTestUtils.assertTranslationsButton( - { button: true, circleArrows: false, locale: false, icon: true }, - "The button is available." - ); - - await FullPageTranslationsTestUtils.assertPageIsUntranslated(runInPage); - - await TestTranslationsTelemetry.assertCounter( - "RequestCount", - Glean.translations.requestsCount, - 0 - ); - await TestTranslationsTelemetry.assertRate( - "ErrorRate", - Glean.translations.errorRate, - { - expectedNumerator: 0, - expectedDenominator: 0, - } - ); - await TestTranslationsTelemetry.assertEvent( - Glean.translations.translationRequest, - { - expectedEventCount: 0, - } - ); - - await FullPageTranslationsTestUtils.openTranslationsPanel({ - onOpenPanel: FullPageTranslationsTestUtils.assertPanelViewDefault, - }); - - await FullPageTranslationsTestUtils.clickTranslateButton({ - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await TestTranslationsTelemetry.assertCounter( - "RequestCount", - Glean.translations.requestsCount, - 1 - ); - await TestTranslationsTelemetry.assertRate( - "ErrorRate", - Glean.translations.errorRate, - { - expectedNumerator: 0, - expectedDenominator: 1, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 1, - expectNewFlowId: true, - finalValuePredicates: [ - value => value.extra.auto_show === "false", - value => value.extra.view_name === "defaultView", - value => value.extra.opened_from === "translationsButton", - value => value.extra.document_language === "es", - ], - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.translateButton, - { - expectedEventCount: 1, - expectNewFlowId: false, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 1, - expectNewFlowId: false, - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translations.translationRequest, - { - expectedEventCount: 1, - expectNewFlowId: false, - finalValuePredicates: [ - value => value.extra.from_language === "es", - value => value.extra.to_language === "en", - value => value.extra.auto_translate === "false", - value => value.extra.document_language === "es", - value => value.extra.top_preferred_language === "en", - ], - } - ); - - await cleanup(); -}); - -/** - * Tests the telemetry event for an automatic translation request. - */ -add_task(async function test_translations_telemetry_auto_translation() { - const { cleanup, resolveDownloads, runInPage } = await loadTestPage({ - page: BLANK_PAGE, - languagePairs: LANGUAGE_PAIRS, - prefs: [["browser.translations.alwaysTranslateLanguages", "es"]], - }); - - await navigate("Navigate to a Spanish page", { - url: SPANISH_PAGE_URL, - downloadHandler: resolveDownloads, - }); - - await FullPageTranslationsTestUtils.assertPageIsTranslated( - "es", - "en", - runInPage - ); - - await TestTranslationsTelemetry.assertCounter( - "RequestCount", - Glean.translations.requestsCount, - 1 - ); - await TestTranslationsTelemetry.assertRate( - "ErrorRate", - Glean.translations.errorRate, - { - expectedNumerator: 0, - expectedDenominator: 1, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.open, { - expectedEventCount: 0, - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translationsPanel.translateButton, - { - expectedEventCount: 0, - } - ); - await TestTranslationsTelemetry.assertEvent(Glean.translationsPanel.close, { - expectedEventCount: 0, - }); - await TestTranslationsTelemetry.assertEvent( - Glean.translations.translationRequest, - { - expectedEventCount: 1, - expectNewFlowId: true, - finalValuePredicates: [ - value => value.extra.from_language === "es", - value => value.extra.to_language === "en", - value => value.extra.auto_translate === "true", - value => value.extra.document_language === "es", - value => value.extra.top_preferred_language === "en", - ], - } - ); - - await cleanup(); -}); diff --git a/browser/components/translations/tests/browser/head.js b/browser/components/translations/tests/browser/head.js index bc9968308c..200ed08719 100644 --- a/browser/components/translations/tests/browser/head.js +++ b/browser/components/translations/tests/browser/head.js @@ -206,7 +206,7 @@ async function navigate( // it doesn't close on navigate the way that it does when it's // open from the translations button, so ensure that we always // close it when we navigate to a new page. - await closeTranslationsPanelIfOpen(); + await closeAllOpenPanelsAndMenus(); info(message); @@ -230,7 +230,7 @@ async function navigate( info(`Loading url: "${url}"`); if (onOpenPanel) { - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( "popupshown", loadTargetPage, onOpenPanel @@ -276,6 +276,146 @@ async function toggleReaderMode() { await readyPromise; } +/** + * A collection of shared functionality utilized by + * FullPageTranslationsTestUtils and SelectTranslationsTestUtils. + * + * Using functions from the aforementioned classes is preferred over + * using functions from this class directly. + */ +class SharedTranslationsTestUtils { + /** + * Asserts that the mainViewId of the panel matches the given string. + * + * @param {FullPageTranslationsPanel | SelectTranslationsPanel} panel + * @param {string} expectedId - The expected id that mainViewId is set to. + */ + static _assertPanelMainViewId(panel, expectedId) { + const mainViewId = panel.elements.multiview.getAttribute("mainViewId"); + is( + mainViewId, + expectedId, + "The mainViewId should match its expected value" + ); + } + + /** + * Asserts that the selected from-language matches the provided arguments. + * + * @param {FullPageTranslationsPanel | SelectTranslationsPanel} panel + * - The UI component or panel whose selected from-language is being asserted. + * @param {object} options - An object containing assertion parameters. + * @param {string} [options.langTag] - A BCP-47 language tag. + * @param {string} [options.l10nId] - A localization identifier. + */ + static _assertSelectedFromLanguage(panel, { langTag, l10nId }) { + const { fromMenuList } = panel.elements; + is( + fromMenuList.value, + langTag, + "Expected selected from-language to match the given language tag" + ); + if (l10nId) { + is( + fromMenuList.getAttribute("data-l10n-id"), + l10nId, + "Expected selected from-language to match the given l10n id" + ); + } + } + + /** + * Asserts that the selected to-language matches the provided arguments. + * + * @param {FullPageTranslationsPanel | SelectTranslationsPanel} panel + * - The UI component or panel whose selected from-language is being asserted. + * @param {object} options - An object containing assertion parameters. + * @param {string} [options.langTag] - A BCP-47 language tag. + * @param {string} [options.l10nId] - A localization identifier. + */ + static _assertSelectedToLanguage(panel, { langTag, l10nId }) { + const { toMenuList } = panel.elements; + if (langTag) { + is( + toMenuList.value, + langTag, + "Expected selected to-language to match the given language tag" + ); + } + if (l10nId) { + is( + toMenuList.getAttribute("data-l10n-id"), + l10nId, + "Expected selected to-language to match the given l10n id" + ); + } + } + + /** + * Asserts the visibility of the given elements based on the given expectations. + * + * @param {object} elements - An object containing the elements to be checked for visibility. + * @param {object} expectations - An object where each property corresponds to a property in elements, + * and its value is a boolean indicating whether the element should + * be visible (true) or hidden (false). + * @throws Throws if elements does not contain a property for each property in expectations. + */ + static _assertPanelElementVisibility(elements, expectations) { + const hidden = {}; + const visible = {}; + + for (const propertyName in expectations) { + ok( + elements.hasOwnProperty(propertyName), + `Expected panel elements to have property ${propertyName}` + ); + if (expectations[propertyName]) { + visible[propertyName] = elements[propertyName]; + } else { + hidden[propertyName] = elements[propertyName]; + } + } + + assertVisibility({ hidden, visible }); + } + + /** + * Executes the provided callback before waiting for the event and then waits for the given event + * to be fired for the element corresponding to the provided elementId. + * + * Optionally executes a postEventAssertion function once the event occurs. + * + * @param {string} elementId - The Id of the element to wait for the event on. + * @param {string} eventName - The name of the event to wait for. + * @param {Function} callback - A callback function to execute immediately before waiting for the event. + * This is often used to trigger the event on the expected element. + * @param {Function|null} [postEventAssertion=null] - An optional callback function to execute after + * the event has occurred. + * @throws Throws if the element with the specified `elementId` does not exist. + * @returns {Promise} + */ + static async _waitForPopupEvent( + elementId, + eventName, + callback, + postEventAssertion = null + ) { + const element = document.getElementById(elementId); + if (!element) { + throw new Error("Unable to find the translations panel element."); + } + const promise = BrowserTestUtils.waitForEvent(element, eventName); + await callback(); + info("Waiting for the translations panel popup to be shown"); + await promise; + if (postEventAssertion) { + postEventAssertion(); + } + // Wait a single tick on the event loop. + await new Promise(resolve => setTimeout(resolve, 0)); + } +} + /** * A class containing test utility functions specific to testing full-page translations. */ @@ -515,61 +655,45 @@ class FullPageTranslationsTestUtils { /** * Asserts that for each provided expectation, the visible state of the corresponding - * element in TranslationsPanel.elements both exists and matches the visibility expectation. + * element in FullPageTranslationsPanel.elements both exists and matches the visibility expectation. * * @param {object} expectations - * A list of expectations for the visibility of any subset of TranslationsPanel.elements + * A list of expectations for the visibility of any subset of FullPageTranslationsPanel.elements */ static #assertPanelElementVisibility(expectations = {}) { - // Assume nothing is visible by default, and overwrite them - // with any specific expectations provided in the argument. - const finalExpectations = { - cancelButton: false, - changeSourceLanguageButton: false, - dismissErrorButton: false, - error: false, - fromMenuList: false, - fromLabel: false, - header: false, - intro: false, - introLearnMoreLink: false, - langSelection: false, - restoreButton: false, - toLabel: false, - toMenuList: false, - translateButton: false, - unsupportedHeader: false, - unsupportedHint: false, - unsupportedLearnMoreLink: false, - ...expectations, - }; - - const elements = TranslationsPanel.elements; - const hidden = {}; - const visible = {}; - - for (const propertyName in finalExpectations) { - ok( - elements.hasOwnProperty(propertyName), - `Expected translations panel elements to have property ${propertyName}` - ); - if (finalExpectations[propertyName]) { - visible[propertyName] = elements[propertyName]; - } else { - hidden[propertyName] = elements[propertyName]; + SharedTranslationsTestUtils._assertPanelElementVisibility( + FullPageTranslationsPanel.elements, + { + cancelButton: false, + changeSourceLanguageButton: false, + dismissErrorButton: false, + error: false, + fromMenuList: false, + fromLabel: false, + header: false, + intro: false, + introLearnMoreLink: false, + langSelection: false, + restoreButton: false, + toLabel: false, + toMenuList: false, + translateButton: false, + unsupportedHeader: false, + unsupportedHint: false, + unsupportedLearnMoreLink: false, + // Overwrite any of the above defaults with the passed in expectations. + ...expectations, } - } - - assertVisibility({ hidden, visible }); + ); } /** - * Asserts that the TranslationsPanel header has the expected l10nId. + * Asserts that the FullPageTranslationsPanel header has the expected l10nId. * * @param {string} l10nId - The expected data-l10n-id of the header. */ static #assertPanelHeaderL10nId(l10nId) { - const { header } = TranslationsPanel.elements; + const { header } = FullPageTranslationsPanel.elements; is( header.getAttribute("data-l10n-id"), l10nId, @@ -577,18 +701,29 @@ class FullPageTranslationsTestUtils { ); } + /** + * Asserts that the FullPageTranslationsPanel error has the expected l10nId. + * + * @param {string} l10nId - The expected data-l10n-id of the error. + */ + static #assertPanelErrorL10nId(l10nId) { + const { errorMessage } = FullPageTranslationsPanel.elements; + is( + errorMessage.getAttribute("data-l10n-id"), + l10nId, + "The translations panel error message should match the expected data-l10n-id" + ); + } + /** * Asserts that the mainViewId of the panel matches the given string. * * @param {string} expectedId */ static #assertPanelMainViewId(expectedId) { - const mainViewId = - TranslationsPanel.elements.multiview.getAttribute("mainViewId"); - is( - mainViewId, - expectedId, - "The full-page Translations panel mainViewId should match its expected value" + SharedTranslationsTestUtils._assertPanelMainViewId( + FullPageTranslationsPanel, + expectedId ); } @@ -598,7 +733,7 @@ class FullPageTranslationsTestUtils { static assertPanelViewDefault() { info("Checking that the panel shows the default view"); FullPageTranslationsTestUtils.#assertPanelMainViewId( - "translations-panel-view-default" + "full-page-translations-panel-view-default" ); FullPageTranslationsTestUtils.#assertPanelElementVisibility({ ...FullPageTranslationsTestUtils.#defaultViewVisibilityExpectations, @@ -614,7 +749,7 @@ class FullPageTranslationsTestUtils { static assertPanelViewError() { info("Checking that the panel shows the error view"); FullPageTranslationsTestUtils.#assertPanelMainViewId( - "translations-panel-view-default" + "full-page-translations-panel-view-default" ); FullPageTranslationsTestUtils.#assertPanelElementVisibility({ error: true, @@ -623,6 +758,9 @@ class FullPageTranslationsTestUtils { FullPageTranslationsTestUtils.#assertPanelHeaderL10nId( "translations-panel-header" ); + FullPageTranslationsTestUtils.#assertPanelErrorL10nId( + "translations-panel-error-translating" + ); } /** @@ -644,7 +782,7 @@ class FullPageTranslationsTestUtils { static assertPanelViewFirstShow() { info("Checking that the panel shows the first-show view"); FullPageTranslationsTestUtils.#assertPanelMainViewId( - "translations-panel-view-default" + "full-page-translations-panel-view-default" ); FullPageTranslationsTestUtils.#assertPanelElementVisibility({ intro: true, @@ -662,7 +800,7 @@ class FullPageTranslationsTestUtils { static assertPanelViewFirstShowError() { info("Checking that the panel shows the first-show error view"); FullPageTranslationsTestUtils.#assertPanelMainViewId( - "translations-panel-view-default" + "full-page-translations-panel-view-default" ); FullPageTranslationsTestUtils.#assertPanelElementVisibility({ error: true, @@ -681,7 +819,7 @@ class FullPageTranslationsTestUtils { static assertPanelViewRevisit() { info("Checking that the panel shows the revisit view"); FullPageTranslationsTestUtils.#assertPanelMainViewId( - "translations-panel-view-default" + "full-page-translations-panel-view-default" ); FullPageTranslationsTestUtils.#assertPanelElementVisibility({ header: true, @@ -702,7 +840,7 @@ class FullPageTranslationsTestUtils { static assertPanelViewUnsupportedLanguage() { info("Checking that the panel shows the unsupported-language view"); FullPageTranslationsTestUtils.#assertPanelMainViewId( - "translations-panel-view-unsupported-language" + "full-page-translations-panel-view-unsupported-language" ); FullPageTranslationsTestUtils.#assertPanelElementVisibility({ changeSourceLanguageButton: true, @@ -718,13 +856,10 @@ class FullPageTranslationsTestUtils { * * @param {string} langTag - A BCP-47 language tag. */ - static assertSelectedFromLanguage(langTag) { - info(`Checking that the selected from-language matches ${langTag}`); - const { fromMenuList } = TranslationsPanel.elements; - is( - fromMenuList.value, - langTag, - "Expected selected from-language to match the given language tag" + static assertSelectedFromLanguage({ langTag, l10nId }) { + SharedTranslationsTestUtils._assertSelectedFromLanguage( + FullPageTranslationsPanel, + { langTag, l10nId } ); } @@ -733,13 +868,10 @@ class FullPageTranslationsTestUtils { * * @param {string} langTag - A BCP-47 language tag. */ - static assertSelectedToLanguage(langTag) { - info(`Checking that the selected to-language matches ${langTag}`); - const { toMenuList } = TranslationsPanel.elements; - is( - toMenuList.value, - langTag, - "Expected selected to-language to match the given language tag" + static assertSelectedToLanguage({ langTag, l10nId }) { + SharedTranslationsTestUtils._assertSelectedToLanguage( + FullPageTranslationsPanel, + { langTag, l10nId } ); } @@ -827,9 +959,9 @@ class FullPageTranslationsTestUtils { */ static async clickCancelButton() { logAction(); - const { cancelButton } = TranslationsPanel.elements; + const { cancelButton } = FullPageTranslationsPanel.elements; assertVisibility({ visible: { cancelButton } }); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( "popuphidden", () => { click(cancelButton, "Clicking the cancel button"); @@ -847,9 +979,9 @@ class FullPageTranslationsTestUtils { */ static async clickChangeSourceLanguageButton({ firstShow = false } = {}) { logAction(); - const { changeSourceLanguageButton } = TranslationsPanel.elements; + const { changeSourceLanguageButton } = FullPageTranslationsPanel.elements; assertVisibility({ visible: { changeSourceLanguageButton } }); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( "popupshown", () => { click( @@ -868,9 +1000,9 @@ class FullPageTranslationsTestUtils { */ static async clickDismissErrorButton() { logAction(); - const { dismissErrorButton } = TranslationsPanel.elements; + const { dismissErrorButton } = FullPageTranslationsPanel.elements; assertVisibility({ visible: { dismissErrorButton } }); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( "popuphidden", () => { click(dismissErrorButton, "Click the dismiss-error button"); @@ -919,9 +1051,9 @@ class FullPageTranslationsTestUtils { */ static async clickRestoreButton() { logAction(); - const { restoreButton } = TranslationsPanel.elements; + const { restoreButton } = FullPageTranslationsPanel.elements; assertVisibility({ visible: { restoreButton } }); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( "popuphidden", () => { click(restoreButton, "Click the restore-page button"); @@ -957,9 +1089,9 @@ class FullPageTranslationsTestUtils { pivotTranslation = false, } = {}) { logAction(); - const { translateButton } = TranslationsPanel.elements; + const { translateButton } = FullPageTranslationsPanel.elements; assertVisibility({ visible: { translateButton } }); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( "popuphidden", () => { click(translateButton); @@ -986,25 +1118,23 @@ class FullPageTranslationsTestUtils { * @param {boolean} config.openWithKeyboard * - Open the panel by synthesizing the keyboard. If false, synthesizes the mouse. */ - static async openTranslationsPanel({ + static async openPanel({ onOpenPanel = null, openFromAppMenu = false, openWithKeyboard = false, }) { logAction(); - await closeTranslationsPanelIfOpen(); + await closeAllOpenPanelsAndMenus(); if (openFromAppMenu) { - await FullPageTranslationsTestUtils.#openTranslationsPanelViaAppMenu({ + await FullPageTranslationsTestUtils.#openPanelViaAppMenu({ onOpenPanel, openWithKeyboard, }); } else { - await FullPageTranslationsTestUtils.#openTranslationsPanelViaTranslationsButton( - { - onOpenPanel, - openWithKeyboard, - } - ); + await FullPageTranslationsTestUtils.#openPanelViaTranslationsButton({ + onOpenPanel, + openWithKeyboard, + }); } } @@ -1017,7 +1147,7 @@ class FullPageTranslationsTestUtils { * @param {boolean} config.openWithKeyboard * - Open the panel by synthesizing the keyboard. If false, synthesizes the mouse. */ - static async #openTranslationsPanelViaAppMenu({ + static async #openPanelViaAppMenu({ onOpenPanel = null, openWithKeyboard = false, }) { @@ -1038,7 +1168,7 @@ class FullPageTranslationsTestUtils { "The app-menu translate button should be enabled" ); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( "popupshown", () => { if (openWithKeyboard) { @@ -1060,7 +1190,7 @@ class FullPageTranslationsTestUtils { * @param {boolean} config.openWithKeyboard * - Open the panel by synthesizing the keyboard. If false, synthesizes the mouse. */ - static async #openTranslationsPanelViaTranslationsButton({ + static async #openPanelViaTranslationsButton({ onOpenPanel = null, openWithKeyboard = false, }) { @@ -1070,7 +1200,7 @@ class FullPageTranslationsTestUtils { { button: true }, "The translations button is visible." ); - await FullPageTranslationsTestUtils.waitForTranslationsPopupEvent( + await FullPageTranslationsTestUtils.waitForPanelPopupEvent( "popupshown", () => { if (openWithKeyboard) { @@ -1091,7 +1221,7 @@ class FullPageTranslationsTestUtils { logAction(); const gearIcons = getAllByL10nId("translations-panel-settings-button"); for (const gearIcon of gearIcons) { - if (gearIcon.hidden) { + if (BrowserTestUtils.isHidden(gearIcon)) { continue; } click(gearIcon, "Open the settings menu"); @@ -1114,7 +1244,7 @@ class FullPageTranslationsTestUtils { */ static switchSelectedFromLanguage(langTag) { logAction(langTag); - const { fromMenuList } = TranslationsPanel.elements; + const { fromMenuList } = FullPageTranslationsPanel.elements; fromMenuList.value = langTag; fromMenuList.dispatchEvent(new Event("command")); } @@ -1126,7 +1256,7 @@ class FullPageTranslationsTestUtils { */ static switchSelectedToLanguage(langTag) { logAction(langTag); - const { toMenuList } = TranslationsPanel.elements; + const { toMenuList } = FullPageTranslationsPanel.elements; toMenuList.value = langTag; toMenuList.dispatchEvent(new Event("command")); } @@ -1142,26 +1272,19 @@ class FullPageTranslationsTestUtils { * An optional assertion to be made immediately after the event occurs. * @returns {Promise} */ - static async waitForTranslationsPopupEvent( + static async waitForPanelPopupEvent( eventName, callback, postEventAssertion = null ) { // De-lazify the panel elements. - TranslationsPanel.elements; - const panel = document.getElementById("translations-panel"); - if (!panel) { - throw new Error("Unable to find the translations panel element."); - } - const promise = BrowserTestUtils.waitForEvent(panel, eventName); - await callback(); - info("Waiting for the translations panel popup to be shown"); - await promise; - if (postEventAssertion) { - postEventAssertion(); - } - // Wait a single tick on the event loop. - await new Promise(resolve => setTimeout(resolve, 0)); + FullPageTranslationsPanel.elements; + await SharedTranslationsTestUtils._waitForPopupEvent( + "full-page-translations-panel", + eventName, + callback, + postEventAssertion + ); } } @@ -1210,8 +1333,7 @@ class SelectTranslationsTestUtils { info(message); } - await closeTranslationsPanelIfOpen(); - await closeContextMenuIfOpen(); + await closeAllOpenPanelsAndMenus(); await SelectTranslationsTestUtils.openContextMenu(runInPage, { selectFirstParagraph, @@ -1274,8 +1396,106 @@ class SelectTranslationsTestUtils { ); } } + } + + /** + * Asserts that for each provided expectation, the visible state of the corresponding + * element in FullPageTranslationsPanel.elements both exists and matches the visibility expectation. + * + * @param {object} expectations + * A list of expectations for the visibility of any subset of SelectTranslationsPanel.elements + */ + static #assertPanelElementVisibility(expectations = {}) { + SharedTranslationsTestUtils._assertPanelElementVisibility( + SelectTranslationsPanel.elements, + { + betaIcon: false, + copyButton: false, + doneButton: false, + fromLabel: false, + fromMenuList: false, + header: false, + textArea: false, + toLabel: false, + toMenuList: false, + translateFullPageButton: false, + // Overwrite any of the above defaults with the passed in expectations. + ...expectations, + } + ); + } - await closeContextMenuIfOpen(); + /** + * Asserts that the mainViewId of the panel matches the given string. + * + * @param {string} expectedId + */ + static #assertPanelMainViewId(expectedId) { + SharedTranslationsTestUtils._assertPanelMainViewId( + SelectTranslationsPanel, + expectedId + ); + } + + /** + * Asserts that panel element visibility matches the default panel view. + */ + static assertPanelViewDefault() { + info("Checking that the select-translations panel shows the default view"); + SelectTranslationsTestUtils.#assertPanelMainViewId( + "select-translations-panel-view-default" + ); + SelectTranslationsTestUtils.#assertPanelElementVisibility({ + betaIcon: true, + fromLabel: true, + fromMenuList: true, + header: true, + textArea: true, + toLabel: true, + toMenuList: true, + copyButton: true, + doneButton: true, + translateFullPageButton: true, + }); + } + + /** + * Asserts that the selected from-language matches the provided language tag. + * + * @param {string} langTag - A BCP-47 language tag. + */ + static assertSelectedFromLanguage({ langTag, l10nId }) { + SharedTranslationsTestUtils._assertSelectedFromLanguage( + SelectTranslationsPanel, + { langTag, l10nId } + ); + } + + /** + * Asserts that the selected to-language matches the provided language tag. + * + * @param {string} langTag - A BCP-47 language tag. + */ + static assertSelectedToLanguage({ langTag, l10nId }) { + SharedTranslationsTestUtils._assertSelectedToLanguage( + SelectTranslationsPanel, + { langTag, l10nId } + ); + } + + /** + * Simulates clicking the done button and waits for the panel to close. + */ + static async clickDoneButton() { + logAction(); + const { doneButton } = SelectTranslationsPanel.elements; + assertVisibility({ visible: { doneButton } }); + await SelectTranslationsTestUtils.waitForPanelPopupEvent( + "popuphidden", + () => { + click(doneButton, "Clicking the done button"); + } + ); } /** @@ -1325,38 +1545,62 @@ class SelectTranslationsTestUtils { } if (openAtFirstParagraph === true) { - await runInPage(async TranslationsTest => { - const { getFirstParagraph } = TranslationsTest.getSelectors(); - const paragraph = getFirstParagraph(); - await TranslationsTest.rightClickContentElement(paragraph); - }); + await SharedTranslationsTestUtils._waitForPopupEvent( + "contentAreaContextMenu", + "popupshown", + async () => { + await runInPage(async TranslationsTest => { + const { getFirstParagraph } = TranslationsTest.getSelectors(); + const paragraph = getFirstParagraph(); + await TranslationsTest.rightClickContentElement(paragraph); + }); + } + ); return; } if (openAtSpanishParagraph === true) { - await runInPage(async TranslationsTest => { - const { getSpanishParagraph } = TranslationsTest.getSelectors(); - const paragraph = getSpanishParagraph(); - await TranslationsTest.rightClickContentElement(paragraph); - }); + await SharedTranslationsTestUtils._waitForPopupEvent( + "contentAreaContextMenu", + "popupshown", + async () => { + await runInPage(async TranslationsTest => { + const { getSpanishParagraph } = TranslationsTest.getSelectors(); + const paragraph = getSpanishParagraph(); + await TranslationsTest.rightClickContentElement(paragraph); + }); + } + ); return; } if (openAtEnglishHyperlink === true) { - await runInPage(async TranslationsTest => { - const { getEnglishHyperlink } = TranslationsTest.getSelectors(); - const hyperlink = getEnglishHyperlink(); - await TranslationsTest.rightClickContentElement(hyperlink); - }); + await SharedTranslationsTestUtils._waitForPopupEvent( + "contentAreaContextMenu", + "popupshown", + async () => { + await runInPage(async TranslationsTest => { + const { getEnglishHyperlink } = TranslationsTest.getSelectors(); + const hyperlink = getEnglishHyperlink(); + await TranslationsTest.rightClickContentElement(hyperlink); + }); + } + ); return; } if (openAtSpanishHyperlink === true) { - await runInPage(async TranslationsTest => { - const { getSpanishHyperlink } = TranslationsTest.getSelectors(); - const hyperlink = getSpanishHyperlink(); - await TranslationsTest.rightClickContentElement(hyperlink); - }); + await SharedTranslationsTestUtils._waitForPopupEvent( + "contentAreaContextMenu", + "popupshown", + async () => { + await runInPage(async TranslationsTest => { + const { getSpanishHyperlink } = TranslationsTest.getSelectors(); + const hyperlink = getSpanishHyperlink(); + await TranslationsTest.rightClickContentElement(hyperlink); + }); + } + ); return; } @@ -1364,6 +1608,96 @@ class SelectTranslationsTestUtils { "openContextMenu() was not provided a declaration for which element to open the menu at." ); } + + /** + * Opens the Select Translations panel via the context menu based on specified options. + * + * @param {Function} runInPage - A content-exposed function to run within the context of the page. + * @param {object} options - Options for selecting paragraphs and opening the context menu. + * @param {boolean} options.selectFirstParagraph - Selects the first paragraph before opening the context menu. + * @param {boolean} options.selectSpanishParagraph - Selects the Spanish paragraph before opening the context menu. + * This is only available in SPANISH_TEST_PAGE. + * @param {string} options.expectedTargetLanguage - The target language for translation. + * @param {boolean} options.openAtFirstParagraph - Opens the context menu at the first paragraph. + * @param {boolean} options.openAtSpanishParagraph - Opens at the Spanish paragraph. + * This is only available in SPANISH_TEST_PAGE. + * @param {boolean} options.openAtEnglishHyperlink - Opens at the English hyperlink. + * This is only available in SPANISH_TEST_PAGE. + * @param {boolean} options.openAtSpanishHyperlink - Opens at the Spanish hyperlink. + * This is only available in SPANISH_TEST_PAGE. + * @param {Function|null} [options.onOpenPanel=null] - An optional callback function to execute after the panel opens. + * @param {string|null} [message=null] - An optional message to log to info. + * @throws Throws an error if the context menu could not be opened with the provided options. + * @returns {Promise} + */ + static async openPanel( + runInPage, + { + selectFirstParagraph, + selectSpanishParagraph, + expectedTargetLanguage, + openAtFirstParagraph, + openAtSpanishParagraph, + openAtEnglishHyperlink, + openAtSpanishHyperlink, + onOpenPanel, + }, + message + ) { + logAction(); + + if (message) { + info(message); + } + + await SelectTranslationsTestUtils.assertContextMenuTranslateSelectionItem( + runInPage, + { + selectFirstParagraph, + selectSpanishParagraph, + expectedTargetLanguage, + openAtFirstParagraph, + openAtSpanishParagraph, + openAtEnglishHyperlink, + openAtSpanishHyperlink, + }, + message + ); + + const menuItem = getById("context-translate-selection"); + + await SelectTranslationsTestUtils.waitForPanelPopupEvent( + "popupshown", + () => click(menuItem), + onOpenPanel + ); + } + + /** + * 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 + * @param {Function} postEventAssertion + * An optional assertion to be made immediately after the event occurs. + * @returns {Promise} + */ + static async waitForPanelPopupEvent( + eventName, + callback, + postEventAssertion = null + ) { + // De-lazify the panel elements. + SelectTranslationsPanel.elements; + await SharedTranslationsTestUtils._waitForPopupEvent( + "select-translations-panel", + eventName, + callback, + postEventAssertion + ); + } } class TranslationsSettingsTestUtils { -- cgit v1.2.3