gecko-dev/toolkit/components/extensions/test/xpcshell/test_ext_i18n.js
Kris Maglione e930b89c34 Bug 1514594: Part 3 - Change ChromeUtils.import API.
***
Bug 1514594: Part 3a - Change ChromeUtils.import to return an exports object; not pollute global. r=mccr8

This changes the behavior of ChromeUtils.import() to return an exports object,
rather than a module global, in all cases except when `null` is passed as a
second argument, and changes the default behavior not to pollute the global
scope with the module's exports. Thus, the following code written for the old
model:

  ChromeUtils.import("resource://gre/modules/Services.jsm");

is approximately the same as the following, in the new model:

  var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");

Since the two behaviors are mutually incompatible, this patch will land with a
scripted rewrite to update all existing callers to use the new model rather
than the old.
***
Bug 1514594: Part 3b - Mass rewrite all JS code to use the new ChromeUtils.import API. rs=Gijs

This was done using the followng script:

https://bitbucket.org/kmaglione/m-c-rewrites/src/tip/processors/cu-import-exports.jsm
***
Bug 1514594: Part 3c - Update ESLint plugin for ChromeUtils.import API changes. r=Standard8

Differential Revision: https://phabricator.services.mozilla.com/D16747
***
Bug 1514594: Part 3d - Remove/fix hundreds of duplicate imports from sync tests. r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D16748
***
Bug 1514594: Part 3e - Remove no-op ChromeUtils.import() calls. r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D16749
***
Bug 1514594: Part 3f.1 - Cleanup various test corner cases after mass rewrite. r=Gijs
***
Bug 1514594: Part 3f.2 - Cleanup various non-test corner cases after mass rewrite. r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D16750

--HG--
extra : rebase_source : 359574ee3064c90f33bf36c2ebe3159a24cc8895
extra : histedit_source : b93c8f42808b1599f9122d7842d2c0b3e656a594%2C64a3a4e3359dc889e2ab2b49461bab9e27fc10a7
2019-01-17 10:18:31 -08:00

507 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
// 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");
let expectedLangs = ["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() {
if (AppConstants.MOZ_BUILD_APP !== "browser") {
// This is not supported on Android.
return;
}
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 aujourdhui appelé République française. Pour dautres 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();
});