From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../extensions/test/xpcshell/test_ext_i18n.js | 571 +++++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_i18n.js (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_i18n.js') diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_i18n.js b/toolkit/components/extensions/test/xpcshell/test_ext_i18n.js new file mode 100644 index 0000000000..048e675a3e --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_i18n.js @@ -0,0 +1,571 @@ +"use strict"; + +const { Preferences } = ChromeUtils.importESModule( + "resource://gre/modules/Preferences.sys.mjs" +); + +// ExtensionContent.jsm needs to know when it's running from xpcshell, +// to use the right timeout for content scripts executed at document_idle. +ExtensionTestUtils.mockAppInfo(); + +const server = createHttpServer(); +server.registerDirectory("/data/", do_get_file("data")); + +const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`; + +var originalReqLocales = Services.locale.requestedLocales; + +registerCleanupFunction(() => { + Preferences.reset("intl.accept_languages"); + Services.locale.requestedLocales = originalReqLocales; +}); + +add_task(async function test_i18n() { + function runTests(assertEq) { + let _ = browser.i18n.getMessage.bind(browser.i18n); + + let url = browser.runtime.getURL("/"); + assertEq( + url, + `moz-extension://${_("@@extension_id")}/`, + "@@extension_id builtin message" + ); + + assertEq("Foo.", _("Foo"), "Simple message in selected locale."); + + assertEq("(bar)", _("bar"), "Simple message fallback in default locale."); + + assertEq("", _("some-unknown-locale-string"), "Unknown locale string."); + + assertEq("", _("@@unknown_builtin_string"), "Unknown built-in string."); + assertEq( + "", + _("@@bidi_unknown_builtin_string"), + "Unknown built-in bidi string." + ); + + assertEq("Føo.", _("Föo"), "Multi-byte message in selected locale."); + + let substitutions = []; + substitutions[4] = "5"; + substitutions[13] = "14"; + + assertEq( + "'$0' '14' '' '5' '$$$$' '$'.", + _("basic_substitutions", substitutions), + "Basic numeric substitutions" + ); + + assertEq( + "'$0' '' 'just a string' '' '$$$$' '$'.", + _("basic_substitutions", "just a string"), + "Basic numeric substitutions, with non-array value" + ); + + let values = _("named_placeholder_substitutions", [ + "(subst $1 $2)", + "(2 $1 $2)", + ]).split("\n"); + + assertEq( + "_foo_ (subst $1 $2) _bar_", + values[0], + "Named and numeric substitution" + ); + + assertEq( + "(2 $1 $2)", + values[1], + "Numeric substitution amid named placeholders" + ); + + assertEq("$bad name$", values[2], "Named placeholder with invalid key"); + + assertEq("", values[3], "Named placeholder with an invalid value"); + + assertEq( + "Accepted, but shouldn't break.", + values[4], + "Named placeholder with a strange content value" + ); + + assertEq("$foo", values[5], "Non-placeholder token that should be ignored"); + } + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + default_locale: "jp", + + content_scripts: [ + { matches: ["http://*/*/file_sample.html"], js: ["content.js"] }, + ], + }, + + files: { + "_locales/en_US/messages.json": { + foo: { + message: "Foo.", + description: "foo", + }, + + föo: { + message: "Føo.", + description: "foo", + }, + + basic_substitutions: { + message: "'$0' '$14' '$1' '$5' '$$$$$' '$$'.", + description: "foo", + }, + + Named_placeholder_substitutions: { + message: + "$Foo$\n$2\n$bad name$\n$bad_value$\n$bad_content_value$\n$foo", + description: "foo", + placeholders: { + foO: { + content: "_foo_ $1 _bar_", + description: "foo", + }, + + "bad name": { + content: "Nope.", + description: "bad name", + }, + + bad_value: "Nope.", + + bad_content_value: { + content: ["Accepted, but shouldn't break."], + description: "bad value", + }, + }, + }, + + broken_placeholders: { + message: "$broken$", + description: "broken placeholders", + placeholders: "foo.", + }, + }, + + "_locales/jp/messages.json": { + foo: { + message: "(foo)", + description: "foo", + }, + + bar: { + message: "(bar)", + description: "bar", + }, + }, + + "content.js": + "new " + + function (runTestsFn) { + runTestsFn((...args) => { + browser.runtime.sendMessage(["assertEq", ...args]); + }); + + browser.runtime.sendMessage(["content-script-finished"]); + } + + `(${runTests})`, + }, + + background: + "new " + + function (runTestsFn) { + browser.runtime.onMessage.addListener(([msg, ...args]) => { + if (msg == "assertEq") { + browser.test.assertEq(...args); + } else { + browser.test.sendMessage(msg, ...args); + } + }); + + runTestsFn(browser.test.assertEq.bind(browser.test)); + } + + `(${runTests})`, + }); + + await extension.startup(); + + let contentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/file_sample.html` + ); + await extension.awaitMessage("content-script-finished"); + await contentPage.close(); + + await extension.unload(); +}); + +add_task(async function test_i18n_negotiation() { + function runTests(expected) { + let _ = browser.i18n.getMessage.bind(browser.i18n); + + browser.test.assertEq(expected, _("foo"), "Got expected message"); + } + + let extensionData = { + manifest: { + default_locale: "en_US", + + content_scripts: [ + { matches: ["http://*/*/file_sample.html"], js: ["content.js"] }, + ], + }, + + files: { + "_locales/en_US/messages.json": { + foo: { + message: "English.", + description: "foo", + }, + }, + + "_locales/jp/messages.json": { + foo: { + message: "\u65e5\u672c\u8a9e", + description: "foo", + }, + }, + + "content.js": + "new " + + function (runTestsFn) { + browser.test.onMessage.addListener(expected => { + runTestsFn(expected); + + browser.test.sendMessage("content-script-finished"); + }); + browser.test.sendMessage("content-ready"); + } + + `(${runTests})`, + }, + + background: + "new " + + function (runTestsFn) { + browser.test.onMessage.addListener(expected => { + runTestsFn(expected); + + browser.test.sendMessage("background-script-finished"); + }); + } + + `(${runTests})`, + }; + + // At the moment extension language negotiation is tied to Firefox language + // negotiation result. That means that to test an extension in `fr`, we need + // to mock `fr` being available in Firefox and then request it. + // + // In the future, we should provide some way for tests to decouple their + // language selection from that of Firefox. + Services.locale.availableLocales = ["en-US", "fr", "jp"]; + + let contentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/file_sample.html` + ); + + for (let [lang, msg] of [ + ["en-US", "English."], + ["jp", "\u65e5\u672c\u8a9e"], + ]) { + Services.locale.requestedLocales = [lang]; + + let extension = ExtensionTestUtils.loadExtension(extensionData); + await extension.startup(); + await extension.awaitMessage("content-ready"); + + extension.sendMessage(msg); + await extension.awaitMessage("background-script-finished"); + await extension.awaitMessage("content-script-finished"); + + await extension.unload(); + } + Services.locale.requestedLocales = originalReqLocales; + + await contentPage.close(); +}); + +add_task(async function test_get_accept_languages() { + function checkResults(source, results, expected) { + browser.test.assertEq( + expected.length, + results.length, + `got expected number of languages in ${source}` + ); + results.forEach((lang, index) => { + browser.test.assertEq( + expected[index], + lang, + `got expected language in ${source}` + ); + }); + } + + function background(checkResultsFn) { + browser.test.onMessage.addListener(([msg, expected]) => { + browser.i18n.getAcceptLanguages().then(results => { + checkResultsFn("background", results, expected); + + browser.test.sendMessage("background-done"); + }); + }); + } + + function content(checkResultsFn) { + browser.test.onMessage.addListener(([msg, expected]) => { + browser.i18n.getAcceptLanguages().then(results => { + checkResultsFn("contentScript", results, expected); + + browser.test.sendMessage("content-done"); + }); + }); + browser.test.sendMessage("content-loaded"); + } + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://*/*/file_sample.html"], + run_at: "document_start", + js: ["content_script.js"], + }, + ], + }, + + background: `(${background})(${checkResults})`, + + files: { + "content_script.js": `(${content})(${checkResults})`, + }, + }); + + let contentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/file_sample.html` + ); + + await extension.startup(); + await extension.awaitMessage("content-loaded"); + + // TODO bug 1765375: ", en" is missing on Android. + let expectedLangs = + AppConstants.platform == "android" ? ["en-US"] : ["en-US", "en"]; + extension.sendMessage(["expect-results", expectedLangs]); + await extension.awaitMessage("background-done"); + await extension.awaitMessage("content-done"); + + expectedLangs = ["en-US", "en", "fr-CA", "fr"]; + Preferences.set("intl.accept_languages", expectedLangs.toString()); + extension.sendMessage(["expect-results", expectedLangs]); + await extension.awaitMessage("background-done"); + await extension.awaitMessage("content-done"); + Preferences.reset("intl.accept_languages"); + + await contentPage.close(); + + await extension.unload(); +}); + +add_task(async function test_get_ui_language() { + function getResults() { + return { + getUILanguage: browser.i18n.getUILanguage(), + getMessage: browser.i18n.getMessage("@@ui_locale"), + }; + } + + function checkResults(source, results, expected) { + browser.test.assertEq( + expected, + results.getUILanguage, + `Got expected getUILanguage result in ${source}` + ); + browser.test.assertEq( + expected, + results.getMessage, + `Got expected getMessage result in ${source}` + ); + } + + function background(getResultsFn, checkResultsFn) { + browser.test.onMessage.addListener(([msg, expected]) => { + checkResultsFn("background", getResultsFn(), expected); + + browser.test.sendMessage("background-done"); + }); + } + + function content(getResultsFn, checkResultsFn) { + browser.test.onMessage.addListener(([msg, expected]) => { + checkResultsFn("contentScript", getResultsFn(), expected); + + browser.test.sendMessage("content-done"); + }); + browser.test.sendMessage("content-loaded"); + } + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://*/*/file_sample.html"], + run_at: "document_start", + js: ["content_script.js"], + }, + ], + }, + + background: `(${background})(${getResults}, ${checkResults})`, + + files: { + "content_script.js": `(${content})(${getResults}, ${checkResults})`, + }, + }); + + let contentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/file_sample.html` + ); + + await extension.startup(); + await extension.awaitMessage("content-loaded"); + + extension.sendMessage(["expect-results", "en-US"]); + + await extension.awaitMessage("background-done"); + await extension.awaitMessage("content-done"); + + // We don't currently have a good way to mock this. + if (false) { + Services.locale.requestedLocales = ["he"]; + + extension.sendMessage(["expect-results", "he"]); + + await extension.awaitMessage("background-done"); + await extension.awaitMessage("content-done"); + } + + await contentPage.close(); + + await extension.unload(); +}); + +add_task(async function test_detect_language() { + const af_string = + " aam skukuza die naam beteken hy wat skoonvee of hy wat alles onderstebo keer wysig " + + "bosveldkampe boskampe is kleiner afgeleë ruskampe wat oor min fasiliteite beskik daar is geen restaurante " + + "of winkels nie en slegs oornagbesoekers word toegelaat bateleur"; + // String with intermixed French/English text + const fr_en_string = + "France is the largest country in Western Europe and the third-largest in Europe as a whole. " + + "A accès aux chiens et aux frontaux qui lui ont été il peut consulter et modifier ses collections et exporter " + + "Cet article concerne le pays européen aujourd’hui appelé République française. Pour d’autres usages du nom France, " + + "Pour une aide rapide et effective, veuiller trouver votre aide dans le menu ci-dessus." + + "Motoring events began soon after the construction of the first successful gasoline-fueled automobiles. The quick brown fox jumped over the lazy dog"; + + function checkResult(source, result, expected) { + browser.test.assertEq( + expected.isReliable, + result.isReliable, + "result.confident is true" + ); + browser.test.assertEq( + expected.languages.length, + result.languages.length, + `result.languages contains the expected number of languages in ${source}` + ); + expected.languages.forEach((lang, index) => { + browser.test.assertEq( + lang.percentage, + result.languages[index].percentage, + `element ${index} of result.languages array has the expected percentage in ${source}` + ); + browser.test.assertEq( + lang.language, + result.languages[index].language, + `element ${index} of result.languages array has the expected language in ${source}` + ); + }); + } + + function backgroundScript(checkResultFn) { + browser.test.onMessage.addListener(([msg, expected]) => { + browser.i18n.detectLanguage(msg).then(result => { + checkResultFn("background", result, expected); + browser.test.sendMessage("background-done"); + }); + }); + } + + function content(checkResultFn) { + browser.test.onMessage.addListener(([msg, expected]) => { + browser.i18n.detectLanguage(msg).then(result => { + checkResultFn("contentScript", result, expected); + browser.test.sendMessage("content-done"); + }); + }); + browser.test.sendMessage("content-loaded"); + } + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://*/*/file_sample.html"], + run_at: "document_start", + js: ["content_script.js"], + }, + ], + }, + + background: `(${backgroundScript})(${checkResult})`, + + files: { + "content_script.js": `(${content})(${checkResult})`, + }, + }); + + let contentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/file_sample.html` + ); + + await extension.startup(); + await extension.awaitMessage("content-loaded"); + + let expected = { + isReliable: true, + languages: [ + { + language: "fr", + percentage: 67, + }, + { + language: "en", + percentage: 32, + }, + ], + }; + extension.sendMessage([fr_en_string, expected]); + await extension.awaitMessage("background-done"); + await extension.awaitMessage("content-done"); + + expected = { + isReliable: true, + languages: [ + { + language: "af", + percentage: 99, + }, + ], + }; + extension.sendMessage([af_string, expected]); + await extension.awaitMessage("background-done"); + await extension.awaitMessage("content-done"); + + await contentPage.close(); + + await extension.unload(); +}); -- cgit v1.2.3