summaryrefslogtreecommitdiffstats
path: root/browser/components/extensions/test/xpcshell/test_ext_urlbar.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/extensions/test/xpcshell/test_ext_urlbar.js')
-rw-r--r--browser/components/extensions/test/xpcshell/test_ext_urlbar.js1506
1 files changed, 1506 insertions, 0 deletions
diff --git a/browser/components/extensions/test/xpcshell/test_ext_urlbar.js b/browser/components/extensions/test/xpcshell/test_ext_urlbar.js
new file mode 100644
index 0000000000..94c370630d
--- /dev/null
+++ b/browser/components/extensions/test/xpcshell/test_ext_urlbar.js
@@ -0,0 +1,1506 @@
+"use strict";
+
+const { AddonTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/AddonTestUtils.sys.mjs"
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs",
+ SearchTestUtils: "resource://testing-common/SearchTestUtils.sys.mjs",
+ UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
+ UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.sys.mjs",
+ UrlbarQueryContext: "resource:///modules/UrlbarUtils.sys.mjs",
+ UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs",
+});
+
+ChromeUtils.defineLazyGetter(this, "UrlbarTestUtils", () => {
+ const { UrlbarTestUtils: module } = ChromeUtils.importESModule(
+ "resource://testing-common/UrlbarTestUtils.sys.mjs"
+ );
+ module.init(this);
+ return module;
+});
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "1",
+ "42"
+);
+SearchTestUtils.init(this);
+SearchTestUtils.initXPCShellAddonManager(this, "system");
+
+function promiseUninstallCompleted(extensionId) {
+ return new Promise(resolve => {
+ // eslint-disable-next-line mozilla/balanced-listeners
+ ExtensionParent.apiManager.on("uninstall-complete", (type, { id }) => {
+ if (id === extensionId) {
+ executeSoon(resolve);
+ }
+ });
+ });
+}
+
+function getPayload(result) {
+ let payload = {};
+ for (let [key, value] of Object.entries(result.payload)) {
+ if (value !== undefined) {
+ payload[key] = value;
+ }
+ }
+ return payload;
+}
+
+add_task(async function startup() {
+ Services.prefs.setCharPref("browser.search.region", "US");
+ Services.prefs.setIntPref("browser.search.addonLoadTimeout", 0);
+ Services.prefs.setBoolPref(
+ "browser.search.separatePrivateDefault.ui.enabled",
+ false
+ );
+ // Set the notification timeout to a really high value to avoid intermittent
+ // failures due to the mock extensions not responding in time.
+ Services.prefs.setIntPref("browser.urlbar.extension.timeout", 5000);
+
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("browser.urlbar.extension.timeout");
+ });
+
+ await AddonTestUtils.promiseStartupManager();
+
+ // Add a test engine and make it default so that when we do searches below,
+ // Firefox doesn't try to include search suggestions from the actual default
+ // engine from over the network.
+ await SearchTestUtils.installSearchExtension(
+ {
+ name: "Test engine",
+ keyword: "@testengine",
+ search_url_get_params: "s={searchTerms}",
+ },
+ { setAsDefault: true }
+ );
+});
+
+// Extensions must specify the "urlbar" permission to use browser.urlbar.
+add_task(async function test_urlbar_without_urlbar_permission() {
+ let ext = ExtensionTestUtils.loadExtension({
+ isPrivileged: true,
+ background() {
+ browser.test.assertEq(
+ browser.urlbar,
+ undefined,
+ "'urlbar' permission is required"
+ );
+ },
+ });
+ await ext.startup();
+ await ext.unload();
+});
+
+// Extensions must be privileged to use browser.urlbar.
+add_task(async function test_urlbar_no_privilege() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ background() {
+ browser.test.assertEq(
+ browser.urlbar,
+ undefined,
+ "'urlbar' permission is privileged"
+ );
+ },
+ });
+ await ext.startup();
+ await ext.unload();
+});
+
+// Extensions must be privileged to use browser.urlbar.
+add_task(async function test_urlbar_temporary_without_privilege() {
+ let extension = ExtensionTestUtils.loadExtension({
+ temporarilyInstalled: true,
+ isPrivileged: false,
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ });
+ ExtensionTestUtils.failOnSchemaWarnings(false);
+ let { messages } = await promiseConsoleOutput(async () => {
+ await Assert.rejects(
+ extension.startup(),
+ /Using the privileged permission/,
+ "Startup failed with privileged permission"
+ );
+ });
+ ExtensionTestUtils.failOnSchemaWarnings(true);
+ AddonTestUtils.checkMessages(
+ messages,
+ {
+ expected: [
+ {
+ message:
+ /Using the privileged permission 'urlbar' requires a privileged add-on/,
+ },
+ ],
+ },
+ true
+ );
+});
+
+// Checks that providers are added and removed properly.
+add_task(async function test_registerProvider() {
+ // A copy of the default providers.
+ let providers = UrlbarProvidersManager.providers.slice();
+
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ for (let state of ["active", "inactive", "restricting"]) {
+ let name = `Test-${state}`;
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ browser.test.assertFalse(query.isPrivate, "Context is non private");
+ browser.test.assertEq(query.maxResults, 10, "Check maxResults");
+ browser.test.assertTrue(
+ query.searchString,
+ "SearchString is non empty"
+ );
+ browser.test.assertTrue(
+ Array.isArray(query.sources),
+ "sources is an array"
+ );
+ return state;
+ }, name);
+ browser.urlbar.onResultsRequested.addListener(query => [], name);
+ }
+ },
+ });
+ await ext.startup();
+
+ Assert.greater(
+ UrlbarProvidersManager.providers.length,
+ providers.length,
+ "Providers have been added"
+ );
+
+ // Run a query, this should execute the above listeners and checks, plus it
+ // will set the provider's isActive and priority.
+ let queryContext = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "*",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(queryContext);
+
+ // Check the providers behavior has been setup properly.
+ for (let provider of UrlbarProvidersManager.providers) {
+ if (!provider.name.startsWith("Test")) {
+ continue;
+ }
+ let [, state] = provider.name.split("-");
+ let isActive = state != "inactive";
+ let restricting = state == "restricting";
+ Assert.equal(
+ isActive,
+ provider.isActive(queryContext),
+ "Check active callback"
+ );
+ if (restricting) {
+ Assert.notEqual(
+ provider.getPriority(queryContext),
+ 0,
+ "Check provider priority"
+ );
+ } else {
+ Assert.equal(
+ provider.getPriority(queryContext),
+ 0,
+ "Check provider priority"
+ );
+ }
+ }
+
+ await ext.unload();
+
+ // Sanity check the providers.
+ Assert.deepEqual(
+ UrlbarProvidersManager.providers,
+ providers,
+ "Should return to the default providers"
+ );
+});
+
+// Adds a single active provider that returns many kinds of results. This also
+// checks that the heuristic result from the built-in HeuristicFallback provider
+// is included.
+add_task(async function test_onProviderResultsRequested() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "active";
+ }, "test");
+ browser.urlbar.onResultsRequested.addListener(query => {
+ browser.test.assertFalse(query.isPrivate);
+ browser.test.assertEq(query.maxResults, 10);
+ browser.test.assertEq(query.searchString, "test");
+ browser.test.assertTrue(Array.isArray(query.sources));
+ return [
+ {
+ type: "remote_tab",
+ source: "tabs",
+ payload: {
+ title: "Test remote_tab-tabs result",
+ url: "https://example.com/remote_tab-tabs",
+ device: "device",
+ lastUsed: 1621366890,
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ suggestion: "Test search-search result",
+ engine: "Test engine",
+ },
+ },
+ {
+ type: "tab",
+ source: "tabs",
+ payload: {
+ title: "Test tab-tabs result",
+ url: "https://example.com/tab-tabs",
+ },
+ },
+ {
+ type: "tip",
+ source: "local",
+ payload: {
+ text: "Test tip-local result text",
+ buttonText: "Test tip-local result button text",
+ buttonUrl: "https://example.com/tip-button",
+ helpUrl: "https://example.com/tip-help",
+ },
+ },
+ {
+ type: "url",
+ source: "history",
+ payload: {
+ title: "Test url-history result",
+ url: "https://example.com/url-history",
+ },
+ },
+ ];
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check isActive and priority.
+ Assert.ok(provider.isActive(context));
+ Assert.equal(provider.getPriority(context), 0);
+
+ // Check the results.
+ let expectedResults = [
+ // The first result should be a search result returned by HeuristicFallback.
+ {
+ type: UrlbarUtils.RESULT_TYPE.SEARCH,
+ source: UrlbarUtils.RESULT_SOURCE.SEARCH,
+ title: "test",
+ heuristic: true,
+ payload: {
+ query: "test",
+ engine: "Test engine",
+ },
+ },
+ // The second result should be our search suggestion result since the
+ // default muxer sorts search suggestion results before other types.
+ {
+ type: UrlbarUtils.RESULT_TYPE.SEARCH,
+ source: UrlbarUtils.RESULT_SOURCE.SEARCH,
+ title: "Test search-search result",
+ heuristic: false,
+ payload: {
+ engine: "Test engine",
+ suggestion: "Test search-search result",
+ },
+ },
+ // The rest of the results should appear in the order we returned them
+ // above.
+ {
+ type: UrlbarUtils.RESULT_TYPE.REMOTE_TAB,
+ source: UrlbarUtils.RESULT_SOURCE.TABS,
+ title: "Test remote_tab-tabs result",
+ heuristic: false,
+ payload: {
+ title: "Test remote_tab-tabs result",
+ url: "https://example.com/remote_tab-tabs",
+ displayUrl: "example.com/remote_tab-tabs",
+ device: "device",
+ lastUsed: 1621366890,
+ },
+ },
+ {
+ type: UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
+ source: UrlbarUtils.RESULT_SOURCE.TABS,
+ title: "Test tab-tabs result",
+ heuristic: false,
+ payload: {
+ title: "Test tab-tabs result",
+ url: "https://example.com/tab-tabs",
+ displayUrl: "example.com/tab-tabs",
+ },
+ },
+ {
+ type: UrlbarUtils.RESULT_TYPE.TIP,
+ source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
+ title: "",
+ heuristic: false,
+ payload: {
+ text: "Test tip-local result text",
+ buttonText: "Test tip-local result button text",
+ buttonUrl: "https://example.com/tip-button",
+ helpUrl: "https://example.com/tip-help",
+ helpL10n: {
+ id: UrlbarPrefs.get("resultMenu")
+ ? "urlbar-result-menu-tip-get-help"
+ : "urlbar-tip-help-icon",
+ },
+ type: "extension",
+ },
+ },
+ {
+ type: UrlbarUtils.RESULT_TYPE.URL,
+ source: UrlbarUtils.RESULT_SOURCE.HISTORY,
+ title: "Test url-history result",
+ heuristic: false,
+ payload: {
+ title: "Test url-history result",
+ url: "https://example.com/url-history",
+ displayUrl: "example.com/url-history",
+ },
+ },
+ ];
+
+ Assert.ok(context.results.every(r => !r.hasSuggestedIndex));
+ let actualResults = context.results.map(r => ({
+ type: r.type,
+ source: r.source,
+ title: r.title,
+ heuristic: r.heuristic,
+ payload: getPayload(r),
+ }));
+
+ Assert.deepEqual(actualResults, expectedResults);
+
+ await ext.unload();
+});
+
+// Extensions can specify search engines using engine names, aliases, and URLs.
+add_task(async function test_onProviderResultsRequested_searchEngines() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "restricting";
+ }, "test");
+ browser.urlbar.onResultsRequested.addListener(query => {
+ return [
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ engine: "Test engine",
+ suggestion: "engine specified",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ keyword: "@testengine",
+ suggestion: "keyword specified",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ url: "https://example.com/?s",
+ suggestion: "url specified",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ engine: "Test engine",
+ keyword: "@testengine",
+ url: "https://example.com/?s",
+ suggestion: "engine, keyword, and url specified",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ keyword: "@testengine",
+ url: "https://example.com/?s",
+ suggestion: "keyword and url specified",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ suggestion: "no engine",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ engine: "bogus",
+ suggestion: "no matching engine",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ keyword: "@bogus",
+ suggestion: "no matching keyword",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ url: "http://bogus-no-search-engine.com/",
+ suggestion: "no matching url",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ url: "bogus",
+ suggestion: "invalid url",
+ },
+ },
+ {
+ type: "search",
+ source: "search",
+ payload: {
+ url: "foo:bar",
+ suggestion: "url with no hostname",
+ },
+ },
+ ];
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check the results. The first several are valid and should include "Test
+ // engine" as the engine. The others don't specify an engine and are
+ // therefore invalid, so they should be ignored.
+ let expectedResults = [
+ {
+ type: UrlbarUtils.RESULT_TYPE.SEARCH,
+ source: UrlbarUtils.RESULT_SOURCE.SEARCH,
+ engine: "Test engine",
+ title: "engine specified",
+ heuristic: false,
+ },
+ {
+ type: UrlbarUtils.RESULT_TYPE.SEARCH,
+ source: UrlbarUtils.RESULT_SOURCE.SEARCH,
+ engine: "Test engine",
+ title: "keyword specified",
+ heuristic: false,
+ },
+ {
+ type: UrlbarUtils.RESULT_TYPE.SEARCH,
+ source: UrlbarUtils.RESULT_SOURCE.SEARCH,
+ engine: "Test engine",
+ title: "url specified",
+ heuristic: false,
+ },
+ {
+ type: UrlbarUtils.RESULT_TYPE.SEARCH,
+ source: UrlbarUtils.RESULT_SOURCE.SEARCH,
+ engine: "Test engine",
+ title: "engine, keyword, and url specified",
+ heuristic: false,
+ },
+ {
+ type: UrlbarUtils.RESULT_TYPE.SEARCH,
+ source: UrlbarUtils.RESULT_SOURCE.SEARCH,
+ engine: "Test engine",
+ title: "keyword and url specified",
+ heuristic: false,
+ },
+ ];
+
+ let actualResults = context.results.map(r => ({
+ type: r.type,
+ source: r.source,
+ engine: r.payload.engine || null,
+ title: r.title,
+ heuristic: r.heuristic,
+ }));
+
+ Assert.deepEqual(actualResults, expectedResults);
+
+ await ext.unload();
+});
+
+// Adds two providers, one active and one inactive. Only the active provider
+// should be asked to return results.
+add_task(async function test_activeAndInactiveProviders() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ for (let behavior of ["active", "inactive"]) {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return behavior;
+ }, behavior);
+ browser.urlbar.onResultsRequested.addListener(query => {
+ browser.test.assertEq(
+ behavior,
+ "active",
+ "onResultsRequested should be fired only for the active provider"
+ );
+ return [
+ {
+ type: "url",
+ source: "history",
+ payload: {
+ title: `Test result ${behavior}`,
+ url: `https://example.com/${behavior}`,
+ },
+ },
+ ];
+ }, behavior);
+ }
+ },
+ });
+ await ext.startup();
+
+ // Check the providers.
+ let active = UrlbarProvidersManager.getProvider("active");
+ let inactive = UrlbarProvidersManager.getProvider("inactive");
+ Assert.ok(active);
+ Assert.ok(inactive);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check isActive and priority.
+ Assert.ok(active.isActive(context));
+ Assert.ok(!inactive.isActive(context));
+ Assert.equal(active.getPriority(context), 0);
+ Assert.equal(inactive.getPriority(context), 0);
+
+ // Check the results.
+ Assert.equal(context.results.length, 2);
+ Assert.ok(context.results[0].heuristic);
+ Assert.equal(context.results[1].title, "Test result active");
+
+ await ext.unload();
+});
+
+// Adds three active providers. They all should be asked for results.
+add_task(async function test_threeActiveProviders() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ for (let i = 0; i < 3; i++) {
+ let name = `test-${i}`;
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "active";
+ }, name);
+ browser.urlbar.onResultsRequested.addListener(query => {
+ return [
+ {
+ type: "url",
+ source: "history",
+ payload: {
+ title: `Test result ${i}`,
+ url: `https://example.com/${i}`,
+ },
+ },
+ ];
+ }, name);
+ }
+ },
+ });
+ await ext.startup();
+
+ // Check the providers.
+ let providers = [];
+ for (let i = 0; i < 3; i++) {
+ let name = `test-${i}`;
+ let provider = UrlbarProvidersManager.getProvider(name);
+ Assert.ok(provider);
+ providers.push(provider);
+ }
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check isActive and priority.
+ for (let provider of providers) {
+ Assert.ok(provider.isActive(context));
+ Assert.equal(provider.getPriority(context), 0);
+ }
+
+ // Check the results.
+ Assert.equal(context.results.length, 4);
+ Assert.ok(context.results[0].heuristic);
+ for (let i = 0; i < providers.length; i++) {
+ Assert.equal(context.results[i + 1].title, `Test result ${i}`);
+ }
+
+ await ext.unload();
+});
+
+// Adds three inactive providers. None of them should be asked for results.
+// This also checks that provider behavior is "inactive" by default.
+add_task(async function test_threeInactiveProviders() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ for (let i = 0; i < 3; i++) {
+ // Don't add an onBehaviorRequested listener. That way we can test that
+ // the default behavior is inactive.
+ browser.urlbar.onResultsRequested.addListener(query => {
+ browser.test.notifyFail(
+ "onResultsRequested fired for inactive provider"
+ );
+ }, `test-${i}`);
+ }
+ },
+ });
+ await ext.startup();
+
+ // Check the providers.
+ let providers = [];
+ for (let i = 0; i < 3; i++) {
+ let name = `test-${i}`;
+ let provider = UrlbarProvidersManager.getProvider(name);
+ Assert.ok(provider);
+ providers.push(provider);
+ }
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check isActive and priority.
+ for (let provider of providers) {
+ Assert.ok(!provider.isActive(context));
+ Assert.equal(provider.getPriority(context), 0);
+ }
+
+ // Check the results.
+ Assert.equal(context.results.length, 1);
+ Assert.ok(context.results[0].heuristic);
+
+ await ext.unload();
+});
+
+// Adds active, inactive, and restricting providers. Only the restricting
+// provider should be asked to return results.
+add_task(async function test_activeInactiveAndRestrictingProviders() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ for (let behavior of ["active", "inactive", "restricting"]) {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return behavior;
+ }, behavior);
+ browser.urlbar.onResultsRequested.addListener(query => {
+ browser.test.assertEq(
+ behavior,
+ "restricting",
+ "onResultsRequested should be fired for the restricting provider"
+ );
+ return [
+ {
+ type: "url",
+ source: "history",
+ payload: {
+ title: `Test result ${behavior}`,
+ url: `https://example.com/${behavior}`,
+ },
+ },
+ ];
+ }, behavior);
+ }
+ },
+ });
+ await ext.startup();
+
+ // Check the providers.
+ let providers = {};
+ for (let behavior of ["active", "inactive", "restricting"]) {
+ let provider = UrlbarProvidersManager.getProvider(behavior);
+ Assert.ok(provider);
+ providers[behavior] = provider;
+ }
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check isActive and isRestricting.
+ Assert.ok(providers.active.isActive(context));
+ Assert.equal(providers.active.getPriority(context), 0);
+ Assert.ok(!providers.inactive.isActive(context));
+ Assert.equal(providers.inactive.getPriority(context), 0);
+ Assert.ok(providers.restricting.isActive(context));
+ Assert.notEqual(providers.restricting.getPriority(context), 0);
+
+ // Check the results.
+ Assert.equal(context.results.length, 1);
+ Assert.equal(context.results[0].title, "Test result restricting");
+
+ await ext.unload();
+});
+
+// Adds a restricting provider that returns a heuristic result. The actual
+// result created from the extension's result should be a heuristic.
+add_task(async function test_heuristicRestricting() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "restricting";
+ }, "test");
+ browser.urlbar.onResultsRequested.addListener(query => {
+ return [
+ {
+ type: "url",
+ source: "history",
+ heuristic: true,
+ payload: {
+ title: "Test result",
+ url: "https://example.com/",
+ },
+ },
+ ];
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check the results.
+ Assert.equal(context.results.length, 1);
+ Assert.ok(context.results[0].heuristic);
+
+ await ext.unload();
+});
+
+// Adds a non-restricting provider that returns a heuristic result. The actual
+// result created from the extension's result should *not* be a heuristic, and
+// the usual UrlbarProviderHeuristicFallback heuristic should be present.
+add_task(async function test_heuristicNonRestricting() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "active";
+ }, "test");
+ browser.urlbar.onResultsRequested.addListener(query => {
+ return [
+ {
+ type: "url",
+ source: "history",
+ heuristic: true,
+ payload: {
+ title: "Test result",
+ url: "https://example.com/",
+ },
+ },
+ ];
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check the results. The first result should be
+ // UrlbarProviderHeuristicFallback's heuristic.
+ let firstResult = context.results[0];
+ Assert.ok(firstResult.heuristic);
+ Assert.equal(firstResult.type, UrlbarUtils.RESULT_TYPE.SEARCH);
+ Assert.equal(firstResult.source, UrlbarUtils.RESULT_SOURCE.SEARCH);
+ Assert.equal(firstResult.payload.engine, "Test engine");
+
+ // The extension result should be present but not the heuristic.
+ let result = context.results.find(r => r.title == "Test result");
+ Assert.ok(result);
+ Assert.ok(!result.heuristic);
+
+ await ext.unload();
+});
+
+// Adds an active provider that doesn't have a listener for onResultsRequested.
+// No results should be added.
+add_task(async function test_onResultsRequestedNotImplemented() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "active";
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check isActive and isRestricting.
+ Assert.ok(provider.isActive(context));
+ Assert.equal(provider.getPriority(context), 0);
+
+ // Check the results.
+ Assert.equal(context.results.length, 1);
+ Assert.ok(context.results[0].heuristic);
+
+ await ext.unload();
+});
+
+// Adds an active provider that returns a result with a malformed payload. The
+// bad result shouldn't be added.
+add_task(async function test_badPayload() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "active";
+ }, "test");
+ browser.urlbar.onResultsRequested.addListener(async query => {
+ return [
+ {
+ type: "url",
+ source: "history",
+ payload: "this is a bad payload",
+ },
+ {
+ type: "url",
+ source: "history",
+ payload: {
+ title: "Test result",
+ url: "https://example.com/",
+ },
+ },
+ ];
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check the results.
+ Assert.equal(context.results.length, 2);
+ Assert.ok(context.results[0].heuristic);
+ Assert.equal(context.results[1].title, "Test result");
+
+ await ext.unload();
+});
+
+// Tests the onQueryCanceled event.
+add_task(async function test_onQueryCanceled() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "active";
+ }, "test");
+ browser.urlbar.onQueryCanceled.addListener(query => {
+ browser.test.notifyPass("canceled");
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query but immediately cancel it.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+
+ let startPromise = controller.startQuery(context);
+ controller.cancelQuery();
+ await startPromise;
+
+ await ext.awaitFinish("canceled");
+
+ await ext.unload();
+});
+
+// Adds an onBehaviorRequested listener that takes too long to respond. The
+// provider should default to inactive.
+add_task(async function test_onBehaviorRequestedTimeout() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(async query => {
+ // setTimeout is available in background scripts
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout, no-undef
+ await new Promise(r => setTimeout(r, 500));
+ return "active";
+ }, "test");
+ browser.urlbar.onResultsRequested.addListener(query => {
+ browser.test.notifyFail(
+ "onResultsRequested fired for inactive provider"
+ );
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+
+ Services.prefs.setIntPref("browser.urlbar.extension.timeout", 0);
+ await controller.startQuery(context);
+ Services.prefs.clearUserPref("browser.urlbar.extension.timeout");
+
+ // Check isActive and priority.
+ Assert.ok(!provider.isActive(context));
+ Assert.equal(provider.getPriority(context), 0);
+
+ // Check the results.
+ Assert.equal(context.results.length, 1);
+ Assert.ok(context.results[0].heuristic);
+
+ await ext.unload();
+});
+
+// Adds an onResultsRequested listener that takes too long to respond. The
+// provider's results should default to no results.
+add_task(async function test_onResultsRequestedTimeout() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "active";
+ }, "test");
+ browser.urlbar.onResultsRequested.addListener(async query => {
+ // setTimeout is available in background scripts
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout, no-undef
+ await new Promise(r => setTimeout(r, 600));
+ return [
+ {
+ type: "url",
+ source: "history",
+ payload: {
+ title: "Test result",
+ url: "https://example.com/",
+ },
+ },
+ ];
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+
+ await controller.startQuery(context);
+
+ // Check isActive and priority.
+ Assert.ok(provider.isActive(context));
+ Assert.equal(provider.getPriority(context), 0);
+
+ // Check the results.
+ Assert.equal(context.results.length, 1);
+ Assert.ok(context.results[0].heuristic);
+
+ await ext.unload();
+});
+
+// Performs a search in a private context for an extension that does not allow
+// private browsing. The extension's listeners should not be called.
+add_task(async function test_privateBrowsing_not_allowed() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ incognito: "not_allowed",
+ },
+ isPrivileged: true,
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ browser.test.notifyFail(
+ "onBehaviorRequested fired in private browsing"
+ );
+ }, "Test-private");
+ browser.urlbar.onResultsRequested.addListener(query => {
+ browser.test.notifyFail("onResultsRequested fired in private browsing");
+ }, "Test-private");
+ // We can't easily test onQueryCanceled here because immediately canceling
+ // the query will cause onResultsRequested not to be fired.
+ // onResultsRequested should in fact not be fired, but that should be
+ // because this test runs in private-browsing mode, not because the query
+ // was canceled. See the next test task for onQueryCanceled.
+ },
+ });
+ await ext.startup();
+
+ // Run a query, this should execute the above listeners and checks, plus it
+ // will set the provider's isActive and priority.
+ let queryContext = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: true,
+ maxResults: 10,
+ searchString: "*",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(queryContext);
+ // Check the providers behavior has been setup properly.
+ let provider = UrlbarProvidersManager.getProvider("Test-private");
+ Assert.ok(!provider.isActive({}), "Check provider is inactive");
+
+ await ext.unload();
+});
+
+// Same as the previous task but tests the onQueryCanceled event: Performs a
+// search in a private context for an extension that does not allow private
+// browsing. The extension's onQueryCanceled listener should not be called.
+add_task(async function test_privateBrowsing_not_allowed_onQueryCanceled() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ incognito: "not_allowed",
+ },
+ isPrivileged: true,
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ browser.test.notifyFail(
+ "onBehaviorRequested fired in private browsing"
+ );
+ }, "test");
+ browser.urlbar.onQueryCanceled.addListener(query => {
+ browser.test.notifyFail("onQueryCanceled fired in private browsing");
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query but immediately cancel it.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: true,
+ maxResults: 10,
+ searchString: "*",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+
+ let startPromise = controller.startQuery(context);
+ controller.cancelQuery();
+ await startPromise;
+
+ // Check isActive and priority.
+ Assert.ok(!provider.isActive(context));
+ Assert.equal(provider.getPriority(context), 0);
+
+ await ext.unload();
+});
+
+// Performs a search in a private context for an extension that allows private
+// browsing. The extension's listeners should be called.
+add_task(async function test_privateBrowsing_allowed() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ let name = "Test-private";
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ browser.test.sendMessage("onBehaviorRequested");
+ return "active";
+ }, name);
+ browser.urlbar.onResultsRequested.addListener(query => {
+ browser.test.sendMessage("onResultsRequested");
+ return [];
+ }, name);
+ // We can't easily test onQueryCanceled here because immediately canceling
+ // the query will cause onResultsRequested not to be fired. See the next
+ // test task for onQueryCanceled.
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("Test-private");
+ Assert.ok(provider);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: true,
+ maxResults: 10,
+ searchString: "*",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check isActive and priority.
+ Assert.ok(provider.isActive(context));
+ Assert.equal(provider.getPriority(context), 0);
+
+ // The events should have been fired.
+ await Promise.all(
+ ["onBehaviorRequested", "onResultsRequested"].map(msg =>
+ ext.awaitMessage(msg)
+ )
+ );
+
+ await ext.unload();
+});
+
+// Same as the previous task but tests the onQueryCanceled event: Performs a
+// search in a private context for an extension that allows private browsing,
+// but cancels the search. The extension's onQueryCanceled listener should be
+// called.
+add_task(async function test_privateBrowsing_allowed_onQueryCanceled() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ let name = "Test-private";
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ browser.test.sendMessage("onBehaviorRequested");
+ return "active";
+ }, name);
+ browser.urlbar.onQueryCanceled.addListener(query => {
+ browser.test.sendMessage("onQueryCanceled");
+ }, name);
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("Test-private");
+ Assert.ok(provider);
+
+ // Run a query but immediately cancel it.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: true,
+ maxResults: 10,
+ searchString: "*",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+
+ let startPromise = controller.startQuery(context);
+ controller.cancelQuery();
+ await startPromise;
+
+ // onQueryCanceled should have been fired.
+ await ext.awaitMessage("onQueryCanceled");
+
+ await ext.unload();
+});
+
+// Performs a search in a non-private context for an extension that does not
+// allow private browsing. The extension's listeners should be called.
+add_task(async function test_nonPrivateBrowsing() {
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ incognito: "not_allowed",
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ background() {
+ browser.urlbar.onBehaviorRequested.addListener(query => {
+ return "active";
+ }, "test");
+ browser.urlbar.onResultsRequested.addListener(query => {
+ return [
+ {
+ type: "url",
+ source: "history",
+ payload: {
+ title: "Test result",
+ url: "https://example.com/",
+ },
+ suggestedIndex: 1,
+ },
+ ];
+ }, "test");
+ },
+ });
+ await ext.startup();
+
+ // Check the provider.
+ let provider = UrlbarProvidersManager.getProvider("test");
+ Assert.ok(provider);
+
+ // Run a query.
+ let context = new UrlbarQueryContext({
+ allowAutofill: false,
+ isPrivate: false,
+ maxResults: 10,
+ searchString: "test",
+ });
+ let controller = UrlbarTestUtils.newMockController();
+ await controller.startQuery(context);
+
+ // Check isActive and priority.
+ Assert.ok(provider.isActive(context));
+ Assert.equal(provider.getPriority(context), 0);
+
+ // Check the results.
+ Assert.equal(context.results.length, 2);
+ Assert.ok(context.results[0].heuristic);
+ Assert.equal(context.results[1].title, "Test result");
+ Assert.equal(context.results[1].suggestedIndex, 1);
+
+ await ext.unload();
+});
+
+// Tests the engagementTelemetry property.
+add_task(async function test_engagementTelemetry() {
+ let getPrefValue = () => UrlbarPrefs.get("eventTelemetry.enabled");
+
+ Assert.equal(
+ getPrefValue(),
+ false,
+ "Engagement telemetry should be disabled by default"
+ );
+
+ let ext = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["urlbar"],
+ },
+ isPrivileged: true,
+ incognitoOverride: "spanning",
+ useAddonManager: "temporary",
+ async background() {
+ await browser.urlbar.engagementTelemetry.set({ value: true });
+ browser.test.sendMessage("ready");
+ },
+ });
+ await ext.startup();
+ await ext.awaitMessage("ready");
+
+ Assert.equal(
+ getPrefValue(),
+ true,
+ "Successfully enabled the engagement telemetry"
+ );
+
+ let completed = promiseUninstallCompleted(ext.id);
+ await ext.unload();
+ await completed;
+
+ Assert.equal(
+ getPrefValue(),
+ false,
+ "Engagement telemetry should be reset after unloading the add-on"
+ );
+});