summaryrefslogtreecommitdiffstats
path: root/browser/components/preferences/tests/browser_browser_languages_subdialog.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/preferences/tests/browser_browser_languages_subdialog.js')
-rw-r--r--browser/components/preferences/tests/browser_browser_languages_subdialog.js1058
1 files changed, 1058 insertions, 0 deletions
diff --git a/browser/components/preferences/tests/browser_browser_languages_subdialog.js b/browser/components/preferences/tests/browser_browser_languages_subdialog.js
new file mode 100644
index 0000000000..1572a8b573
--- /dev/null
+++ b/browser/components/preferences/tests/browser_browser_languages_subdialog.js
@@ -0,0 +1,1058 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { AddonTestUtils } = ChromeUtils.import(
+ "resource://testing-common/AddonTestUtils.jsm"
+);
+
+AddonTestUtils.initMochitest(this);
+
+const BROWSER_LANGUAGES_URL =
+ "chrome://browser/content/preferences/dialogs/browserLanguages.xhtml";
+const DICTIONARY_ID_PL = "pl@dictionaries.addons.mozilla.org";
+const TELEMETRY_CATEGORY = "intl.ui.browserLanguage";
+
+function langpackId(locale) {
+ return `langpack-${locale}@firefox.mozilla.org`;
+}
+
+function getManifestData(locale, version = "2.0") {
+ return {
+ langpack_id: locale,
+ name: `${locale} Language Pack`,
+ description: `${locale} Language pack`,
+ languages: {
+ [locale]: {
+ chrome_resources: {
+ branding: `browser/chrome/${locale}/locale/branding/`,
+ },
+ version: "1",
+ },
+ },
+ browser_specific_settings: {
+ gecko: {
+ id: langpackId(locale),
+ strict_min_version: AppConstants.MOZ_APP_VERSION,
+ strict_max_version: AppConstants.MOZ_APP_VERSION,
+ },
+ },
+ version,
+ manifest_version: 2,
+ sources: {
+ browser: {
+ base_path: "browser/",
+ },
+ },
+ author: "Mozilla",
+ };
+}
+
+let testLocales = ["fr", "pl", "he"];
+let testLangpacks;
+
+function createLangpack(locale, version) {
+ return AddonTestUtils.createTempXPIFile({
+ "manifest.json": getManifestData(locale, version),
+ [`browser/${locale}/branding/brand.ftl`]: "-brand-short-name = Firefox",
+ });
+}
+
+function createTestLangpacks() {
+ if (!testLangpacks) {
+ testLangpacks = Promise.all(
+ testLocales.map(async locale => [locale, await createLangpack(locale)])
+ );
+ }
+ return testLangpacks;
+}
+
+function createLocaleResult(target_locale, url) {
+ return {
+ guid: langpackId(target_locale),
+ type: "language",
+ target_locale,
+ current_compatible_version: {
+ files: [
+ {
+ platform: "all",
+ url,
+ },
+ ],
+ },
+ };
+}
+
+async function createLanguageToolsFile() {
+ let langpacks = await createTestLangpacks();
+ let results = langpacks.map(([locale, file]) =>
+ createLocaleResult(locale, Services.io.newFileURI(file).spec)
+ );
+
+ let filename = "language-tools.json";
+ let files = { [filename]: { results } };
+ let tempdir = AddonTestUtils.tempDir.clone();
+ let dir = await AddonTestUtils.promiseWriteFilesToDir(tempdir.path, files);
+ dir.append(filename);
+
+ return dir;
+}
+
+async function createDictionaryBrowseResults() {
+ let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
+ let dictionaryPath = testDir + "/addons/pl-dictionary.xpi";
+ let filename = "dictionaries.json";
+ let response = {
+ page_size: 25,
+ page_count: 1,
+ count: 1,
+ results: [
+ {
+ current_version: {
+ id: 1823648,
+ compatibility: {
+ firefox: { max: "9999", min: "4.0" },
+ },
+ files: [
+ {
+ platform: "all",
+ url: dictionaryPath,
+ },
+ ],
+ version: "1.0.20160228",
+ },
+ default_locale: "pl",
+ description: "Polish spell-check",
+ guid: DICTIONARY_ID_PL,
+ name: "Polish Dictionary",
+ slug: "polish-spellchecker-dictionary",
+ status: "public",
+ summary: "Polish dictionary",
+ type: "dictionary",
+ },
+ ],
+ };
+
+ let files = { [filename]: response };
+ let dir = await AddonTestUtils.promiseWriteFilesToDir(
+ AddonTestUtils.tempDir.path,
+ files
+ );
+ dir.append(filename);
+
+ return dir;
+}
+
+function assertLocaleOrder(list, locales) {
+ is(
+ list.itemCount,
+ locales.split(",").length,
+ "The right number of locales are selected"
+ );
+ is(
+ Array.from(list.children)
+ .map(child => child.value)
+ .join(","),
+ locales,
+ "The selected locales are in order"
+ );
+}
+
+function assertAvailableLocales(list, locales) {
+ let items = Array.from(list.menupopup.children);
+ let listLocales = items.filter(item => item.value && item.value != "search");
+ is(
+ listLocales.length,
+ locales.length,
+ "The right number of locales are available"
+ );
+ is(
+ listLocales
+ .map(item => item.value)
+ .sort()
+ .join(","),
+ locales.sort().join(","),
+ "The available locales match"
+ );
+ is(items[0].getAttribute("class"), "label-item", "The first row is a label");
+}
+
+function getDialogId(dialogDoc) {
+ return dialogDoc.ownerGlobal.arguments[0].telemetryId;
+}
+
+function assertTelemetryRecorded(events) {
+ let snapshot = Services.telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ true
+ );
+
+ // Make sure we got some data.
+ ok(
+ snapshot.parent && !!snapshot.parent.length,
+ "Got parent telemetry events in the snapshot"
+ );
+
+ // Only look at the related events after stripping the timestamp and category.
+ let relatedEvents = snapshot.parent
+ .filter(([timestamp, category]) => category == TELEMETRY_CATEGORY)
+ .map(relatedEvent => relatedEvent.slice(2, 6));
+
+ // Events are now an array of: method, object[, value[, extra]] as expected.
+ Assert.deepEqual(relatedEvents, events, "The events are recorded correctly");
+}
+
+async function selectLocale(localeCode, available, selected, dialogDoc) {
+ let [locale] = Array.from(available.menupopup.children).filter(
+ item => item.value == localeCode
+ );
+ available.selectedItem = locale;
+
+ // Get ready for the selected list to change.
+ let added = waitForMutation(selected, { childList: true }, target =>
+ Array.from(target.children).some(el => el.value == localeCode)
+ );
+
+ // Add the locale.
+ dialogDoc.getElementById("add").doCommand();
+
+ // Wait for the list to update.
+ await added;
+}
+
+async function openDialog(doc, search = false) {
+ let dialogLoaded = promiseLoadSubDialog(BROWSER_LANGUAGES_URL);
+ if (search) {
+ doc.getElementById("primaryBrowserLocaleSearch").doCommand();
+ doc.getElementById("primaryBrowserLocale").menupopup.hidePopup();
+ } else {
+ doc.getElementById("manageBrowserLanguagesButton").doCommand();
+ }
+ let dialogWin = await dialogLoaded;
+ let dialogDoc = dialogWin.document;
+ return {
+ dialog: dialogDoc.getElementById("BrowserLanguagesDialog"),
+ dialogDoc,
+ available: dialogDoc.getElementById("availableLocales"),
+ selected: dialogDoc.getElementById("selectedLocales"),
+ };
+}
+
+add_task(async function testDisabledBrowserLanguages() {
+ let langpacksFile = await createLanguageToolsFile();
+ let langpacksUrl = Services.io.newFileURI(langpacksFile).spec;
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", true],
+ ["intl.multilingual.liveReload", false],
+ ["intl.multilingual.liveReloadBidirectional", false],
+ ["intl.locale.requested", "en-US,pl,he,de"],
+ ["extensions.langpacks.signatures.required", false],
+ ["extensions.getAddons.langpacks.url", langpacksUrl],
+ ],
+ });
+
+ // Install an old pl langpack.
+ let oldLangpack = await createLangpack("pl", "1.0");
+ await AddonTestUtils.promiseInstallFile(oldLangpack);
+
+ // Install all the other available langpacks.
+ let pl;
+ let langpacks = await createTestLangpacks();
+ let addons = await Promise.all(
+ langpacks.map(async ([locale, file]) => {
+ if (locale == "pl") {
+ pl = await AddonManager.getAddonByID(langpackId("pl"));
+ // Disable pl so it's removed from selected.
+ await pl.disable();
+ return pl;
+ }
+ let install = await AddonTestUtils.promiseInstallFile(file);
+ return install.addon;
+ })
+ );
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+
+ let doc = gBrowser.contentDocument;
+ let { dialogDoc, available, selected } = await openDialog(doc);
+
+ // pl is not selected since it's disabled.
+ is(pl.userDisabled, true, "pl is disabled");
+ is(pl.version, "1.0", "pl is the old 1.0 version");
+ assertLocaleOrder(selected, "en-US,he");
+
+ // Wait for the children menu to be populated.
+ await BrowserTestUtils.waitForCondition(
+ () => !!available.children.length,
+ "Children list populated"
+ );
+
+ // Only fr is enabled and not selected, so it's the only locale available.
+ assertAvailableLocales(available, ["fr"]);
+
+ // Search for more languages.
+ available.menupopup.lastElementChild.doCommand();
+ available.menupopup.hidePopup();
+ await waitForMutation(available.menupopup, { childList: true }, target =>
+ Array.from(available.menupopup.children).some(
+ locale => locale.value == "pl"
+ )
+ );
+
+ // pl is now available since it is available remotely.
+ assertAvailableLocales(available, ["fr", "pl"]);
+
+ let installId = null;
+ AddonTestUtils.promiseInstallEvent("onInstallEnded").then(([install]) => {
+ installId = install.installId;
+ });
+
+ // Add pl.
+ await selectLocale("pl", available, selected, dialogDoc);
+ assertLocaleOrder(selected, "pl,en-US,he");
+
+ // Find pl again since it's been upgraded.
+ pl = await AddonManager.getAddonByID(langpackId("pl"));
+ is(pl.userDisabled, false, "pl is now enabled");
+ is(pl.version, "2.0", "pl is upgraded to version 2.0");
+
+ let dialogId = getDialogId(dialogDoc);
+ ok(dialogId, "There's a dialogId");
+ ok(installId, "There's an installId");
+
+ await Promise.all(addons.map(addon => addon.uninstall()));
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ assertTelemetryRecorded([
+ ["manage", "main", dialogId],
+ ["search", "dialog", dialogId],
+ ["add", "dialog", dialogId, { installId }],
+
+ // Cancel is recorded when the tab is closed.
+ ["cancel", "dialog", dialogId],
+ ]);
+});
+
+add_task(async function testReorderingBrowserLanguages() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", true],
+ ["intl.multilingual.liveReload", false],
+ ["intl.multilingual.liveReloadBidirectional", false],
+ ["intl.locale.requested", "en-US,pl,he,de"],
+ ["extensions.langpacks.signatures.required", false],
+ ],
+ });
+
+ // Install all the available langpacks.
+ let langpacks = await createTestLangpacks();
+ let addons = await Promise.all(
+ langpacks.map(async ([locale, file]) => {
+ let install = await AddonTestUtils.promiseInstallFile(file);
+ return install.addon;
+ })
+ );
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+
+ let doc = gBrowser.contentDocument;
+ let messageBar = doc.getElementById("confirmBrowserLanguage");
+ is(messageBar.hidden, true, "The message bar is hidden at first");
+
+ // Open the dialog.
+ let { dialog, dialogDoc, selected } = await openDialog(doc);
+ let firstDialogId = getDialogId(dialogDoc);
+
+ // The initial order is set by the pref, filtered by available.
+ assertLocaleOrder(selected, "en-US,pl,he");
+
+ // Moving pl down changes the order.
+ selected.selectedItem = selected.querySelector("[value='pl']");
+ dialogDoc.getElementById("down").doCommand();
+ assertLocaleOrder(selected, "en-US,he,pl");
+
+ // Accepting the change shows the confirm message bar.
+ let dialogClosed = BrowserTestUtils.waitForEvent(dialog, "dialogclosing");
+ dialog.acceptDialog();
+ await dialogClosed;
+
+ // The message bar uses async `formatValues` and that may resolve
+ // after the dialog is closed.
+ await BrowserTestUtils.waitForMutationCondition(
+ messageBar,
+ { attributes: true },
+ () => !messageBar.hidden
+ );
+ is(
+ messageBar.querySelector("button").getAttribute("locales"),
+ "en-US,he,pl",
+ "The locales are set on the message bar button"
+ );
+
+ // Open the dialog again.
+ let newDialog = await openDialog(doc);
+ dialog = newDialog.dialog;
+ dialogDoc = newDialog.dialogDoc;
+ let secondDialogId = getDialogId(dialogDoc);
+ selected = newDialog.selected;
+
+ // The initial order comes from the previous settings.
+ assertLocaleOrder(selected, "en-US,he,pl");
+
+ // Select pl in the list.
+ selected.selectedItem = selected.querySelector("[value='pl']");
+ // Move pl back up.
+ dialogDoc.getElementById("up").doCommand();
+ assertLocaleOrder(selected, "en-US,pl,he");
+
+ // Accepting the change hides the confirm message bar.
+ dialogClosed = BrowserTestUtils.waitForEvent(dialog, "dialogclosing");
+ dialog.acceptDialog();
+ await dialogClosed;
+ is(messageBar.hidden, true, "The message bar is hidden again");
+
+ ok(firstDialogId, "There was an id on the first dialog");
+ ok(secondDialogId, "There was an id on the second dialog");
+ ok(firstDialogId != secondDialogId, "The dialog ids are different");
+ ok(
+ parseInt(firstDialogId) < parseInt(secondDialogId),
+ "The second dialog id is larger than the first"
+ );
+
+ await Promise.all(addons.map(addon => addon.uninstall()));
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ assertTelemetryRecorded([
+ ["manage", "main", firstDialogId],
+ ["reorder", "dialog", firstDialogId],
+ ["accept", "dialog", firstDialogId],
+ ["manage", "main", secondDialogId],
+ ["reorder", "dialog", secondDialogId],
+ ["accept", "dialog", secondDialogId],
+ ]);
+});
+
+add_task(async function testAddAndRemoveSelectedLanguages() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", true],
+ ["intl.multilingual.liveReload", false],
+ ["intl.multilingual.liveReloadBidirectional", false],
+ ["intl.locale.requested", "en-US"],
+ ["extensions.langpacks.signatures.required", false],
+ ],
+ });
+
+ let langpacks = await createTestLangpacks();
+ let addons = await Promise.all(
+ langpacks.map(async ([locale, file]) => {
+ let install = await AddonTestUtils.promiseInstallFile(file);
+ return install.addon;
+ })
+ );
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+
+ let doc = gBrowser.contentDocument;
+ let messageBar = doc.getElementById("confirmBrowserLanguage");
+ is(messageBar.hidden, true, "The message bar is hidden at first");
+
+ // Open the dialog.
+ let { dialog, dialogDoc, available, selected } = await openDialog(doc);
+ let dialogId = getDialogId(dialogDoc);
+
+ // loadLocalesFromAMO is async but `initAvailableLocales` doesn't wait
+ // for it to be resolved, so we have to wait for the list to be populated
+ // before we test for its values.
+ await BrowserTestUtils.waitForMutationCondition(
+ available.menupopup,
+ { attributes: true, childList: true },
+ () => {
+ let listLocales = Array.from(available.menupopup.children).filter(
+ item => item.value && item.value != "search"
+ );
+ return listLocales.length == 3;
+ }
+ );
+ // The initial order is set by the pref.
+ assertLocaleOrder(selected, "en-US");
+ assertAvailableLocales(available, ["fr", "pl", "he"]);
+
+ // Add pl and fr to selected.
+ await selectLocale("pl", available, selected, dialogDoc);
+ await selectLocale("fr", available, selected, dialogDoc);
+
+ assertLocaleOrder(selected, "fr,pl,en-US");
+ assertAvailableLocales(available, ["he"]);
+
+ // Remove pl and fr from selected.
+ dialogDoc.getElementById("remove").doCommand();
+ dialogDoc.getElementById("remove").doCommand();
+ assertLocaleOrder(selected, "en-US");
+ assertAvailableLocales(available, ["fr", "pl", "he"]);
+
+ // Add he to selected.
+ await selectLocale("he", available, selected, dialogDoc);
+ assertLocaleOrder(selected, "he,en-US");
+ assertAvailableLocales(available, ["pl", "fr"]);
+
+ // Accepting the change shows the confirm message bar.
+ let dialogClosed = BrowserTestUtils.waitForEvent(dialog, "dialogclosing");
+ dialog.acceptDialog();
+ await dialogClosed;
+
+ await waitForMutation(
+ messageBar,
+ { attributes: true, attributeFilter: ["hidden"] },
+ target => !target.hidden
+ );
+
+ is(messageBar.hidden, false, "The message bar is now visible");
+ is(
+ messageBar.querySelector("button").getAttribute("locales"),
+ "he,en-US",
+ "The locales are set on the message bar button"
+ );
+
+ await Promise.all(addons.map(addon => addon.uninstall()));
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ assertTelemetryRecorded([
+ ["manage", "main", dialogId],
+
+ // Install id is not recorded since it was already installed.
+ ["add", "dialog", dialogId],
+ ["add", "dialog", dialogId],
+
+ ["remove", "dialog", dialogId],
+ ["remove", "dialog", dialogId],
+
+ ["add", "dialog", dialogId],
+ ["accept", "dialog", dialogId],
+ ]);
+});
+
+add_task(async function testInstallFromAMO() {
+ let langpacks = await AddonManager.getAddonsByTypes(["locale"]);
+ is(langpacks.length, 0, "There are no langpacks installed");
+
+ let langpacksFile = await createLanguageToolsFile();
+ let langpacksUrl = Services.io.newFileURI(langpacksFile).spec;
+ let dictionaryBrowseFile = await createDictionaryBrowseResults();
+ let browseApiEndpoint = Services.io.newFileURI(dictionaryBrowseFile).spec;
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", true],
+ ["intl.multilingual.liveReload", false],
+ ["intl.multilingual.liveReloadBidirectional", false],
+ ["intl.locale.requested", "en-US"],
+ ["extensions.getAddons.langpacks.url", langpacksUrl],
+ ["extensions.langpacks.signatures.required", false],
+ ["extensions.getAddons.get.url", browseApiEndpoint],
+ ],
+ });
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+
+ let doc = gBrowser.contentDocument;
+ let messageBar = doc.getElementById("confirmBrowserLanguage");
+ is(messageBar.hidden, true, "The message bar is hidden at first");
+
+ // Verify only en-US is listed on the main pane.
+ let getMainPaneLocales = () => {
+ let available = doc.getElementById("primaryBrowserLocale");
+ let availableLocales = Array.from(available.menupopup.children);
+ return availableLocales
+ .map(item => item.value)
+ .sort()
+ .join(",");
+ };
+ is(getMainPaneLocales(), "en-US,search", "Only en-US installed to start");
+
+ // Open the dialog.
+ let { dialog, dialogDoc, available, selected } = await openDialog(doc, true);
+ let firstDialogId = getDialogId(dialogDoc);
+
+ // Make sure the message bar is still hidden.
+ is(
+ messageBar.hidden,
+ true,
+ "The message bar is still hidden after searching"
+ );
+
+ if (available.itemCount == 1) {
+ await waitForMutation(
+ available.menupopup,
+ { childList: true },
+ target => available.itemCount > 1
+ );
+ }
+
+ // The initial order is set by the pref.
+ assertLocaleOrder(selected, "en-US");
+ assertAvailableLocales(available, ["fr", "he", "pl"]);
+ is(
+ Services.locale.availableLocales.join(","),
+ "en-US",
+ "There is only one installed locale"
+ );
+
+ // Verify that there are no extra dictionaries.
+ let dicts = await AddonManager.getAddonsByTypes(["dictionary"]);
+ is(dicts.length, 0, "There are no installed dictionaries");
+
+ let installId = null;
+ AddonTestUtils.promiseInstallEvent("onInstallEnded").then(([install]) => {
+ installId = install.installId;
+ });
+
+ // Add Polish, this will install the langpack.
+ await selectLocale("pl", available, selected, dialogDoc);
+
+ ok(installId, "We got an installId for the langpack installation");
+
+ let langpack = await AddonManager.getAddonByID(langpackId("pl"));
+ Assert.deepEqual(
+ langpack.installTelemetryInfo,
+ { source: "about:preferences" },
+ "The source is set to preferences"
+ );
+
+ // Verify the list is correct.
+ assertLocaleOrder(selected, "pl,en-US");
+ assertAvailableLocales(available, ["fr", "he"]);
+ is(
+ Services.locale.availableLocales.sort().join(","),
+ "en-US,pl",
+ "Polish is now installed"
+ );
+
+ await BrowserTestUtils.waitForCondition(async () => {
+ let newDicts = await AddonManager.getAddonsByTypes(["dictionary"]);
+ let done = !!newDicts.length;
+
+ if (done) {
+ is(
+ newDicts[0].id,
+ DICTIONARY_ID_PL,
+ "The polish dictionary was installed"
+ );
+ }
+
+ return done;
+ });
+
+ // Move pl down the list, which prevents an error since it isn't valid.
+ dialogDoc.getElementById("down").doCommand();
+ assertLocaleOrder(selected, "en-US,pl");
+
+ // Test that disabling the langpack removes it from the list.
+ let dialogClosed = BrowserTestUtils.waitForEvent(dialog, "dialogclosing");
+ dialog.acceptDialog();
+ await dialogClosed;
+
+ // Verify pl is now available to select.
+ is(getMainPaneLocales(), "en-US,pl,search", "en-US and pl now available");
+
+ // Disable the Polish langpack.
+ langpack = await AddonManager.getAddonByID("langpack-pl@firefox.mozilla.org");
+ await langpack.disable();
+
+ ({ dialogDoc, available, selected } = await openDialog(doc, true));
+ let secondDialogId = getDialogId(dialogDoc);
+
+ // Wait for the available langpacks to load.
+ if (available.itemCount == 1) {
+ await waitForMutation(
+ available.menupopup,
+ { childList: true },
+ target => available.itemCount > 1
+ );
+ }
+ assertLocaleOrder(selected, "en-US");
+ assertAvailableLocales(available, ["fr", "he", "pl"]);
+
+ // Uninstall the langpack and dictionary.
+ let installs = await AddonManager.getAddonsByTypes(["locale", "dictionary"]);
+ is(installs.length, 2, "There is one langpack and one dictionary installed");
+ await Promise.all(installs.map(item => item.uninstall()));
+
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ assertTelemetryRecorded([
+ // First dialog installs a locale and accepts.
+ ["search", "main", firstDialogId],
+ // It has an installId since it was downloaded.
+ ["add", "dialog", firstDialogId, { installId }],
+ // It got moved down to avoid errors with finding translations.
+ ["reorder", "dialog", firstDialogId],
+ ["accept", "dialog", firstDialogId],
+
+ // The second dialog just checks the state and is closed with the tab.
+ ["search", "main", secondDialogId],
+ ["cancel", "dialog", secondDialogId],
+ ]);
+});
+
+let hasSearchOption = popup =>
+ Array.from(popup.children).some(el => el.value == "search");
+
+add_task(async function testDownloadEnabled() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", true],
+ ["intl.multilingual.liveReload", false],
+ ["intl.multilingual.liveReloadBidirectional", false],
+ ],
+ });
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+ let doc = gBrowser.contentDocument;
+
+ let defaultMenulist = doc.getElementById("primaryBrowserLocale");
+ ok(
+ hasSearchOption(defaultMenulist.menupopup),
+ "There's a search option in the General pane"
+ );
+
+ let { available } = await openDialog(doc, false);
+ ok(
+ hasSearchOption(available.menupopup),
+ "There's a search option in the dialog"
+ );
+
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+add_task(async function testDownloadDisabled() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", false],
+ ["intl.multilingual.liveReload", false],
+ ["intl.multilingual.liveReloadBidirectional", false],
+ ],
+ });
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+ let doc = gBrowser.contentDocument;
+
+ let defaultMenulist = doc.getElementById("primaryBrowserLocale");
+ ok(
+ !hasSearchOption(defaultMenulist.menupopup),
+ "There's no search option in the General pane"
+ );
+
+ let { available } = await openDialog(doc, false);
+ ok(
+ !hasSearchOption(available.menupopup),
+ "There's no search option in the dialog"
+ );
+
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+add_task(async function testReorderMainPane() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", false],
+ ["intl.multilingual.liveReload", false],
+ ["intl.multilingual.liveReloadBidirectional", false],
+ ["intl.locale.requested", "en-US"],
+ ["extensions.langpacks.signatures.required", false],
+ ],
+ });
+
+ // Clear the telemetry from other tests.
+ Services.telemetry.clearEvents();
+
+ let langpacks = await createTestLangpacks();
+ let addons = await Promise.all(
+ langpacks.map(async ([locale, file]) => {
+ let install = await AddonTestUtils.promiseInstallFile(file);
+ return install.addon;
+ })
+ );
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+ let doc = gBrowser.contentDocument;
+
+ let messageBar = doc.getElementById("confirmBrowserLanguage");
+ is(messageBar.hidden, true, "The message bar is hidden at first");
+
+ let available = doc.getElementById("primaryBrowserLocale");
+ let availableLocales = Array.from(available.menupopup.children);
+ let availableCodes = availableLocales
+ .map(item => item.value)
+ .sort()
+ .join(",");
+ is(
+ availableCodes,
+ "en-US,fr,he,pl",
+ "All of the available locales are listed"
+ );
+
+ is(available.selectedItem.value, "en-US", "English is selected");
+
+ let hebrew = availableLocales.find(item => item.value == "he");
+ hebrew.click();
+ available.menupopup.hidePopup();
+
+ await BrowserTestUtils.waitForCondition(
+ () => !messageBar.hidden,
+ "Wait for message bar to show"
+ );
+
+ is(messageBar.hidden, false, "The message bar is now shown");
+ is(
+ messageBar.querySelector("button").getAttribute("locales"),
+ "he,en-US",
+ "The locales are set on the message bar button"
+ );
+
+ await Promise.all(addons.map(addon => addon.uninstall()));
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ assertTelemetryRecorded([["reorder", "main"]]);
+});
+
+add_task(async function testLiveLanguageReloading() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", true],
+ ["intl.multilingual.liveReload", true],
+ ["intl.multilingual.liveReloadBidirectional", false],
+ ["intl.locale.requested", "en-US,fr,he,de"],
+ ["extensions.langpacks.signatures.required", false],
+ ],
+ });
+
+ // Clear the telemetry from other tests.
+ Services.telemetry.clearEvents();
+
+ let langpacks = await createTestLangpacks();
+ let addons = await Promise.all(
+ langpacks.map(async ([locale, file]) => {
+ let install = await AddonTestUtils.promiseInstallFile(file);
+ return install.addon;
+ })
+ );
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+
+ let doc = gBrowser.contentDocument;
+
+ let available = doc.getElementById("primaryBrowserLocale");
+ let availableLocales = Array.from(available.menupopup.children);
+
+ is(
+ Services.locale.appLocaleAsBCP47,
+ "en-US",
+ "The app locale starts as English."
+ );
+
+ Assert.deepEqual(
+ Services.locale.requestedLocales,
+ ["en-US", "fr", "he", "de"],
+ "The locale order starts as what was initially requested."
+ );
+
+ // French and English are both LTR languages.
+ let french = availableLocales.find(item => item.value == "fr");
+
+ french.click();
+ available.menupopup.hidePopup();
+
+ is(
+ Services.locale.appLocaleAsBCP47,
+ "fr",
+ "The app locale was changed to French"
+ );
+
+ Assert.deepEqual(
+ Services.locale.requestedLocales,
+ ["fr", "en-US", "he", "de"],
+ "The locale order is switched to french first."
+ );
+
+ await Promise.all(addons.map(addon => addon.uninstall()));
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ assertTelemetryRecorded([["reorder", "main"]]);
+});
+
+add_task(async function testLiveLanguageReloadingBidiOff() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", true],
+ ["intl.multilingual.liveReload", true],
+ ["intl.multilingual.liveReloadBidirectional", false],
+ ["intl.locale.requested", "en-US,fr,he,de"],
+ ["extensions.langpacks.signatures.required", false],
+ ],
+ });
+
+ // Clear the telemetry from other tests.
+ Services.telemetry.clearEvents();
+
+ let langpacks = await createTestLangpacks();
+ let addons = await Promise.all(
+ langpacks.map(async ([locale, file]) => {
+ let install = await AddonTestUtils.promiseInstallFile(file);
+ return install.addon;
+ })
+ );
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+
+ let doc = gBrowser.contentDocument;
+
+ let available = doc.getElementById("primaryBrowserLocale");
+ let availableLocales = Array.from(available.menupopup.children);
+
+ is(
+ Services.locale.appLocaleAsBCP47,
+ "en-US",
+ "The app locale starts as English."
+ );
+
+ Assert.deepEqual(
+ Services.locale.requestedLocales,
+ ["en-US", "fr", "he", "de"],
+ "The locale order starts as what was initially requested."
+ );
+
+ let messageBar = doc.getElementById("confirmBrowserLanguage");
+ is(messageBar.hidden, true, "The message bar is hidden at first");
+
+ // English is LTR and Hebrew is RTL.
+ let hebrew = availableLocales.find(item => item.value == "he");
+
+ hebrew.click();
+ available.menupopup.hidePopup();
+
+ await BrowserTestUtils.waitForCondition(
+ () => !messageBar.hidden,
+ "Wait for message bar to show"
+ );
+
+ is(messageBar.hidden, false, "The message bar is now shown");
+
+ is(
+ Services.locale.appLocaleAsBCP47,
+ "en-US",
+ "The app locale remains in English"
+ );
+
+ Assert.deepEqual(
+ Services.locale.requestedLocales,
+ ["en-US", "fr", "he", "de"],
+ "The locale order did not change."
+ );
+
+ await Promise.all(addons.map(addon => addon.uninstall()));
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ assertTelemetryRecorded([["reorder", "main"]]);
+});
+
+add_task(async function testLiveLanguageReloadingBidiOn() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["intl.multilingual.enabled", true],
+ ["intl.multilingual.downloadEnabled", true],
+ ["intl.multilingual.liveReload", true],
+ ["intl.multilingual.liveReloadBidirectional", true],
+ ["intl.locale.requested", "en-US,fr,he,de"],
+ ["extensions.langpacks.signatures.required", false],
+ ],
+ });
+
+ // Clear the telemetry from other tests.
+ Services.telemetry.clearEvents();
+
+ let langpacks = await createTestLangpacks();
+ let addons = await Promise.all(
+ langpacks.map(async ([locale, file]) => {
+ let install = await AddonTestUtils.promiseInstallFile(file);
+ return install.addon;
+ })
+ );
+
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+
+ let doc = gBrowser.contentDocument;
+
+ let available = doc.getElementById("primaryBrowserLocale");
+ let availableLocales = Array.from(available.menupopup.children);
+
+ is(
+ Services.locale.appLocaleAsBCP47,
+ "en-US",
+ "The app locale starts as English."
+ );
+
+ Assert.deepEqual(
+ Services.locale.requestedLocales,
+ ["en-US", "fr", "he", "de"],
+ "The locale order starts as what was initially requested."
+ );
+
+ let messageBar = doc.getElementById("confirmBrowserLanguage");
+ is(messageBar.hidden, true, "The message bar is hidden at first");
+
+ // English is LTR and Hebrew is RTL.
+ let hebrew = availableLocales.find(item => item.value == "he");
+
+ hebrew.click();
+ available.menupopup.hidePopup();
+
+ is(messageBar.hidden, true, "The message bar is still hidden");
+
+ is(
+ Services.locale.appLocaleAsBCP47,
+ "he",
+ "The app locale was changed to Hebrew."
+ );
+
+ Assert.deepEqual(
+ Services.locale.requestedLocales,
+ ["he", "en-US", "fr", "de"],
+ "The locale changed with Hebrew first."
+ );
+
+ await Promise.all(addons.map(addon => addon.uninstall()));
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ assertTelemetryRecorded([["reorder", "main"]]);
+});