Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

"use strict";
const { Preferences } = ChromeUtils.importESModule(
);
// ExtensionContent.sys.mjs 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(([, expected]) => {
browser.i18n.getAcceptLanguages().then(results => {
checkResultsFn("background", results, expected);
browser.test.sendMessage("background-done");
});
});
}
function content(checkResultsFn) {
browser.test.onMessage.addListener(([, 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: [
{
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(([, expected]) => {
checkResultsFn("background", getResultsFn(), expected);
browser.test.sendMessage("background-done");
});
}
function content(getResultsFn, checkResultsFn) {
browser.test.onMessage.addListener(([, expected]) => {
checkResultsFn("contentScript", getResultsFn(), expected);
browser.test.sendMessage("content-done");
});
browser.test.sendMessage("content-loaded");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
content_scripts: [
{
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: [
{
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();
});