diff options
Diffstat (limited to 'browser/components/urlbar/tests/ext/browser')
9 files changed, 532 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/ext/browser/.eslintrc.js b/browser/components/urlbar/tests/ext/browser/.eslintrc.js new file mode 100644 index 0000000000..e57058ecb1 --- /dev/null +++ b/browser/components/urlbar/tests/ext/browser/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + env: { + webextensions: true, + }, +}; diff --git a/browser/components/urlbar/tests/ext/browser/browser.ini b/browser/components/urlbar/tests/ext/browser/browser.ini new file mode 100644 index 0000000000..416fc52eb3 --- /dev/null +++ b/browser/components/urlbar/tests/ext/browser/browser.ini @@ -0,0 +1,18 @@ +# 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/. + +[DEFAULT] +support-files = + ../../browser/head-common.js + ../api.js + ../schema.json + head.js + +[browser_ext_urlbar_attributionURL.js] +[browser_ext_urlbar_clearInput.js] +[browser_ext_urlbar_dynamicResult.js] +support-files = + dynamicResult.css +[browser_ext_urlbar_engagementTelemetry.js] +[browser_ext_urlbar_extensionTimeout.js] diff --git a/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_attributionURL.js b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_attributionURL.js new file mode 100644 index 0000000000..a5bccc8eba --- /dev/null +++ b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_attributionURL.js @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* global browser */ + +// This tests the browser.experiments.urlbar.engagementTelemetry WebExtension +// Experiment API. + +"use strict"; + +add_settings_tasks("browser.partnerlink.attributionURL", "string", () => { + browser.test.onMessage.addListener(async (method, arg) => { + let result = await browser.experiments.urlbar.attributionURL[method](arg); + browser.test.sendMessage("done", result); + }); +}); diff --git a/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_clearInput.js b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_clearInput.js new file mode 100644 index 0000000000..afeff3b8a1 --- /dev/null +++ b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_clearInput.js @@ -0,0 +1,31 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* global browser */ + +// This tests the browser.experiments.urlbar.clearInput WebExtension Experiment +// API. + +"use strict"; + +add_task(async function test() { + // Load a page so that pageproxystate is valid. When the extension calls + // clearInput, the pageproxystate should become invalid. + await BrowserTestUtils.withNewTab("http://example.com/", async () => { + Assert.notEqual(gURLBar.value, "", "Input is not empty"); + Assert.equal(gURLBar.getAttribute("pageproxystate"), "valid"); + + let ext = await loadExtension({ + background: async () => { + await browser.experiments.urlbar.clearInput(); + browser.test.sendMessage("done"); + }, + }); + await ext.awaitMessage("done"); + + Assert.equal(gURLBar.value, "", "Input is empty"); + Assert.equal(gURLBar.getAttribute("pageproxystate"), "invalid"); + + await ext.unload(); + }); +}); diff --git a/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_dynamicResult.js b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_dynamicResult.js new file mode 100644 index 0000000000..a710d8949d --- /dev/null +++ b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_dynamicResult.js @@ -0,0 +1,137 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* global browser */ + +// This tests dynamic results using the WebExtension Experiment API. + +"use strict"; + +add_task(async function test() { + let ext = await loadExtension({ + extraFiles: { + "dynamicResult.css": await ( + await fetch("file://" + getTestFilePath("dynamicResult.css")) + ).text(), + }, + background: async () => { + browser.experiments.urlbar.addDynamicResultType("testDynamicType"); + browser.experiments.urlbar.addDynamicViewTemplate("testDynamicType", { + stylesheet: "dynamicResult.css", + children: [ + { + name: "text", + tag: "span", + }, + { + name: "button", + tag: "span", + attributes: { + role: "button", + }, + }, + ], + }); + browser.urlbar.onBehaviorRequested.addListener(query => { + return "restricting"; + }, "test"); + browser.urlbar.onResultsRequested.addListener(query => { + return [ + { + type: "dynamic", + source: "local", + heuristic: true, + payload: { + dynamicType: "testDynamicType", + }, + }, + ]; + }, "test"); + browser.experiments.urlbar.onViewUpdateRequested.addListener(payload => { + return { + text: { + textContent: "This is a dynamic result.", + }, + button: { + textContent: "Click Me", + }, + }; + }, "test"); + browser.urlbar.onResultPicked.addListener((payload, elementName) => { + browser.test.sendMessage("onResultPicked", [payload, elementName]); + }, "test"); + }, + }); + + // Wait for the provider and dynamic type to be registered before continuing. + await TestUtils.waitForCondition( + () => + UrlbarProvidersManager.getProvider("test") && + UrlbarResult.getDynamicResultType("testDynamicType"), + "Waiting for provider and dynamic type to be registered" + ); + Assert.ok( + UrlbarProvidersManager.getProvider("test"), + "Provider should be registered" + ); + Assert.ok( + UrlbarResult.getDynamicResultType("testDynamicType"), + "Dynamic type should be registered" + ); + + // Do a search. + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: "test", + waitForFocus: SimpleTest.waitForFocus, + }); + + // Get the row. + let row = await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0); + Assert.equal( + row.result.type, + UrlbarUtils.RESULT_TYPE.DYNAMIC, + "row.result.type" + ); + Assert.equal( + row.getAttribute("dynamicType"), + "testDynamicType", + "row[dynamicType]" + ); + + let text = row.querySelector(".urlbarView-dynamic-testDynamicType-text"); + + // The view's call to provider.getViewUpdate is async, so we need to make sure + // the update has been applied before continuing to avoid intermittent + // failures. + await TestUtils.waitForCondition( + () => text.textContent == "This is a dynamic result." + ); + + // Check the elements. + Assert.equal( + text.textContent, + "This is a dynamic result.", + "text.textContent" + ); + let button = row.querySelector(".urlbarView-dynamic-testDynamicType-button"); + Assert.equal(button.textContent, "Click Me", "button.textContent"); + + // The result's button should be selected since the result is the heuristic. + Assert.equal( + UrlbarTestUtils.getSelectedElement(window), + button, + "Button should be selected" + ); + + // Pick the button. + let pickPromise = ext.awaitMessage("onResultPicked"); + await UrlbarTestUtils.promisePopupClose(window, () => + EventUtils.synthesizeKey("KEY_Enter") + ); + let [payload, elementName] = await pickPromise; + Assert.equal(payload.dynamicType, "testDynamicType", "Picked payload"); + Assert.equal(elementName, "button", "Picked element name"); + + await ext.unload(); +}); diff --git a/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_engagementTelemetry.js b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_engagementTelemetry.js new file mode 100644 index 0000000000..50ded14d4e --- /dev/null +++ b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_engagementTelemetry.js @@ -0,0 +1,18 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* global browser */ + +// This tests the browser.experiments.urlbar.engagementTelemetry WebExtension +// Experiment API. + +"use strict"; + +add_settings_tasks("browser.urlbar.eventTelemetry.enabled", "boolean", () => { + browser.test.onMessage.addListener(async (method, arg) => { + let result = await browser.experiments.urlbar.engagementTelemetry[method]( + arg + ); + browser.test.sendMessage("done", result); + }); +}); diff --git a/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_extensionTimeout.js b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_extensionTimeout.js new file mode 100644 index 0000000000..de09ef263c --- /dev/null +++ b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_extensionTimeout.js @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* global browser */ + +// This tests the browser.experiments.urlbar.engagementTelemetry WebExtension +// Experiment API. + +"use strict"; + +add_settings_tasks("browser.urlbar.extension.timeout", "number", () => { + browser.test.onMessage.addListener(async (method, arg) => { + let result = await browser.experiments.urlbar.extensionTimeout[method](arg); + browser.test.sendMessage("done", result); + }); +}); diff --git a/browser/components/urlbar/tests/ext/browser/dynamicResult.css b/browser/components/urlbar/tests/ext/browser/dynamicResult.css new file mode 100644 index 0000000000..efd0c8c950 --- /dev/null +++ b/browser/components/urlbar/tests/ext/browser/dynamicResult.css @@ -0,0 +1,36 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +.urlbarView-row[dynamicType=testDynamicType] > .urlbarView-row-inner { + display: flex; + align-items: center; + min-height: 32px; + width: 100%; +} + +.urlbarView-dynamic-testDynamicType-text { + flex-grow: 1; + flex-shrink: 1; + padding: 10px; +} + +.urlbarView-dynamic-testDynamicType-button { + min-height: 16px; + padding: 8px; + border: none; + border-radius: 2px; + font-size: 0.93em; + color: inherit; + background-color: var(--urlbarView-button-background); + min-width: 8.75em; + text-align: center; + flex-basis: initial; + flex-shrink: 0; + margin-inline-end: 10px; +} + +.urlbarView-dynamic-testDynamicType-button[selected] { + color: white; + background-color: var(--urlbarView-primary-button-background); + box-shadow: 0 0 0 1px #0a84ff inset, 0 0 0 1px #0a84ff, 0 0 0 4px rgba(10, 132, 255, 0.3); +} diff --git a/browser/components/urlbar/tests/ext/browser/head.js b/browser/components/urlbar/tests/ext/browser/head.js new file mode 100644 index 0000000000..8d11a88066 --- /dev/null +++ b/browser/components/urlbar/tests/ext/browser/head.js @@ -0,0 +1,253 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * The files in this directory test the browser.urlbarExperiments WebExtension + * Experiment APIs, which are the WebExtension APIs we ship in our urlbar + * experiment extensions. Unlike the WebExtension APIs we ship in mozilla- + * central, which have continuous test coverage [1], our WebExtension Experiment + * APIs would not have continuous test coverage were it not for the fact that we + * copy and test them here. This is especially useful for APIs that are used in + * experiments that target multiple versions of Firefox, and for APIs that are + * reused in multiple experiments. See [2] and [3] for more info on + * experiments. + * + * [1] See browser/components/extensions/test + * [2] browser/components/urlbar/docs/experiments.rst + * [3] https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/basics.html#webextensions-experiments + */ + +"use strict"; + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/browser/components/urlbar/tests/browser/head-common.js", + this +); + +ChromeUtils.defineESModuleGetters(this, { + Preferences: "resource://gre/modules/Preferences.sys.mjs", +}); + +const SCHEMA_BASENAME = "schema.json"; +const SCRIPT_BASENAME = "api.js"; + +const SCHEMA_PATH = getTestFilePath(SCHEMA_BASENAME); +const SCRIPT_PATH = getTestFilePath(SCRIPT_BASENAME); + +let schemaSource; +let scriptSource; + +add_setup(async function loadSource() { + schemaSource = await (await fetch("file://" + SCHEMA_PATH)).text(); + scriptSource = await (await fetch("file://" + SCRIPT_PATH)).text(); +}); + +/** + * Loads a mock extension with our browser.experiments.urlbar API and a + * background script. Be sure to call `await ext.unload()` when you're done + * with it. + * + * @param {object} options + * Options object + * @param {Function} options.background + * This function is serialized and becomes the background script. + * @param {object} [options.extraFiles] + * Extra files to load in the extension. + * @returns {object} + * The extension. + */ +async function loadExtension({ background, extraFiles = {} }) { + let ext = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["urlbar"], + experiment_apis: { + experiments_urlbar: { + schema: SCHEMA_BASENAME, + parent: { + scopes: ["addon_parent"], + paths: [["experiments", "urlbar"]], + script: SCRIPT_BASENAME, + }, + }, + }, + }, + files: { + [SCHEMA_BASENAME]: schemaSource, + [SCRIPT_BASENAME]: scriptSource, + ...extraFiles, + }, + isPrivileged: true, + background, + }); + await ext.startup(); + return ext; +} + +/** + * Tests toggling a preference value via an experiments.urlbar API. + * + * @param {string} prefName + * The name of the pref to be tested. + * @param {string} type + * The type of the pref being set. One of "string", "boolean", or "number". + * @param {Function} background + * Boilerplate function that returns the value from calling the + * browser.experiments.urlbar.prefName[method] APIs. + */ +function add_settings_tasks(prefName, type, background) { + let defaultPreferences = new Preferences({ defaultBranch: true }); + + let originalValue = defaultPreferences.get(prefName); + registerCleanupFunction(() => { + defaultPreferences.set(prefName, originalValue); + }); + + let firstValue, secondValue; + switch (type) { + case "string": + firstValue = "test value 1"; + secondValue = "test value 2"; + break; + case "number": + firstValue = 10; + secondValue = 100; + break; + case "boolean": + firstValue = false; + secondValue = true; + break; + default: + Assert.ok( + false, + `"type" parameter must be one of "string", "number", or "boolean"` + ); + } + + add_task(async function get() { + let ext = await loadExtension({ background }); + + defaultPreferences.set(prefName, firstValue); + ext.sendMessage("get", {}); + let result = await ext.awaitMessage("done"); + Assert.strictEqual(result.value, firstValue); + + defaultPreferences.set(prefName, secondValue); + ext.sendMessage("get", {}); + result = await ext.awaitMessage("done"); + Assert.strictEqual(result.value, secondValue); + + await ext.unload(); + }); + + add_task(async function set() { + let ext = await loadExtension({ background }); + + defaultPreferences.set(prefName, firstValue); + ext.sendMessage("set", { value: secondValue }); + let result = await ext.awaitMessage("done"); + Assert.strictEqual(result, true); + Assert.strictEqual(defaultPreferences.get(prefName), secondValue); + + ext.sendMessage("set", { value: firstValue }); + result = await ext.awaitMessage("done"); + Assert.strictEqual(result, true); + Assert.strictEqual(defaultPreferences.get(prefName), firstValue); + + await ext.unload(); + }); + + add_task(async function clear() { + // no set() + defaultPreferences.set(prefName, firstValue); + let ext = await loadExtension({ background }); + ext.sendMessage("clear", {}); + let result = await ext.awaitMessage("done"); + Assert.strictEqual(result, false); + Assert.strictEqual(defaultPreferences.get(prefName), firstValue); + await ext.unload(); + + // firstValue -> secondValue + defaultPreferences.set(prefName, firstValue); + ext = await loadExtension({ background }); + ext.sendMessage("set", { value: secondValue }); + await ext.awaitMessage("done"); + ext.sendMessage("clear", {}); + result = await ext.awaitMessage("done"); + Assert.strictEqual(result, true); + Assert.strictEqual(defaultPreferences.get(prefName), firstValue); + await ext.unload(); + + // secondValue -> firstValue + defaultPreferences.set(prefName, secondValue); + ext = await loadExtension({ background }); + ext.sendMessage("set", { value: firstValue }); + await ext.awaitMessage("done"); + ext.sendMessage("clear", {}); + result = await ext.awaitMessage("done"); + Assert.strictEqual(result, true); + Assert.strictEqual(defaultPreferences.get(prefName), secondValue); + await ext.unload(); + + // firstValue -> firstValue + defaultPreferences.set(prefName, firstValue); + ext = await loadExtension({ background }); + ext.sendMessage("set", { value: firstValue }); + await ext.awaitMessage("done"); + ext.sendMessage("clear", {}); + result = await ext.awaitMessage("done"); + Assert.strictEqual(result, true); + Assert.strictEqual(defaultPreferences.get(prefName), firstValue); + await ext.unload(); + + // secondValue -> secondValue + defaultPreferences.set(prefName, secondValue); + ext = await loadExtension({ background }); + ext.sendMessage("set", { value: secondValue }); + await ext.awaitMessage("done"); + ext.sendMessage("clear", {}); + result = await ext.awaitMessage("done"); + Assert.strictEqual(result, true); + Assert.strictEqual(defaultPreferences.get(prefName), secondValue); + await ext.unload(); + }); + + add_task(async function shutdown() { + // no set() + defaultPreferences.set(prefName, firstValue); + let ext = await loadExtension({ background }); + await ext.unload(); + Assert.strictEqual(defaultPreferences.get(prefName), firstValue); + + // firstValue -> secondValue + defaultPreferences.set(prefName, firstValue); + ext = await loadExtension({ background }); + ext.sendMessage("set", { value: secondValue }); + await ext.awaitMessage("done"); + await ext.unload(); + Assert.strictEqual(defaultPreferences.get(prefName), firstValue); + + // secondValue -> firstValue + defaultPreferences.set(prefName, secondValue); + ext = await loadExtension({ background }); + ext.sendMessage("set", { value: firstValue }); + await ext.awaitMessage("done"); + await ext.unload(); + Assert.strictEqual(defaultPreferences.get(prefName), secondValue); + + // firstValue -> firstValue + defaultPreferences.set(prefName, firstValue); + ext = await loadExtension({ background }); + ext.sendMessage("set", { value: firstValue }); + await ext.awaitMessage("done"); + await ext.unload(); + Assert.strictEqual(defaultPreferences.get(prefName), firstValue); + + // secondValue -> secondValue + defaultPreferences.set(prefName, secondValue); + ext = await loadExtension({ background }); + ext.sendMessage("set", { value: secondValue }); + await ext.awaitMessage("done"); + await ext.unload(); + Assert.strictEqual(defaultPreferences.get(prefName), secondValue); + }); +} |