diff options
Diffstat (limited to 'dom/l10n/tests/mochitest/document_l10n')
15 files changed, 765 insertions, 0 deletions
diff --git a/dom/l10n/tests/mochitest/document_l10n/README.txt b/dom/l10n/tests/mochitest/document_l10n/README.txt new file mode 100644 index 0000000000..b798a5039a --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/README.txt @@ -0,0 +1,3 @@ +Tests in this directory cover support for DocumentL10n +WebIDL API across different use cases such as +processes, principals and so on. diff --git a/dom/l10n/tests/mochitest/document_l10n/non-system-principal/README.txt b/dom/l10n/tests/mochitest/document_l10n/non-system-principal/README.txt new file mode 100644 index 0000000000..d0cc074166 --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/non-system-principal/README.txt @@ -0,0 +1,3 @@ +Tests in this directory cover the functionality +of DocumentL10n WebIDL API in non-system-principal +scenario. diff --git a/dom/l10n/tests/mochitest/document_l10n/non-system-principal/browser_resource_uri.js b/dom/l10n/tests/mochitest/document_l10n/non-system-principal/browser_resource_uri.js new file mode 100644 index 0000000000..a658e88bec --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/non-system-principal/browser_resource_uri.js @@ -0,0 +1,109 @@ +let uri = + "chrome://mochitests/content/browser/dom/l10n/tests/mochitest//document_l10n/non-system-principal/"; +let protocol = Services.io + .getProtocolHandler("resource") + .QueryInterface(Ci.nsIResProtocolHandler); + +protocol.setSubstitution("l10n-test", Services.io.newURI(uri)); + +// Since we want the mock source to work with all locales, we're going +// to register it for currently used locales, and we'll put the path that +// doesn't use the `{locale}` component to make it work irrelevant of +// what locale the mochitest is running in. +// +// Notice: we're using a `chrome://` protocol here only for convenience reasons. +// Real sources should use `resource://` protocol. +let locales = Services.locale.appLocalesAsBCP47; + +// This source is actually using a real `FileSource` instead of a mocked one, +// because we want to test that fetching real I/O out of the `uri` works in non-system-principal. +let source = new L10nFileSource("test", "app", locales, `${uri}localization/`); +L10nRegistry.getInstance().registerSources([source]); + +registerCleanupFunction(() => { + protocol.setSubstitution("l10n-test", null); + L10nRegistry.getInstance().removeSources(["test"]); + SpecialPowers.pushPrefEnv({ + set: [["dom.ipc.processPrelaunch.enabled", true]], + }); +}); + +const kChildPage = getRootDirectory(gTestPath) + "test.html"; + +const kAboutPagesRegistered = Promise.all([ + BrowserTestUtils.registerAboutPage( + registerCleanupFunction, + "test-about-l10n-child", + kChildPage, + Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD | + Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | + Ci.nsIAboutModule.ALLOW_SCRIPT + ), +]); + +add_task(async () => { + // Bug 1640333 - windows fails (sometimes) to ever get document.l10n.ready + // if e10s process caching is enabled + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.ipc.processPrelaunch.enabled", false], + ["dom.security.skip_about_page_has_csp_assert", true], + ], + }); + await kAboutPagesRegistered; + await BrowserTestUtils.withNewTab( + "about:test-about-l10n-child", + async browser => { + await SpecialPowers.spawn(browser, [], async function () { + let document = content.document; + let window = document.defaultView; + + await document.testsReadyPromise; + + let principal = SpecialPowers.wrap(document).nodePrincipal; + is( + principal.spec, + "about:test-about-l10n-child", + "correct content principal" + ); + + let desc = document.getElementById("main-desc"); + + // We can test here for a particular value because we're + // using a mock file source which is locale independent. + // + // If you're writing a test that verifies that a UI + // widget got real localization, you should not rely on + // the particular value, but rather on the content not + // being empty (to keep the test pass in non-en-US locales). + is(desc.textContent, "This is a mock page title"); + + // Test for l10n.getAttributes + let label = document.getElementById("label1"); + let l10nArgs = document.l10n.getAttributes(label); + is(l10nArgs.id, "subtitle"); + is(l10nArgs.args.name, "Firefox"); + + // Test for manual value formatting + let customMsg = document.getElementById("customMessage").textContent; + is(customMsg, "This is a custom message formatted from JS."); + + // Since we applied the `data-l10n-id` attribute + // on `label` in this microtask, we have to wait for + // the next paint to verify that the MutationObserver + // applied the translation. + await new Promise(resolve => { + let verifyL10n = () => { + if (!label.textContent.includes("Firefox")) { + window.requestAnimationFrame(verifyL10n); + } else { + resolve(); + } + }; + + window.requestAnimationFrame(verifyL10n); + }); + }); + } + ); +}); diff --git a/dom/l10n/tests/mochitest/document_l10n/non-system-principal/localization/test.ftl b/dom/l10n/tests/mochitest/document_l10n/non-system-principal/localization/test.ftl new file mode 100644 index 0000000000..a5da5a8f00 --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/non-system-principal/localization/test.ftl @@ -0,0 +1,4 @@ +page-title = This is a mock page title +subtitle = This is a label for { $name } + +custom-message = This is a custom message formatted from JS. diff --git a/dom/l10n/tests/mochitest/document_l10n/non-system-principal/test.html b/dom/l10n/tests/mochitest/document_l10n/non-system-principal/test.html new file mode 100644 index 0000000000..5d91f3da46 --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/non-system-principal/test.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test DocumentL10n in HTML environment</title> + <link rel="localization" href="test.ftl"/> + <script type="text/javascript"> + document.testsReadyPromise = new Promise((resolve) => { + // The test is in this file to ensure that we're testing + // the behavior in a non-system principal. + document.addEventListener("DOMContentLoaded", async () => { + await document.l10n.ready; + + // Assign the localization from JS + let label = document.getElementById("label1"); + document.l10n.setAttributes( + label, + "subtitle", + { + name: "Firefox", + } + ); + + const customMsg = await document.l10n.formatValue("custom-message"); + document.getElementById("customMessage").textContent = customMsg; + resolve(); + }, {once: true}); + }); + </script> +</head> +<body> + <h1 id="main-desc" data-l10n-id="page-title"></h1> + + <p id="label1"></p> + <p id="customMessage"></p> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_connectRoot_webcomponent.html b/dom/l10n/tests/mochitest/document_l10n/test_connectRoot_webcomponent.html new file mode 100644 index 0000000000..3f2def3547 --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_connectRoot_webcomponent.html @@ -0,0 +1,90 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test Web Component connecting into Document's l10n</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <link rel="localization" href="browser/preferences/preferences.ftl"></link> + <script type="application/javascript"> + SimpleTest.waitForExplicitFinish(); + + // In this test we are introducing two widgets. The only difference between them + // is that the first one is using `connectRoot` with the `aTranslate` argument set to `true`, + // and the other one to `false`. + // + // In this test, we will inject both of them into the DOM for parsing. + // For a test that verifies the behavior when they're injected lazily, see + // `test_connectRoot_webcomponent_lazy.html` test. + // + // Since both widgets get injected into DOM during parsing, we expect both of them + // to get translated before `document.l10n.ready` is resolved. + + let passedTests = 0; + + class FluentWidget extends HTMLElement { + constructor() { + super(); + const shadowRoot = this.attachShadow({mode: "open"}); + const t = document.querySelector("#fluent-widget-template"); + const instance = t.content.cloneNode(true); + shadowRoot.appendChild(instance); + } + async connectedCallback() { + MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl"); + + document.l10n.connectRoot(this.shadowRoot, true); + + let label = this.shadowRoot.getElementById("label"); + + await document.l10n.ready; + is(label.textContent, "Learn more", "localization content applied to element"); + passedTests++; + if (passedTests == 2) { + SimpleTest.finish(); + } + } + } + + class FluentWidget2 extends HTMLElement { + constructor() { + super(); + const shadowRoot = this.attachShadow({mode: "open"}); + const t = document.querySelector("#fluent-widget-template"); + const instance = t.content.cloneNode(true); + shadowRoot.appendChild(instance); + } + async connectedCallback() { + MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl"); + + document.l10n.connectRoot(this.shadowRoot, false); + + let label = this.shadowRoot.getElementById("label"); + + await document.l10n.ready; + is(label.textContent, "Learn more", "localization content applied to element"); + passedTests++; + if (passedTests == 2) { + SimpleTest.finish(); + } + } + } + + customElements.define("fluent-widget", FluentWidget); + customElements.define("fluent-widget2", FluentWidget2); + </script> +</head> +<body> + <template id="fluent-widget-template"> + <div> + <button id="label" data-l10n-id="do-not-track-learn-more"></button> + </div> + </template> + <fluent-widget></fluent-widget> + <fluent-widget2></fluent-widget2> + <script> + // This trick makes sure that we connect the widgets before parsing is completed. + document.write(""); + </script> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_connectRoot_webcomponent_lazy.html b/dom/l10n/tests/mochitest/document_l10n/test_connectRoot_webcomponent_lazy.html new file mode 100644 index 0000000000..b74bbc00c8 --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_connectRoot_webcomponent_lazy.html @@ -0,0 +1,98 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test Web Component connecting into Document's l10n</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <script type="application/javascript"> + SimpleTest.waitForExplicitFinish(); + + // In this test we are introducing two widgets. The only difference between them + // is that the first one is using `connectRoot` with the `aTranslate` argument set to `true`, + // and the other one to `false`. + // + // In this test, we will inject both of them lazily, after initial parsing is completed. + // For a test that verifies the behavior when they're injected during parsing, see + // `test_connectRoot_webcomponent.html` test. + // + // The expected difference is that when both get lazily injected into the DOM, the first one + // will get translated, while the other will not. + // The latter behavior will be used by widgets that will want to translate the initial DOM on their + // own before connecting the root. + + let firstWidgetTranslated = false; + + class FluentWidget extends HTMLElement { + constructor() { + super(); + const shadowRoot = this.attachShadow({mode: "open"}); + const t = document.querySelector("#fluent-widget-template"); + const instance = t.content.cloneNode(true); + shadowRoot.appendChild(instance); + } + connectedCallback() { + MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl"); + + document.l10n.connectRoot(this.shadowRoot, true); + + let label = this.shadowRoot.getElementById("label"); + + let verifyL10n = () => { + if (label.textContent.length) { + window.removeEventListener("MozAfterPaint", verifyL10n); + is(label.textContent, "Learn more", "localization content applied to element"); + firstWidgetTranslated = true; + } + }; + window.addEventListener("MozAfterPaint", verifyL10n); + } + } + + class FluentWidget2 extends HTMLElement { + constructor() { + super(); + const shadowRoot = this.attachShadow({mode: "open"}); + const t = document.querySelector("#fluent-widget-template"); + const instance = t.content.cloneNode(true); + shadowRoot.appendChild(instance); + } + connectedCallback() { + MozXULElement.insertFTLIfNeeded("browser/preferences/preferences.ftl"); + + document.l10n.connectRoot(this.shadowRoot, false); + + let label = this.shadowRoot.getElementById("label"); + + let verifyL10n = () => { + if (firstWidgetTranslated) { + is(label.textContent.length, 0, "This widget should remain untranslated."); + window.removeEventListener("MozAfterPaint", verifyL10n); + SimpleTest.finish(); + } + }; + window.addEventListener("MozAfterPaint", verifyL10n); + } + } + + customElements.define("fluent-widget", FluentWidget); + customElements.define("fluent-widget2", FluentWidget2); + + window.addEventListener("load", () => { + window.requestIdleCallback(async () => { + let widget = document.createElement("fluent-widget"); + document.body.appendChild(widget); + let widget2 = document.createElement("fluent-widget2"); + document.body.appendChild(widget2); + }); + }, { once: true }); + </script> +</head> +<body> + <template id="fluent-widget-template"> + <div> + <button id="label" data-l10n-id="do-not-track-learn-more"></button> + </div> + </template> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_docl10n.html b/dom/l10n/tests/mochitest/document_l10n/test_docl10n.html new file mode 100644 index 0000000000..12ff623f5c --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_docl10n.html @@ -0,0 +1,66 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test DocumentL10n in HTML environment</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <link rel="localization" href="crashreporter/aboutcrashes.ftl"/> + <script> + "use strict"; + SimpleTest.waitForExplicitFinish(); + + is(document.l10n.ready && document.l10n.ready.then !== undefined, true, + "document.l10n.ready exists and is a Promise"); + + (async function() { + await document.l10n.ready; + + const desc = document.getElementById("main-desc"); + is(!!desc.textContent.length, true, "initial localization is applied"); + + const msg = await document.l10n.formatValue("id-heading"); + is(!!msg.length, true, "value is formatted manually"); + + const label = document.getElementById("label1"); + let l10nArgs = document.l10n.getAttributes(label); + is(l10nArgs.id, null, "id is null if not set"); + + SimpleTest.doesThrow( + () => { + const bad = {}; + bad.bad = bad; + document.l10n.setAttributes(label, "date-crashed-heading", bad); + }, + "an error is thrown for invalid args", + ); + + l10nArgs = document.l10n.getAttributes(label); + is(l10nArgs.id, null, "id is not set if args are invalid"); + + document.l10n.setAttributes( + label, + "date-crashed-heading", + { + name: "John", + } + ); + ok(document.hasPendingL10nMutations, "Should have pending mutations"); + l10nArgs = document.l10n.getAttributes(label); + is(l10nArgs.id, "date-crashed-heading", "id is set by setAttributes"); + is(l10nArgs.args.name, "John", "args are set by setAttributes"); + // Test for mutations applied. + document.addEventListener("L10nMutationsFinished", function() { + ok(!!label.textContent.length, "Should've applied translation"); + ok(!document.hasPendingL10nMutations, "Should have no more pending mutations"); + SimpleTest.finish(); + }, { once: true }); + })(); + </script> +</head> +<body> + <h1 id="main-desc" data-l10n-id="crash-reports-title"></h1> + + <p id="label1"></p> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_docl10n.xhtml b/dom/l10n/tests/mochitest/document_l10n/test_docl10n.xhtml new file mode 100644 index 0000000000..2d51d8689e --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_docl10n.xhtml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<!DOCTYPE html> + +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta charset="utf-8"></meta> + <title>Test DocumentL10n in HTML environment</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"></link> + <link rel="localization" href="crashreporter/aboutcrashes.ftl"/> + <script type="application/javascript"> + "use strict"; + SimpleTest.waitForExplicitFinish(); + + document.addEventListener("DOMContentLoaded", async function() { + await document.l10n.ready; + + // Test for initial localization applied. + let desc = document.getElementById("main-desc"); + is(!!desc.textContent.length, true); + + // Test for manual value formatting + let msg = await document.l10n.formatValue("id-heading"); + is(!!msg.length, true); + + // Test for mutations applied. + let verifyL10n = () => { + if (label.textContent.length) { + window.removeEventListener("MozAfterPaint", verifyL10n); + SimpleTest.finish(); + } + }; + window.addEventListener("MozAfterPaint", verifyL10n); + + let label = document.getElementById("label1"); + document.l10n.setAttributes( + label, + "date-crashed-heading", + { + name: "John", + } + ); + + // Test for l10n.getAttributes + let l10nArgs = document.l10n.getAttributes(label); + is(l10nArgs.id, "date-crashed-heading"); + is(l10nArgs.args.name, "John"); + }, { once: true}); + </script> +</head> +<body> + <h1 id="main-desc" data-l10n-id="crash-reports-title"></h1> + + <p id="label1" /> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_docl10n_lazy.html b/dom/l10n/tests/mochitest/document_l10n/test_docl10n_lazy.html new file mode 100644 index 0000000000..6c3ddb73ed --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_docl10n_lazy.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test Lazy DocumentL10n in HTML environment</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <script type="application/javascript"> + "use strict"; + SimpleTest.waitForExplicitFinish(); + + is(document.l10n, null, "document.l10n is null."); + + window.addEventListener("load", async () => { + is(document.l10n, null, "document.l10n is null after load."); + + let desc = document.getElementById("main-desc"); + is(desc.textContent.length, 0, "main-desc is not translated"); + + let link = document.createElement("link"); + link.setAttribute("rel", "localization"); + link.setAttribute("href", "crashreporter/aboutcrashes.ftl"); + document.head.appendChild(link); + + // Verify now that `l10n.ready` exists and is fulfilled. + await document.l10n.ready; + + // Lazy initialized localization should translate the document. + is(!!desc.textContent.length, true, "main-desc is translated"); + + document.head.removeChild(link); + + is(document.l10n, null, "document.l10n is null"); + + SimpleTest.finish(); + }, { once: true}); + </script> +</head> +<body> + <h1 id="main-desc" data-l10n-id="crash-reports-title"></h1> + + <p id="label1"></p> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_docl10n_ready_rejected.html b/dom/l10n/tests/mochitest/document_l10n/test_docl10n_ready_rejected.html new file mode 100644 index 0000000000..63e18f802c --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_docl10n_ready_rejected.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test mozIDOMLocalization.ready rejected state</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <link rel="localization" href="path/to_non_existing.ftl"/> + <script type="application/javascript"> + "use strict"; + SimpleTest.waitForExplicitFinish(); + + document.addEventListener("DOMContentLoaded", async function() { + /** + * Even when we fail to localize all elements, we will + * still resolve the `ready` promise to communicate that + * the initial translation phase is now completed. + */ + document.l10n.ready.then(() => { + is(1, 1, "the ready should resolve"); + SimpleTest.finish(); + }); + }); + </script> +</head> +<body> + <h1 data-l10n-id="non-existing-id"></h1> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_docl10n_removeResourceIds.html b/dom/l10n/tests/mochitest/document_l10n/test_docl10n_removeResourceIds.html new file mode 100644 index 0000000000..8ccaa04614 --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_docl10n_removeResourceIds.html @@ -0,0 +1,59 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test DocumentL10n::RemoveResourceIds</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <link rel="localization" href="toolkit/about/aboutAddons.ftl"/> + <link rel="localization" href="toolkit/about/aboutSupport.ftl"/> + <script type="application/javascript"> + "use strict"; + /* eslint-disable mozilla/prefer-formatValues */ + + SimpleTest.waitForExplicitFinish(); + + window.onload = async function() { + { + // 1. An example message from aboutAddons should be available. + let value = await document.l10n.formatValue("shortcuts-browserAction2"); + is(!!value.length, true, "localized value retrieved"); + } + + { + // 2. Remove aboutAddons.ftl + let link = document.head.querySelector("link[href*=aboutAddons]"); + document.head.removeChild(link); + } + + { + // 3. An example message from aboutSupport should still be available. + let value = await document.l10n.formatValue("features-version"); + is(!!value.length, true, "localized value retrieved"); + + // 4. An example message from aboutAddons should not be available. + await document.l10n.formatValue("shortcuts-browserAction").then( + () => { + ok(false, "localization should not be available"); + }, + () => { + ok(true, "localization should not be available"); + }); + } + + { + // 5. Remove aboutSupport.ftl + let link = document.head.querySelector("link[href*=aboutSupport]"); + document.head.removeChild(link); + + // 6. document.l10n should be null. + is(document.l10n, null, "document.l10n should be null"); + + SimpleTest.finish(); + } + }; + </script> +</head> +<body> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_docl10n_sync.html b/dom/l10n/tests/mochitest/document_l10n/test_docl10n_sync.html new file mode 100644 index 0000000000..ea44d1afe1 --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_docl10n_sync.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html data-l10n-sync> +<head> + <meta charset="utf-8"> + <title>Test DocumentL10n in HTML environment</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <link rel="localization" href="crashreporter/aboutcrashes.ftl"/> + <script type="application/javascript"> + "use strict"; + SimpleTest.waitForExplicitFinish(); + + document.addEventListener("DOMContentLoaded", async function() { + await document.l10n.ready; + + // Test for initial localization applied. + let desc = document.getElementById("main-desc"); + is(!!desc.textContent.length, true); + + // Test for manual value formatting. + let msg = await document.l10n.formatValue("id-heading"); + is(!!msg.length, true); + + // Test for mutations applied. + let verifyL10n = () => { + if (label.textContent.length) { + window.removeEventListener("MozAfterPaint", verifyL10n); + SimpleTest.finish(); + } + }; + window.addEventListener("MozAfterPaint", verifyL10n); + + let label = document.getElementById("label1"); + document.l10n.setAttributes( + label, + "date-crashed-heading", + { + name: "John", + } + ); + + // Test for l10n.getAttributes + let l10nArgs = document.l10n.getAttributes(label); + is(l10nArgs.id, "date-crashed-heading"); + is(l10nArgs.args.name, "John"); + }, { once: true}); + </script> +</head> +<body> + <h1 id="main-desc" data-l10n-id="crash-reports-title"></h1> + + <p id="label1"></p> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_telemetry.html b/dom/l10n/tests/mochitest/document_l10n/test_telemetry.html new file mode 100644 index 0000000000..b528ebc7ea --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_telemetry.html @@ -0,0 +1,83 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test DocumentL10n Telemetry</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <script type="application/javascript"> + "use strict"; + const { BrowserTestUtils } = ChromeUtils.import( + "resource://testing-common/BrowserTestUtils.jsm" + ); + + SimpleTest.waitForExplicitFinish(); + + function countValues(snapshot, key) { + if (!snapshot.hasOwnProperty(key)) { + return 0; + } + let values = snapshot[key].values; + return Object.values(values).reduce((sum, n) => sum + n, 0); + } + + (async function() { + let histogram = Services.telemetry + .getKeyedHistogramById("L10N_DOCUMENT_INITIAL_TRANSLATION_TIME_US"); + let snapshot = histogram.snapshot(); + + // In some cases the test runs before first window is localized. + // We just want to ensure that we didn't register more than 1 + // first window telemetry. + let firstWindowCount = countValues(snapshot, "browser_first_window"); + is(firstWindowCount < 2, true); + + histogram.clear(); + + // Open a new window + let win = await BrowserTestUtils.openNewBrowserWindow({ + waitForTabURL: "about:blank", + }); + + // Telemetry in testing is flaky and when landing this test + // we saw cases where the snapshot did not contain the new + // window telemetry at this moment. + // + // We're going to use `waitForCondition` to test for + // the telemetry to be eventually recorded. + BrowserTestUtils.waitForCondition(() => { + snapshot = histogram.snapshot(); + + // We want to make sure that since we cleared histogram + // just one new window of either type has been opened. + let browserWindowsCount = + countValues(snapshot, "browser_new_window") + + countValues(snapshot, "browser_first_window"); + return browserWindowsCount == 1; + }); + + // Open preferences in a new tab + let tab = BrowserTestUtils.addTab( + win.gBrowser, + "about:preferences" + ); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + + // Similarly to the above, we've seen cases where the telemetry + // was not present right after the tab was opened, so + // we'll use `waitForCondition` here. + BrowserTestUtils.waitForCondition(() => { + snapshot = histogram.snapshot(); + + return countValues(snapshot, "about:preferences") == 1; + }); + + await BrowserTestUtils.closeWindow(win); + + SimpleTest.finish(); + })(); + </script> +</head> +<body> +</body> +</html> diff --git a/dom/l10n/tests/mochitest/document_l10n/test_unpriv_iframe.html b/dom/l10n/tests/mochitest/document_l10n/test_unpriv_iframe.html new file mode 100644 index 0000000000..4f4b29c500 --- /dev/null +++ b/dom/l10n/tests/mochitest/document_l10n/test_unpriv_iframe.html @@ -0,0 +1,26 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Ensure unprivilaged document cannot access document.l10n in an iframe</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <script type="application/javascript"> + "use strict"; + SimpleTest.waitForExplicitFinish(); + + addLoadEvent(function() { + let frame = document.getElementById("frame"); + let frame2 = document.getElementById("frame2"); + + is("l10n" in frame.contentDocument, false); + is("l10n" in frame2.contentDocument, false); + }); + addLoadEvent(SimpleTest.finish); + </script> +</head> +<body> + <iframe id="frame" src="about:blank"></iframe> + <iframe id="frame2" src="about:crashes"></iframe> +</body> +</html> |