summaryrefslogtreecommitdiffstats
path: root/browser/components/translations/tests/browser
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/translations/tests/browser')
-rw-r--r--browser/components/translations/tests/browser/browser.ini19
-rw-r--r--browser/components/translations/tests/browser/browser_manage_languages.js195
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_always_translate_language.js413
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_basics.js94
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_beta_langs.js66
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_button.js80
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_cancel.js32
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_gear.js42
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_never_translate_language.js343
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_never_translate_site.js432
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_retry.js80
-rw-r--r--browser/components/translations/tests/browser/browser_translations_panel_switch_languages.js97
-rw-r--r--browser/components/translations/tests/browser/browser_translations_telemetry_open_panel.js73
-rw-r--r--browser/components/translations/tests/browser/browser_translations_telemetry_translation_failure.js195
-rw-r--r--browser/components/translations/tests/browser/browser_translations_telemetry_translation_request.js173
-rw-r--r--browser/components/translations/tests/browser/head.js348
16 files changed, 2682 insertions, 0 deletions
diff --git a/browser/components/translations/tests/browser/browser.ini b/browser/components/translations/tests/browser/browser.ini
new file mode 100644
index 0000000000..fd67597972
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser.ini
@@ -0,0 +1,19 @@
+[DEFAULT]
+support-files =
+ head.js
+ !/toolkit/components/translations/tests/browser/shared-head.js
+ !/toolkit/components/translations/tests/browser/translations-test.mjs
+[browser_manage_languages.js]
+[browser_translations_panel_always_translate_language.js]
+[browser_translations_panel_basics.js]
+[browser_translations_panel_beta_langs.js]
+[browser_translations_panel_button.js]
+[browser_translations_panel_cancel.js]
+[browser_translations_panel_gear.js]
+[browser_translations_panel_never_translate_language.js]
+[browser_translations_panel_never_translate_site.js]
+[browser_translations_panel_retry.js]
+[browser_translations_panel_switch_languages.js]
+[browser_translations_telemetry_open_panel.js]
+[browser_translations_telemetry_translation_failure.js]
+[browser_translations_telemetry_translation_request.js]
diff --git a/browser/components/translations/tests/browser/browser_manage_languages.js b/browser/components/translations/tests/browser/browser_manage_languages.js
new file mode 100644
index 0000000000..651029ad86
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_manage_languages.js
@@ -0,0 +1,195 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const frenchModels = [
+ "lex.50.50.enfr.s2t.bin",
+ "lex.50.50.fren.s2t.bin",
+ "model.enfr.intgemm.alphas.bin",
+ "model.fren.intgemm.alphas.bin",
+ "vocab.enfr.spm",
+ "vocab.fren.spm",
+];
+
+add_task(async function test_about_preferences_manage_languages() {
+ const {
+ cleanup,
+ remoteClients,
+ elements: {
+ downloadAllLabel,
+ downloadAll,
+ deleteAll,
+ frenchLabel,
+ frenchDownload,
+ frenchDelete,
+ spanishLabel,
+ spanishDownload,
+ spanishDelete,
+ },
+ } = await setupAboutPreferences([
+ { fromLang: "en", toLang: "fr" },
+ { fromLang: "fr", toLang: "en" },
+ { fromLang: "en", toLang: "es" },
+ { fromLang: "es", toLang: "en" },
+ ]);
+
+ is(
+ downloadAllLabel.getAttribute("data-l10n-id"),
+ "translations-manage-all-language",
+ "The first row is all of the languages."
+ );
+ is(frenchLabel.textContent, "French", "There is a French row.");
+ is(spanishLabel.textContent, "Spanish", "There is a Spanish row.");
+
+ await assertVisibility({
+ message: "Everything starts out as available to download",
+ visible: { downloadAll, frenchDownload, spanishDownload },
+ hidden: { deleteAll, frenchDelete, spanishDelete },
+ });
+
+ click(frenchDownload, "Downloading French");
+
+ Assert.deepEqual(
+ await remoteClients.translationModels.resolvePendingDownloads(
+ frenchModels.length
+ ),
+ frenchModels,
+ "French models were downloaded."
+ );
+
+ await assertVisibility({
+ message: "French can now be deleted, and delete all is available.",
+ visible: { downloadAll, deleteAll, frenchDelete, spanishDownload },
+ hidden: { frenchDownload, spanishDelete },
+ });
+
+ click(frenchDelete, "Deleting French");
+
+ await assertVisibility({
+ message: "Everything can be downloaded.",
+ visible: { downloadAll, frenchDownload, spanishDownload },
+ hidden: { deleteAll, frenchDelete, spanishDelete },
+ });
+
+ click(downloadAll, "Downloading all languages.");
+
+ const allModels = [
+ "lex.50.50.enes.s2t.bin",
+ "lex.50.50.enfr.s2t.bin",
+ "lex.50.50.esen.s2t.bin",
+ "lex.50.50.fren.s2t.bin",
+ "model.enes.intgemm.alphas.bin",
+ "model.enfr.intgemm.alphas.bin",
+ "model.esen.intgemm.alphas.bin",
+ "model.fren.intgemm.alphas.bin",
+ "vocab.enes.spm",
+ "vocab.enfr.spm",
+ "vocab.esen.spm",
+ "vocab.fren.spm",
+ ];
+ Assert.deepEqual(
+ await remoteClients.translationModels.resolvePendingDownloads(
+ allModels.length
+ ),
+ allModels,
+ "All models were downloaded."
+ );
+ Assert.deepEqual(
+ await remoteClients.languageIdModels.resolvePendingDownloads(1),
+ ["lid.176.ftz"],
+ "Language ID model was downloaded."
+ );
+ Assert.deepEqual(
+ await remoteClients.translationsWasm.resolvePendingDownloads(2),
+ ["bergamot-translator", "fasttext-wasm"],
+ "Wasm was downloaded."
+ );
+
+ await assertVisibility({
+ message: "Everything can be deleted.",
+ visible: { deleteAll, frenchDelete, spanishDelete },
+ hidden: { downloadAll, frenchDownload, spanishDownload },
+ });
+
+ click(deleteAll, "Deleting all languages.");
+
+ await assertVisibility({
+ message: "Everything can be downloaded again",
+ visible: { downloadAll, frenchDownload, spanishDownload },
+ hidden: { deleteAll, frenchDelete, spanishDelete },
+ });
+
+ click(frenchDownload, "Downloading French.");
+ click(spanishDownload, "Downloading Spanish.");
+
+ Assert.deepEqual(
+ await remoteClients.translationModels.resolvePendingDownloads(
+ allModels.length
+ ),
+ allModels,
+ "All models were downloaded again."
+ );
+
+ remoteClients.translationsWasm.assertNoNewDownloads();
+ remoteClients.languageIdModels.assertNoNewDownloads();
+
+ await assertVisibility({
+ message: "Everything is downloaded again.",
+ visible: { deleteAll, frenchDelete, spanishDelete },
+ hidden: { downloadAll, frenchDownload, spanishDownload },
+ });
+
+ return cleanup();
+});
+
+add_task(async function test_about_preferences_download_reject() {
+ const {
+ cleanup,
+ remoteClients,
+ elements: { document, frenchDownload },
+ } = await setupAboutPreferences([
+ { fromLang: "en", toLang: "fr" },
+ { fromLang: "fr", toLang: "en" },
+ { fromLang: "en", toLang: "es" },
+ { fromLang: "es", toLang: "en" },
+ ]);
+
+ click(frenchDownload, "Downloading French");
+
+ is(
+ maybeGetByL10nId("translations-manage-error-download", document),
+ null,
+ "No error messages are present."
+ );
+
+ const errors = await captureTranslationsError(() =>
+ remoteClients.translationModels.rejectPendingDownloads(frenchModels.length)
+ );
+
+ ok(
+ !!errors.length,
+ `The errors for download should have been reported, found ${errors.length} errors`
+ );
+ for (const { error } of errors) {
+ is(
+ error?.message,
+ "Failed to download file.",
+ "The error reported was a download error."
+ );
+ }
+
+ await TestUtils.waitForCondition(
+ () => maybeGetByL10nId("translations-manage-error-download", document),
+ "The error message is now visible."
+ );
+
+ click(frenchDownload, "Attempting to download French again", document);
+ is(
+ maybeGetByL10nId("translations-manage-error-download", document),
+ null,
+ "The error message is hidden again."
+ );
+
+ return cleanup();
+});
diff --git a/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language.js b/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language.js
new file mode 100644
index 0000000000..4bc2c7dc15
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_always_translate_language.js
@@ -0,0 +1,413 @@
+/* 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,
+ prefs: [["browser.translations.alwaysTranslateLanguages", "pl,fr"]],
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The translations button is visible."
+ );
+
+ info(
+ 'The document language "es" is not in the alwaysTranslateLanguages pref, ' +
+ "so the page should be untranslated, in its original form"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ info(
+ "Simulate clicking always-translate-language in the settings menu, " +
+ "adding the document language to the alwaysTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsAlwaysTranslateLanguage("es", false);
+ await toggleAlwaysTranslateLanguage();
+ await assertIsAlwaysTranslateLanguage("es", true);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ info(
+ "The page should now be automatically translated because the document language " +
+ "should be added to the always-translate pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is translated automatically",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ info("Navigate to a different Spanish page");
+ await navigate(SPANISH_PAGE_URL_DOT_ORG);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ info(
+ "The page should now be automatically translated because the document language " +
+ "should be added to the always-translate pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is translated automatically",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ info(
+ "Simulate clicking always-translate-language in the settings menu " +
+ "removing the document language from the alwaysTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsAlwaysTranslateLanguage("es", true);
+ await toggleAlwaysTranslateLanguage();
+ await assertIsAlwaysTranslateLanguage("es", false);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "Only the button appears"
+ );
+
+ info(
+ "The page should no longer automatically translated because the document language " +
+ "should be removed from the always-translate pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await cleanup();
+});
+
+/**
+ * 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,
+ prefs: [["browser.translations.alwaysTranslateLanguages", "pl,fr"]],
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button is available."
+ );
+
+ info(
+ 'The document language "es" is not in the alwaysTranslateLanguages pref, ' +
+ "so the page should be untranslated, in its original form"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-button"),
+ "Start translating by clicking the translate button."
+ );
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ info(
+ "Simulate clicking always-translate-language in the settings menu, " +
+ "adding the document language to the alwaysTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsAlwaysTranslateLanguage("es", false);
+ await toggleAlwaysTranslateLanguage();
+ await assertIsAlwaysTranslateLanguage("es", true);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The continues to present the locale without pending downloads."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ info(
+ "Simulate clicking always-translate-language in the settings menu " +
+ "removing the document language from the alwaysTranslateLanguages pref"
+ );
+ await assertIsAlwaysTranslateLanguage("es", true);
+ await toggleAlwaysTranslateLanguage();
+ await assertIsAlwaysTranslateLanguage("es", false);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "Only the button appears"
+ );
+
+ info(
+ "The page should no longer automatically translated because the document language " +
+ "should be removed from the always-translate pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await cleanup();
+ }
+);
+
+/**
+ * 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,
+ prefs: [["browser.translations.alwaysTranslateLanguages", "pl,fr"]],
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The translations button is visible."
+ );
+
+ info(
+ 'The document language "es" is not in the alwaysTranslateLanguages pref, ' +
+ "so the page should be untranslated, in its original form"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ info(
+ "Simulate clicking always-translate-language in the settings menu, " +
+ "adding the document language to the alwaysTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsAlwaysTranslateLanguage("es", false);
+ await toggleAlwaysTranslateLanguage();
+ await assertIsAlwaysTranslateLanguage("es", true);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ info(
+ "The page should now be automatically translated because the document language " +
+ "should be added to the always-translate pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is translated automatically",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ await navigate(
+ SPANISH_PAGE_URL_DOT_ORG,
+ "Navigate to a different Spanish page"
+ );
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ info(
+ "The page should now be automatically translated because the document language " +
+ "should be added to the always-translate pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is translated automatically",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Re-opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-restore-button"),
+ "Click the restore language button."
+ );
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button is reverted to have an icon."
+ );
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is restored to Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ info(
+ "Simulate clicking always-translate-language in the settings menu, " +
+ "removing the document language to the alwaysTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsAlwaysTranslateLanguage("es", true);
+ await toggleAlwaysTranslateLanguage();
+ await assertIsAlwaysTranslateLanguage("es", false);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button shows only the icon."
+ );
+
+ await navigate(SPANISH_PAGE_URL_DOT_ORG, "Reload the page");
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button shows only the icon."
+ );
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is restored to Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ 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
new file mode 100644
index 0000000000..df2b0da4e5
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_basics.js
@@ -0,0 +1,94 @@
+/* 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 assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button is available."
+ );
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-button"),
+ "Start translating by clicking the translate button."
+ );
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Re-opening the popup");
+ });
+
+ ok(
+ getByL10nId("translations-panel-translate-button").disabled,
+ "The translate button is disabled when re-opening."
+ );
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-restore-button"),
+ "Click the restore language button."
+ );
+ });
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is restored to Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await 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_beta_langs.js b/browser/components/translations/tests/browser/browser_translations_panel_beta_langs.js
new file mode 100644
index 0000000000..f44f2ad9e8
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_beta_langs.js
@@ -0,0 +1,66 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Tests that languages are displayed correctly as being in beta or not.
+ */
+add_task(async function test_translations_panel_display_beta_languages() {
+ const { cleanup } = await loadTestPage({
+ page: SPANISH_PAGE_URL,
+ languagePairs: LANGUAGE_PAIRS,
+ });
+
+ function assertBetaDisplay(selectElement) {
+ const betaL10nId = "translations-panel-displayname-beta";
+ const options = selectElement.querySelectorAll("menuitem");
+ if (options.length === 0) {
+ throw new Error("Could not find the menuitems.");
+ }
+
+ for (const option of options) {
+ for (const languagePair of LANGUAGE_PAIRS) {
+ if (
+ languagePair.fromLang === option.value ||
+ languagePair.toLang === option.value
+ ) {
+ if (option.getAttribute("data-l10n-id") === betaL10nId) {
+ is(
+ languagePair.isBeta,
+ true,
+ `Since data-l10n-id was ${betaL10nId} for ${option.value}, then it must be part of a beta language pair, but it was not.`
+ );
+ }
+ if (!languagePair.isBeta) {
+ is(
+ option.getAttribute("data-l10n-id") === betaL10nId,
+ false,
+ `Since the languagePair is non-beta, the language option ${option.value} should not have a data-l10-id of ${betaL10nId}, but it does.`
+ );
+ }
+ }
+ }
+ }
+ }
+
+ const { button } = await assertTranslationsButton(
+ { button: true },
+ "The button is available."
+ );
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ assertBetaDisplay(document.getElementById("translations-panel-to"));
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-cancel"),
+ "Click the cancel button."
+ );
+ });
+
+ 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
new file mode 100644
index 0000000000..57e09260fb
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_button.js
@@ -0,0 +1,80 @@
+/* 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() {
+ info("Start at a page in Spanish.");
+ const { cleanup } = await loadTestPage({
+ page: SPANISH_PAGE_URL,
+ languagePairs: LANGUAGE_PAIRS,
+ });
+
+ await assertTranslationsButton(
+ { button: true },
+ "The button should be visible since the page can be translated from Spanish."
+ );
+
+ navigate(ENGLISH_PAGE_URL, "Navigate to an English page.");
+
+ await assertTranslationsButton(
+ { button: false },
+ "The button should be invisible since the page is in English."
+ );
+
+ navigate(SPANISH_PAGE_URL, "Navigate back to a Spanish page.");
+
+ await 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() {
+ info("Start at a page in Spanish.");
+
+ const { cleanup, tab: spanishTab } = await loadTestPage({
+ page: SPANISH_PAGE_URL,
+ languagePairs: LANGUAGE_PAIRS,
+ });
+
+ await 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 assertTranslationsButton(
+ { button: false },
+ "The button should be invisible since the tab is in English."
+ );
+
+ await switchTab(spanishTab);
+
+ await assertTranslationsButton(
+ { button: true },
+ "The button should be visible again since the page is in Spanish."
+ );
+
+ await switchTab(englishTab);
+
+ await 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
new file mode 100644
index 0000000000..b9bf532d96
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_cancel.js
@@ -0,0 +1,32 @@
+/* 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,
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true },
+ "The button is available."
+ );
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-cancel"),
+ "Click the cancel button."
+ );
+ });
+
+ 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
new file mode 100644
index 0000000000..46838accb4
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_gear.js
@@ -0,0 +1,42 @@
+/* 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,
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true },
+ "The button is available."
+ );
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ const gearIcon = getByL10nId("translations-panel-settings-button");
+ click(gearIcon, "Open the preferences menu");
+
+ const manageLanguages = getByL10nId(
+ "translations-panel-settings-manage-languages"
+ );
+ info("Choose to manage the languages.");
+ manageLanguages.doCommand();
+
+ await TestUtils.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
new file mode 100644
index 0000000000..c85443f457
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_never_translate_language.js
@@ -0,0 +1,343 @@
+/* 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,
+ prefs: [["browser.translations.neverTranslateLanguages", "pl,fr"]],
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The translations button is visible."
+ );
+
+ info(
+ 'The document language "es" is not in the neverTranslateLanguages pref, ' +
+ "so the page should be untranslated, in its original form."
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ info(
+ "Simulate clicking never-translate-language in the settings menu, " +
+ "adding the document language from the neverTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsNeverTranslateLanguage("es", false);
+ await toggleNeverTranslateLanguage();
+ await assertIsNeverTranslateLanguage("es", true);
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info(
+ "The page should still be in its original, untranslated form because " +
+ "the document language is in the neverTranslateLanguages pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(SPANISH_PAGE_URL, "Reload the page");
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info(
+ "The page should still be in its original, untranslated form because " +
+ "the document language is in the neverTranslateLanguages pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(
+ SPANISH_PAGE_URL_DOT_ORG,
+ "Navigate to a different Spanish page"
+ );
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info(
+ "The page should still be in its original, untranslated form because " +
+ "the document language is in the neverTranslateLanguages pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ 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,
+ prefs: [["browser.translations.neverTranslateLanguages", "pl,fr"]],
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button is available."
+ );
+
+ info(
+ 'The document language "es" is not in the alwaysTranslateLanguages pref, ' +
+ "so the page should be untranslated, in its original form"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-button"),
+ "Start translating by clicking the translate button."
+ );
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ info(
+ "Simulate clicking never-translate-language in the settings menu, " +
+ "adding the document language from the neverTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsNeverTranslateLanguage("es", false);
+ await toggleNeverTranslateLanguage();
+ await assertIsNeverTranslateLanguage("es", true);
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info(
+ "The page should still be in its original, untranslated form because " +
+ "the document language is in the neverTranslateLanguages pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(SPANISH_PAGE_URL, "Reload the page");
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info(
+ "The page should still be in its original, untranslated form because " +
+ "the document language is in the neverTranslateLanguages pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ 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,
+ prefs: [
+ ["browser.translations.alwaysTranslateLanguages", "uk,it"],
+ ["browser.translations.neverTranslateLanguages", "pl,fr"],
+ ],
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button is available."
+ );
+
+ info(
+ "Simulate clicking always-translate-language in the settings menu, " +
+ "adding the document language to the alwaysTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsAlwaysTranslateLanguage("es", false);
+ await assertIsNeverTranslateLanguage("es", false);
+
+ await toggleAlwaysTranslateLanguage();
+
+ await assertIsAlwaysTranslateLanguage("es", true);
+ await assertIsNeverTranslateLanguage("es", false);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ info(
+ "Simulate clicking never-translate-language in the settings menu, " +
+ "adding the document language from the neverTranslateLanguages pref " +
+ "and removing it from the alwaysTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsAlwaysTranslateLanguage("es", true);
+ await assertIsNeverTranslateLanguage("es", false);
+
+ await toggleNeverTranslateLanguage();
+
+ await assertIsAlwaysTranslateLanguage("es", false);
+ await assertIsNeverTranslateLanguage("es", true);
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info(
+ "The page should still be in its original, untranslated form because " +
+ "the document language is in the neverTranslateLanguages pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(SPANISH_PAGE_URL, "Reload the page");
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info(
+ "The page should still be in its original, untranslated form because " +
+ "the document language is in the neverTranslateLanguages pref"
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ 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
new file mode 100644
index 0000000000..b54b5a4a2c
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_never_translate_site.js
@@ -0,0 +1,432 @@
+/* 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,
+ permissionsUrls: [SPANISH_PAGE_URL],
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The translations button is visible."
+ );
+
+ info(
+ "Translations permissions are currently allowed for this test page " +
+ "and the page should be untranslated, in its original form."
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ info(
+ "Simulate clicking never-translate-site in the settings menu, " +
+ "denying translations permissions for this content window principal"
+ );
+ await openSettingsMenu();
+
+ await assertIsNeverTranslateSite(SPANISH_PAGE_URL, false);
+ await toggleNeverTranslateSite();
+ await assertIsNeverTranslateSite(SPANISH_PAGE_URL, true);
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(SPANISH_PAGE_URL, "Reload the page");
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(
+ SPANISH_PAGE_URL_2,
+ "Navigate to a Spanish page with the same content principal"
+ );
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible, because this content principal is denied"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(
+ SPANISH_PAGE_URL_DOT_ORG,
+ "Navigate to a Spanish page with a different content principal"
+ );
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be visible, because this content principal " +
+ "has not been denied translations permissions"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ 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,
+ permissionsUrls: [SPANISH_PAGE_URL],
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The translations button is visible."
+ );
+
+ info(
+ "Translations permissions are currently allowed for this test page " +
+ "and the page should be untranslated, in its original form."
+ );
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-button"),
+ "Start translating by clicking the translate button."
+ );
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ info(
+ "Simulate clicking never-translate-site in the settings menu, " +
+ "denying translations permissions for this content window principal"
+ );
+ await openSettingsMenu();
+
+ await assertIsNeverTranslateSite(SPANISH_PAGE_URL, false);
+ await toggleNeverTranslateSite();
+ await assertIsNeverTranslateSite(SPANISH_PAGE_URL, true);
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(SPANISH_PAGE_URL, "Reload the page");
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(
+ SPANISH_PAGE_URL_2,
+ "Navigate to a Spanish page with the same content principal"
+ );
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible, because this content principal is denied"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(
+ SPANISH_PAGE_URL_DOT_ORG,
+ "Navigate to a Spanish page with a different content principal"
+ );
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be visible, because this content principal " +
+ "has not been denied translations permissions"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ 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,
+ prefs: [["browser.translations.alwaysTranslateLanguages", "uk,it"]],
+ permissionsUrls: [SPANISH_PAGE_URL],
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button is available."
+ );
+
+ info(
+ "Simulate clicking always-translate-language in the settings menu, " +
+ "adding the document language to the alwaysTranslateLanguages pref"
+ );
+ await openSettingsMenu();
+
+ await assertIsAlwaysTranslateLanguage("es", false);
+ await assertIsNeverTranslateSite(SPANISH_PAGE_URL, false);
+
+ await toggleAlwaysTranslateLanguage();
+
+ await assertIsAlwaysTranslateLanguage("es", true);
+ await assertIsNeverTranslateSite(SPANISH_PAGE_URL, false);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ info(
+ "Simulate clicking never-translate-site in the settings menu, " +
+ "denying translations permissions for this content window principal"
+ );
+ await openSettingsMenu();
+
+ await assertIsAlwaysTranslateLanguage("es", true);
+ await assertIsNeverTranslateSite(SPANISH_PAGE_URL, false);
+
+ await toggleNeverTranslateSite();
+
+ await assertIsAlwaysTranslateLanguage("es", true);
+ await assertIsNeverTranslateSite(SPANISH_PAGE_URL, true);
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(SPANISH_PAGE_URL, "Reload the page");
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(
+ SPANISH_PAGE_URL_2,
+ "Navigate to a Spanish page with the same content principal"
+ );
+
+ await assertTranslationsButton(
+ { button: false },
+ "The translations button should be invisible, because this content principal is denied"
+ );
+
+ info("The page should still be in its original, untranslated form");
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await navigate(
+ SPANISH_PAGE_URL_DOT_ORG,
+ "Navigate to a Spanish page with a different content principal"
+ );
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ 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
new file mode 100644
index 0000000000..e9b3f93257
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_retry.js
@@ -0,0 +1,80 @@
+/* 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,
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true },
+ "The button is available."
+ );
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-button"),
+ "Start translating by clicking the translate button."
+ );
+ });
+
+ await resolveDownloads(1);
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Re-opening the popup");
+ });
+
+ info('Switch to language to "fr"');
+ const toSelect = getById("translations-panel-to");
+ toSelect.value = "fr";
+ toSelect.dispatchEvent(new Event("command"));
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-button"),
+ "Re-translate the page by clicking the translate button."
+ );
+ });
+
+ // This is a pivot language which requires 2 models.
+ await resolveDownloads(2);
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated using the changed languages.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to fr, html]"
+ );
+ });
+
+ 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
new file mode 100644
index 0000000000..58bcb212d7
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_panel_switch_languages.js
@@ -0,0 +1,97 @@
+/* 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,
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true },
+ "The button is available."
+ );
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ const translateButton = getByL10nId("translations-panel-translate-button");
+ const fromSelect = getById("translations-panel-from");
+ const toSelect = getById("translations-panel-to");
+
+ ok(!translateButton.disabled, "The translate button starts as enabled");
+ is(fromSelect.value, "es", "The from select starts as Spanish");
+ is(toSelect.value, "en", "The to select starts as English");
+
+ info('Switch from language to "es"');
+ fromSelect.value = "en";
+ fromSelect.dispatchEvent(new Event("command"));
+
+ ok(
+ translateButton.disabled,
+ "The translate button is disabled when the languages are the same"
+ );
+
+ info('Switch from language back to "es"');
+ fromSelect.value = "es";
+ fromSelect.dispatchEvent(new Event("command"));
+
+ ok(
+ !translateButton.disabled,
+ "When the languages are different it can be translated"
+ );
+
+ info("Switch to language to nothing");
+ fromSelect.value = "";
+ fromSelect.dispatchEvent(new Event("command"));
+
+ ok(
+ translateButton.disabled,
+ "The translate button is disabled nothing is selected."
+ );
+
+ info('Switch from language to "en"');
+ fromSelect.value = "en";
+ fromSelect.dispatchEvent(new Event("command"));
+
+ info('Switch to language to "fr"');
+ toSelect.value = "fr";
+ toSelect.dispatchEvent(new Event("command"));
+
+ ok(!translateButton.disabled, "The translate button can now be used");
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ translateButton,
+ "Start translating by clicking the translate button."
+ );
+ });
+
+ await resolveDownloads(1);
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated using the changed languages.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [en to fr, html]"
+ );
+ });
+
+ 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
new file mode 100644
index 0000000000..41aa730863
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_telemetry_open_panel.js
@@ -0,0 +1,73 @@
+/* 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(
+ "OpenPanel",
+ Glean.translationsPanel.open,
+ {
+ expectedLength: 0,
+ }
+ );
+
+ const { button } = await assertTranslationsButton(
+ { button: true },
+ "The button is available."
+ );
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-cancel"),
+ "Click the cancel button."
+ );
+ });
+
+ await TestTranslationsTelemetry.assertEvent(
+ "OpenPanel",
+ Glean.translationsPanel.open,
+ {
+ expectedLength: 1,
+ finalValuePredicates: [
+ value => value.extra.opened_from === "translationsButton",
+ ],
+ }
+ );
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-cancel"),
+ "Click the cancel button."
+ );
+ });
+
+ await TestTranslationsTelemetry.assertEvent(
+ "OpenPanel",
+ Glean.translationsPanel.open,
+ {
+ expectedLength: 2,
+ allValuePredicates: [
+ value => value.extra.opened_from === "translationsButton",
+ ],
+ }
+ );
+
+ 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
new file mode 100644
index 0000000000..1268e6452b
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_telemetry_translation_failure.js
@@ -0,0 +1,195 @@
+/* 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() {
+ PromiseTestUtils.expectUncaughtRejection(
+ /Intentionally rejecting downloads./
+ );
+
+ const { cleanup, rejectDownloads, runInPage } = await loadTestPage({
+ page: SPANISH_PAGE_URL,
+ languagePairs: LANGUAGE_PAIRS,
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button is available."
+ );
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await TestTranslationsTelemetry.assertCounter(
+ "RequestCount",
+ Glean.translations.requestsCount,
+ 0
+ );
+ await TestTranslationsTelemetry.assertRate(
+ "ErrorRate",
+ Glean.translations.errorRate,
+ {
+ expectedNumerator: 0,
+ expectedDenominator: 0,
+ }
+ );
+ await TestTranslationsTelemetry.assertEvent(
+ "TranslationRequest",
+ Glean.translations.translationRequest,
+ {
+ expectedLength: 0,
+ }
+ );
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-button"),
+ "Start translating by clicking the translate button."
+ );
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await rejectDownloads(1);
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await TestTranslationsTelemetry.assertCounter(
+ "RequestCount",
+ Glean.translations.requestsCount,
+ 1
+ );
+ await TestTranslationsTelemetry.assertRate(
+ "ErrorRate",
+ Glean.translations.errorRate,
+ {
+ expectedNumerator: 1,
+ expectedDenominator: 1,
+ }
+ );
+ await TestTranslationsTelemetry.assertEvent(
+ "Error",
+ Glean.translations.error,
+ {
+ expectedLength: 1,
+ finalValuePredicates: [
+ value =>
+ value.extra.reason === "Error: Intentionally rejecting downloads.",
+ ],
+ }
+ );
+ await TestTranslationsTelemetry.assertEvent(
+ "TranslationRequest",
+ Glean.translations.translationRequest,
+ {
+ expectedLength: 1,
+ finalValuePredicates: [
+ value => value.extra.from_language === "es",
+ value => value.extra.to_language === "en",
+ value => value.extra.auto_translate === "false",
+ ],
+ }
+ );
+
+ await cleanup();
+ }
+);
+
+/**
+ * Tests the telemetry event for an automatic translation request failure.
+ */
+add_task(async function test_translations_telemetry_auto_translation_failure() {
+ PromiseTestUtils.expectUncaughtRejection(
+ /Intentionally rejecting downloads./
+ );
+
+ const { cleanup, rejectDownloads, runInPage } = await loadTestPage({
+ page: SPANISH_PAGE_URL,
+ languagePairs: LANGUAGE_PAIRS,
+ prefs: [["browser.translations.alwaysTranslateLanguages", "es"]],
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await rejectDownloads(1);
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await TestTranslationsTelemetry.assertCounter(
+ "RequestCount",
+ Glean.translations.requestsCount,
+ 1
+ );
+ await TestTranslationsTelemetry.assertRate(
+ "ErrorRate",
+ Glean.translations.errorRate,
+ {
+ expectedNumerator: 1,
+ expectedDenominator: 1,
+ }
+ );
+ await TestTranslationsTelemetry.assertEvent(
+ "Error",
+ Glean.translations.error,
+ {
+ expectedLength: 1,
+ finalValuePredicates: [
+ value =>
+ value.extra.reason === "Error: Intentionally rejecting downloads.",
+ ],
+ }
+ );
+ await TestTranslationsTelemetry.assertEvent(
+ "TranslationRequest",
+ Glean.translations.translationRequest,
+ {
+ expectedLength: 1,
+ finalValuePredicates: [
+ value => value.extra.from_language === "es",
+ value => value.extra.to_language === "en",
+ value => value.extra.auto_translate === "true",
+ ],
+ }
+ );
+
+ 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
new file mode 100644
index 0000000000..ce22615630
--- /dev/null
+++ b/browser/components/translations/tests/browser/browser_translations_telemetry_translation_request.js
@@ -0,0 +1,173 @@
+/* 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,
+ });
+
+ const { button } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: false, icon: true },
+ "The button is available."
+ );
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The page's H1 is in Spanish.",
+ getH1,
+ "Don Quijote de La Mancha"
+ );
+ });
+
+ await TestTranslationsTelemetry.assertCounter(
+ "RequestCount",
+ Glean.translations.requestsCount,
+ 0
+ );
+ await TestTranslationsTelemetry.assertRate(
+ "ErrorRate",
+ Glean.translations.errorRate,
+ {
+ expectedNumerator: 0,
+ expectedDenominator: 0,
+ }
+ );
+ await TestTranslationsTelemetry.assertEvent(
+ "TranslationRequest",
+ Glean.translations.translationRequest,
+ {
+ expectedLength: 0,
+ }
+ );
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ await waitForTranslationsPopupEvent("popuphidden", () => {
+ click(
+ getByL10nId("translations-panel-translate-button"),
+ "Start translating by clicking the translate button."
+ );
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ await TestTranslationsTelemetry.assertCounter(
+ "RequestCount",
+ Glean.translations.requestsCount,
+ 1
+ );
+ await TestTranslationsTelemetry.assertRate(
+ "ErrorRate",
+ Glean.translations.errorRate,
+ {
+ expectedNumerator: 0,
+ expectedDenominator: 1,
+ }
+ );
+ await TestTranslationsTelemetry.assertEvent(
+ "TranslationRequest",
+ Glean.translations.translationRequest,
+ {
+ expectedLength: 1,
+ finalValuePredicates: [
+ value => value.extra.from_language === "es",
+ value => value.extra.to_language === "en",
+ value => value.extra.auto_translate === "false",
+ ],
+ }
+ );
+
+ 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: SPANISH_PAGE_URL,
+ languagePairs: LANGUAGE_PAIRS,
+ prefs: [["browser.translations.alwaysTranslateLanguages", "es"]],
+ });
+
+ await assertTranslationsButton(
+ { button: true, circleArrows: true, locale: false, icon: true },
+ "The icon presents the loading indicator."
+ );
+
+ await resolveDownloads(1);
+
+ const { locale } = await assertTranslationsButton(
+ { button: true, circleArrows: false, locale: true, icon: true },
+ "The icon presents the locale."
+ );
+
+ is(locale.innerText, "en", "The English language tag is shown.");
+
+ await runInPage(async TranslationsTest => {
+ const { getH1 } = TranslationsTest.getSelectors();
+ await TranslationsTest.assertTranslationResult(
+ "The pages H1 is translated.",
+ getH1,
+ "DON QUIJOTE DE LA MANCHA [es to en, html]"
+ );
+ });
+
+ await TestTranslationsTelemetry.assertCounter(
+ "RequestCount",
+ Glean.translations.requestsCount,
+ 1
+ );
+ await TestTranslationsTelemetry.assertRate(
+ "ErrorRate",
+ Glean.translations.errorRate,
+ {
+ expectedNumerator: 0,
+ expectedDenominator: 1,
+ }
+ );
+ await TestTranslationsTelemetry.assertEvent(
+ "TranslationRequest",
+ Glean.translations.translationRequest,
+ {
+ expectedLength: 1,
+ finalValuePredicates: [
+ value => value.extra.from_language === "es",
+ value => value.extra.to_language === "en",
+ value => value.extra.auto_translate === "true",
+ ],
+ }
+ );
+
+ await cleanup();
+});
diff --git a/browser/components/translations/tests/browser/head.js b/browser/components/translations/tests/browser/head.js
new file mode 100644
index 0000000000..56839971b7
--- /dev/null
+++ b/browser/components/translations/tests/browser/head.js
@@ -0,0 +1,348 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/toolkit/components/translations/tests/browser/shared-head.js",
+ this
+);
+
+/**
+ * Assert some property about the translations button.
+ *
+ * @param {Record<string, boolean>} visibleAssertions
+ * @param {string} message The message for the assertion.
+ * @returns {HTMLElement}
+ */
+async function assertTranslationsButton(visibleAssertions, message) {
+ const elements = {
+ button: document.getElementById("translations-button"),
+ icon: document.getElementById("translations-button-icon"),
+ circleArrows: document.getElementById("translations-button-circle-arrows"),
+ locale: document.getElementById("translations-button-locale"),
+ };
+
+ for (const [name, element] of Object.entries(elements)) {
+ if (!element) {
+ throw new Error("Could not find the " + name);
+ }
+ }
+
+ try {
+ // Test that the visibilities match.
+ await TestUtils.waitForCondition(() => {
+ for (const [name, visible] of Object.entries(visibleAssertions)) {
+ if (elements[name].hidden === visible) {
+ return false;
+ }
+ }
+ return true;
+ }, message);
+ } catch (error) {
+ // On a mismatch, report it.
+ for (const [name, expected] of Object.entries(visibleAssertions)) {
+ is(!elements[name].hidden, expected, `Visibility for "${name}"`);
+ }
+ }
+
+ ok(true, message);
+
+ return elements;
+}
+
+/**
+ * A convenience function to open the settings menu of the
+ * translations panel. Fails the test if the menu cannot be opened.
+ */
+async function openSettingsMenu() {
+ const { button } = await assertTranslationsButton(
+ { button: true },
+ "The button is available."
+ );
+
+ await waitForTranslationsPopupEvent("popupshown", () => {
+ click(button, "Opening the popup");
+ });
+
+ const gearIcon = getByL10nId("translations-panel-settings-button");
+ click(gearIcon, "Open the settings menu");
+}
+
+/**
+ * Simulates the effect of clicking the always-translate-language menuitem.
+ * Requires that the settings menu of the translations panel is open,
+ * otherwise the test will fail.
+ */
+async function toggleAlwaysTranslateLanguage() {
+ const alwaysTranslateLanguage = getByL10nId(
+ "translations-panel-settings-always-translate-language"
+ );
+ info("Toggle the always-translate-language menuitem");
+ await alwaysTranslateLanguage.doCommand();
+}
+
+/**
+ * Simulates the effect of clicking the never-translate-language menuitem.
+ * Requires that the settings menu of the translations panel is open,
+ * otherwise the test will fail.
+ */
+async function toggleNeverTranslateLanguage() {
+ const neverTranslateLanguage = getByL10nId(
+ "translations-panel-settings-never-translate-language"
+ );
+ info("Toggle the never-translate-language menuitem");
+ await neverTranslateLanguage.doCommand();
+}
+
+/**
+ * Simulates the effect of clicking the never-translate-site menuitem.
+ * Requires that the settings menu of the translations panel is open,
+ * otherwise the test will fail.
+ */
+async function toggleNeverTranslateSite() {
+ const neverTranslateSite = getByL10nId(
+ "translations-panel-settings-never-translate-site"
+ );
+ info("Toggle the never-translate-site menuitem");
+ await neverTranslateSite.doCommand();
+}
+
+/**
+ * Asserts that the always-translate-language checkbox matches the expected checked state.
+ *
+ * @param {string} langTag - A BCP-47 language tag
+ * @param {boolean} expectChecked - Whether the checkbox should be checked
+ */
+async function assertIsAlwaysTranslateLanguage(langTag, expectChecked) {
+ await assertCheckboxState(
+ "translations-panel-settings-always-translate-language",
+ expectChecked
+ );
+}
+
+/**
+ * Asserts that the never-translate-language checkbox matches the expected checked state.
+ *
+ * @param {string} langTag - A BCP-47 language tag
+ * @param {boolean} expectChecked - Whether the checkbox should be checked
+ */
+async function assertIsNeverTranslateLanguage(langTag, expectChecked) {
+ await assertCheckboxState(
+ "translations-panel-settings-never-translate-language",
+ expectChecked
+ );
+}
+
+/**
+ * Asserts that the never-translate-site checkbox matches the expected checked state.
+ *
+ * @param {string} url - The url of a website
+ * @param {boolean} expectChecked - Whether the checkbox should be checked
+ */
+async function assertIsNeverTranslateSite(url, expectChecked) {
+ await assertCheckboxState(
+ "translations-panel-settings-never-translate-site",
+ expectChecked
+ );
+}
+
+/**
+ * Asserts that the state of a checkbox with a given dataL10nId is
+ * checked or not, based on the value of expected being true or false.
+ *
+ * @param {string} dataL10nId - The data-l10n-id of the checkbox.
+ * @param {boolean} expectChecked - Whether the checkbox should be checked.
+ */
+async function assertCheckboxState(dataL10nId, expectChecked) {
+ const menuItems = getAllByL10nId(dataL10nId);
+ for (const menuItem of menuItems) {
+ await TestUtils.waitForCondition(
+ () =>
+ menuItem.getAttribute("checked") === (expectChecked ? "true" : "false"),
+ "Waiting for checkbox state"
+ );
+ is(
+ menuItem.getAttribute("checked"),
+ expectChecked ? "true" : "false",
+ `Should match expected checkbox state for ${dataL10nId}`
+ );
+ }
+}
+
+/**
+ * Navigate to a URL and indicate a message as to why.
+ */
+async function navigate(url, message) {
+ info(message);
+
+ // Load a blank page first to ensure that tests don't hang.
+ // I don't know why this is needed, but it appears to be necessary.
+ BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, BLANK_PAGE);
+ await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+
+ BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, url);
+ await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+}
+
+/**
+ * Add a tab to the page
+ *
+ * @param {string} url
+ */
+async function addTab(url) {
+ info(`Adding tab for ` + url);
+ const tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ url,
+ true // Wait for laod
+ );
+ return {
+ tab,
+ removeTab() {
+ BrowserTestUtils.removeTab(tab);
+ },
+ };
+}
+
+async function switchTab(tab) {
+ info("Switching tabs");
+ await BrowserTestUtils.switchTab(gBrowser, tab);
+}
+
+function click(button, message) {
+ info(message);
+ EventUtils.synthesizeMouseAtCenter(button, {});
+}
+
+/**
+ * @param {Element} element
+ * @returns {boolean}
+ */
+function isVisible(element) {
+ const win = element.ownerDocument.ownerGlobal;
+ const { visibility, display } = win.getComputedStyle(element);
+ return visibility === "visible" && display !== "none";
+}
+
+/**
+ * Get an element by its l10n id, as this is a user-visible way to find an element.
+ * The `l10nId` represents the text that a user would actually see.
+ *
+ * @param {string} l10nId
+ * @param {Document} doc
+ * @returns {Element}
+ */
+function getByL10nId(l10nId, doc = document) {
+ const elements = doc.querySelectorAll(`[data-l10n-id="${l10nId}"]`);
+ if (elements.length === 0) {
+ throw new Error("Could not find the element by l10n id: " + l10nId);
+ }
+ for (const element of elements) {
+ if (isVisible(element)) {
+ return element;
+ }
+ }
+ throw new Error("The element is not visible in the DOM: " + l10nId);
+}
+
+/**
+ * Get all elements that match the l10n id.
+ *
+ * @param {string} l10nId
+ * @param {Document} doc
+ * @returns {Element}
+ */
+function getAllByL10nId(l10nId, doc = document) {
+ const elements = doc.querySelectorAll(`[data-l10n-id="${l10nId}"]`);
+ if (elements.length === 0) {
+ throw new Error("Could not find the element by l10n id: " + l10nId);
+ }
+ return elements;
+}
+
+/**
+ * @param {string} id
+ * @param {Document} [doc]
+ * @returns {Element}
+ */
+function getById(id, doc = document) {
+ const element = doc.getElementById(id);
+ if (!element) {
+ throw new Error("Could not find the element by id: #" + id);
+ }
+ if (isVisible(element)) {
+ return element;
+ }
+ throw new Error("The element is not visible in the DOM: #" + id);
+}
+
+/**
+ * A non-throwing version of `getByL10nId`.
+ *
+ * @param {string} l10nId
+ * @returns {Element | null}
+ */
+function maybeGetByL10nId(l10nId, doc = document) {
+ const selector = `[data-l10n-id="${l10nId}"]`;
+ const elements = doc.querySelectorAll(selector);
+ for (const element of elements) {
+ if (isVisible(element)) {
+ return element;
+ }
+ }
+ return null;
+}
+
+/**
+ * XUL popups will fire the popupshown and popuphidden events. These will fire for
+ * any type of popup in the browser. This function waits for one of those events, and
+ * checks that the viewId of the popup is PanelUI-profiler
+ *
+ * @param {"popupshown" | "popuphidden"} eventName
+ * @param {Function} callback
+ * @returns {Promise<void>}
+ */
+async function waitForTranslationsPopupEvent(eventName, callback) {
+ const panel = document.getElementById("translations-panel");
+ if (!panel) {
+ throw new Error("Unable to find the translations panel element.");
+ }
+ const promise = BrowserTestUtils.waitForEvent(panel, eventName);
+ callback();
+ info("Waiting for the translations panel popup to be shown");
+ await promise;
+ // Wait a single tick on the event loop.
+ await new Promise(resolve => setTimeout(resolve, 0));
+}
+
+/**
+ * When switching between between views in the popup panel, wait for the view to
+ * be fully shown.
+ *
+ * @param {Function} callback
+ */
+async function waitForViewShown(callback) {
+ const panel = document.getElementById("translations-panel");
+ if (!panel) {
+ throw new Error("Unable to find the translations panel element.");
+ }
+ const promise = BrowserTestUtils.waitForEvent(panel, "ViewShown");
+ callback();
+ info("Waiting for the translations panel view to be shown");
+ await promise;
+ await new Promise(resolve => setTimeout(resolve, 0));
+}
+
+const ENGLISH_PAGE_URL = TRANSLATIONS_TESTER_EN;
+const SPANISH_PAGE_URL = TRANSLATIONS_TESTER_ES;
+const SPANISH_PAGE_URL_2 = TRANSLATIONS_TESTER_ES_2;
+const SPANISH_PAGE_URL_DOT_ORG = TRANSLATIONS_TESTER_ES_DOT_ORG;
+const LANGUAGE_PAIRS = [
+ { fromLang: "es", toLang: "en", isBeta: false },
+ { fromLang: "en", toLang: "es", isBeta: false },
+ { fromLang: "fr", toLang: "en", isBeta: false },
+ { fromLang: "en", toLang: "fr", isBeta: false },
+ { fromLang: "en", toLang: "uk", isBeta: true },
+ { fromLang: "uk", toLang: "en", isBeta: true },
+];