Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
const { AddonTestUtils } = ChromeUtils.importESModule(
);
const { setTimeout } = ChromeUtils.importESModule(
);
let delay = () => new Promise(resolve => setTimeout(resolve, 0));
const kSearchFormURL = "https://example.com/searchform";
const kSearchEngineURL = "https://example.com/?search={searchTerms}";
const kSearchSuggestURL = "https://example.com/?suggest={searchTerms}";
const kSearchTerm = "foo";
const kSearchTermIntl = "日";
const URLTYPE_SUGGEST_JSON = "application/x-suggestions+json";
AddonTestUtils.init(this);
AddonTestUtils.createAppInfo(
"xpcshell@tests.mozilla.org",
"XPCShell",
"42",
"42"
);
add_task(async function setup() {
await AddonTestUtils.promiseStartupManager();
await Services.search.init();
});
add_task(async function test_extension_adding_engine() {
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {
icons: {
16: "foo.ico",
32: "foo32.ico",
},
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
search_form: kSearchFormURL,
search_url: kSearchEngineURL,
suggest_url: kSearchSuggestURL,
},
},
},
useAddonManager: "temporary",
});
await ext1.startup();
await AddonTestUtils.waitForSearchProviderStartup(ext1);
let engine = Services.search.getEngineByName("MozSearch");
ok(engine, "Engine should exist.");
let { baseURI } = ext1.extension;
equal(
await engine.getIconURL(),
baseURI.resolve("foo.ico"),
"16x16 icon path matches"
);
equal(
await engine.getIconURL(16),
baseURI.resolve("foo.ico"),
"16x16 icon path matches"
);
// TODO: Bug 1871036 - Differently sized icons are currently incorrectly
// handled for add-ons.
// equal(
// await engine.getIconURL(32),
// baseURI.resolve("foo32.ico"),
// "32x32 icon path matches"
// );
let expectedSuggestURL = kSearchSuggestURL.replace(
"{searchTerms}",
kSearchTerm
);
let submissionSuggest = engine.getSubmission(
kSearchTerm,
URLTYPE_SUGGEST_JSON
);
let encodedSubmissionURL = engine.getSubmission(kSearchTermIntl).uri.spec;
let testSubmissionURL = kSearchEngineURL.replace(
"{searchTerms}",
encodeURIComponent(kSearchTermIntl)
);
equal(
encodedSubmissionURL,
testSubmissionURL,
"Encoded UTF-8 URLs should match"
);
equal(
submissionSuggest.uri.spec,
expectedSuggestURL,
"Suggest URLs should match"
);
equal(engine.searchForm, kSearchFormURL, "Search form URLs should match");
await ext1.unload();
await delay();
engine = Services.search.getEngineByName("MozSearch");
ok(!engine, "Engine should not exist");
});
add_task(async function test_extension_adding_engine_with_spaces() {
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {
chrome_settings_overrides: {
search_provider: {
name: "MozSearch ",
keyword: "MozSearch",
},
},
},
useAddonManager: "temporary",
});
await ext1.startup();
await AddonTestUtils.waitForSearchProviderStartup(ext1);
let engine = Services.search.getEngineByName("MozSearch");
ok(engine, "Engine should exist.");
await ext1.unload();
await delay();
engine = Services.search.getEngineByName("MozSearch");
ok(!engine, "Engine should not exist");
});
add_task(async function test_upgrade_default_position_engine() {
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
},
},
browser_specific_settings: {
gecko: {
id: "testengine@mozilla.com",
},
},
version: "0.1",
},
useAddonManager: "temporary",
});
await ext1.startup();
await AddonTestUtils.waitForSearchProviderStartup(ext1);
let engine = Services.search.getEngineByName("MozSearch");
await Services.search.setDefault(
engine,
Ci.nsISearchService.CHANGE_REASON_UNKNOWN
);
await Services.search.moveEngine(engine, 1);
await ext1.upgrade({
manifest: {
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
},
},
browser_specific_settings: {
gecko: {
id: "testengine@mozilla.com",
},
},
version: "0.2",
},
useAddonManager: "temporary",
});
await AddonTestUtils.waitForSearchProviderStartup(ext1);
engine = Services.search.getEngineByName("MozSearch");
equal(
Services.search.defaultEngine,
engine,
"Default engine should still be MozSearch"
);
equal(
(await Services.search.getEngines()).map(e => e.name).indexOf(engine.name),
1,
"Engine is in position 1"
);
await ext1.unload();
await delay();
engine = Services.search.getEngineByName("MozSearch");
ok(!engine, "Engine should not exist");
});
add_task(async function test_extension_get_params() {
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
search_url: kSearchEngineURL,
search_url_get_params: "foo=bar&bar=foo",
suggest_url: kSearchSuggestURL,
suggest_url_get_params: "foo=bar&bar=foo",
},
},
},
useAddonManager: "temporary",
});
await ext1.startup();
await AddonTestUtils.waitForSearchProviderStartup(ext1);
let engine = Services.search.getEngineByName("MozSearch");
ok(engine, "Engine should exist.");
let url = engine.wrappedJSObject._getURLOfType("text/html");
equal(url.method, "GET", "Search URLs method is GET");
let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm);
let submission = engine.getSubmission(kSearchTerm);
equal(
submission.uri.spec,
`${expectedURL}&foo=bar&bar=foo`,
"Search URLs should match"
);
let expectedSuggestURL = kSearchSuggestURL.replace(
"{searchTerms}",
kSearchTerm
);
let submissionSuggest = engine.getSubmission(
kSearchTerm,
URLTYPE_SUGGEST_JSON
);
equal(
submissionSuggest.uri.spec,
`${expectedSuggestURL}&foo=bar&bar=foo`,
"Suggest URLs should match"
);
await ext1.unload();
});
add_task(async function test_extension_post_params() {
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
search_url: kSearchEngineURL,
search_url_post_params: "foo=bar&bar=foo",
suggest_url: kSearchSuggestURL,
suggest_url_post_params: "foo=bar&bar=foo",
},
},
},
useAddonManager: "temporary",
});
await ext1.startup();
await AddonTestUtils.waitForSearchProviderStartup(ext1);
let engine = Services.search.getEngineByName("MozSearch");
ok(engine, "Engine should exist.");
let url = engine.wrappedJSObject._getURLOfType("text/html");
equal(url.method, "POST", "Search URLs method is POST");
let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm);
let submission = engine.getSubmission(kSearchTerm);
equal(submission.uri.spec, expectedURL, "Search URLs should match");
// postData is a nsIMIMEInputStream which contains a nsIStringInputStream.
equal(
submission.postData.data.data,
"foo=bar&bar=foo",
"Search postData should match"
);
let expectedSuggestURL = kSearchSuggestURL.replace(
"{searchTerms}",
kSearchTerm
);
let submissionSuggest = engine.getSubmission(
kSearchTerm,
URLTYPE_SUGGEST_JSON
);
equal(
submissionSuggest.uri.spec,
expectedSuggestURL,
"Suggest URLs should match"
);
equal(
submissionSuggest.postData.data.data,
"foo=bar&bar=foo",
"Suggest postData should match"
);
await ext1.unload();
});
add_task(async function test_extension_no_query_params() {
const ext1 = ExtensionTestUtils.loadExtension({
manifest: {
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
},
},
},
useAddonManager: "temporary",
});
await ext1.startup();
await AddonTestUtils.waitForSearchProviderStartup(ext1);
let engine = Services.search.getEngineByName("MozSearch");
ok(engine, "Engine should exist.");
const encodedSubmissionURL = engine.getSubmission(kSearchTermIntl).uri.spec;
const testSubmissionURL =
"https://example.com/" + encodeURIComponent(kSearchTermIntl);
equal(
encodedSubmissionURL,
testSubmissionURL,
"Encoded UTF-8 URLs should match"
);
const expectedSuggestURL = "https://example.com/suggest/" + kSearchTerm;
let submissionSuggest = engine.getSubmission(
kSearchTerm,
URLTYPE_SUGGEST_JSON
);
equal(
submissionSuggest.uri.spec,
expectedSuggestURL,
"Suggest URLs should match"
);
await ext1.unload();
await delay();
engine = Services.search.getEngineByName("MozSearch");
ok(!engine, "Engine should not exist");
});
add_task(async function test_extension_empty_suggestUrl() {
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {
default_locale: "en",
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
search_url: kSearchEngineURL,
search_url_post_params: "foo=bar&bar=foo",
suggest_url: "__MSG_suggestUrl__",
suggest_url_get_params: "__MSG_suggestUrlGetParams__",
},
},
},
useAddonManager: "temporary",
files: {
"_locales/en/messages.json": {
suggestUrl: {
message: "",
},
suggestUrlGetParams: {
message: "",
},
},
},
});
await ext1.startup();
await AddonTestUtils.waitForSearchProviderStartup(ext1);
let engine = Services.search.getEngineByName("MozSearch");
ok(engine, "Engine should exist.");
let url = engine.wrappedJSObject._getURLOfType("text/html");
equal(url.method, "POST", "Search URLs method is POST");
let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm);
let submission = engine.getSubmission(kSearchTerm);
equal(submission.uri.spec, expectedURL, "Search URLs should match");
// postData is a nsIMIMEInputStream which contains a nsIStringInputStream.
equal(
submission.postData.data.data,
"foo=bar&bar=foo",
"Search postData should match"
);
let submissionSuggest = engine.getSubmission(
kSearchTerm,
URLTYPE_SUGGEST_JSON
);
ok(!submissionSuggest, "There should be no suggest URL.");
await ext1.unload();
});
add_task(async function test_extension_empty_suggestUrl_with_params() {
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {
default_locale: "en",
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
search_url: kSearchEngineURL,
search_url_post_params: "foo=bar&bar=foo",
suggest_url: "__MSG_suggestUrl__",
suggest_url_get_params: "__MSG_suggestUrlGetParams__",
},
},
},
useAddonManager: "temporary",
files: {
"_locales/en/messages.json": {
suggestUrl: {
message: "",
},
suggestUrlGetParams: {
message: "abc",
},
},
},
});
await ext1.startup();
await AddonTestUtils.waitForSearchProviderStartup(ext1);
let engine = Services.search.getEngineByName("MozSearch");
ok(engine, "Engine should exist.");
let url = engine.wrappedJSObject._getURLOfType("text/html");
equal(url.method, "POST", "Search URLs method is POST");
let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm);
let submission = engine.getSubmission(kSearchTerm);
equal(submission.uri.spec, expectedURL, "Search URLs should match");
// postData is a nsIMIMEInputStream which contains a nsIStringInputStream.
equal(
submission.postData.data.data,
"foo=bar&bar=foo",
"Search postData should match"
);
let submissionSuggest = engine.getSubmission(
kSearchTerm,
URLTYPE_SUGGEST_JSON
);
ok(!submissionSuggest, "There should be no suggest URL.");
await ext1.unload();
});
async function checkBadUrl(searchProviderKey, urlValue) {
let normalized = await ExtensionTestUtils.normalizeManifest({
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
search_url: "https://example.com/",
[searchProviderKey]: urlValue,
},
},
});
ok(
/Error processing chrome_settings_overrides\.search_provider[^:]*: .* must match/.test(
normalized.error
),
`Expected error for ${searchProviderKey}:${urlValue} "${normalized.error}"`
);
}
async function checkValidUrl(urlValue) {
let normalized = await ExtensionTestUtils.normalizeManifest({
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
search_form: urlValue,
search_url: urlValue,
suggest_url: urlValue,
},
},
});
equal(normalized.error, undefined, `Valid search_provider url: ${urlValue}`);
}
add_task(async function test_extension_not_allow_http() {
await checkBadUrl("search_form", "http://example.com/{searchTerms}");
await checkBadUrl("search_url", "http://example.com/{searchTerms}");
await checkBadUrl("suggest_url", "http://example.com/{searchTerms}");
});
add_task(async function test_manifest_disallows_http_localhost_prefix() {
await checkBadUrl("search_url", "http://localhost.example.com");
await checkBadUrl("search_url", "http://localhost.example.com/");
await checkBadUrl("search_url", "http://127.0.0.1.example.com/");
await checkBadUrl("search_url", "http://localhost:1234@example.com/");
});
add_task(async function test_manifest_allow_http_for_localhost() {
await checkValidUrl("http://localhost");
await checkValidUrl("http://localhost/");
await checkValidUrl("http://localhost:/");
await checkValidUrl("http://localhost:1/");
await checkValidUrl("http://localhost:65535/");
await checkValidUrl("http://127.0.0.1");
await checkValidUrl("http://127.0.0.1:");
await checkValidUrl("http://127.0.0.1:/");
await checkValidUrl("http://127.0.0.1/");
await checkValidUrl("http://127.0.0.1:80/");
await checkValidUrl("http://[::1]");
await checkValidUrl("http://[::1]:");
await checkValidUrl("http://[::1]:/");
await checkValidUrl("http://[::1]/");
await checkValidUrl("http://[::1]:80/");
});
add_task(async function test_extension_allow_http_for_localhost() {
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {
chrome_settings_overrides: {
search_provider: {
name: "MozSearch",
keyword: "MozSearch",
},
},
},
useAddonManager: "temporary",
});
await ext1.startup();
await AddonTestUtils.waitForSearchProviderStartup(ext1);
let engine = Services.search.getEngineByName("MozSearch");
ok(engine, "Engine should exist.");
await ext1.unload();
});
add_task(async function test_search_favicon_mv3() {
Services.prefs.setBoolPref("extensions.manifestV3.enabled", true);
let normalized = await ExtensionTestUtils.normalizeManifest({
manifest_version: 3,
chrome_settings_overrides: {
search_provider: {
name: "HTTP Icon in MV3",
search_url: "https://example.org/",
},
},
});
Assert.ok(
normalized.error.endsWith("must be a relative URL"),
"Should have an error"
);
normalized = await ExtensionTestUtils.normalizeManifest({
manifest_version: 3,
chrome_settings_overrides: {
search_provider: {
name: "HTTP Icon in MV3",
search_url: "https://example.org/",
favicon_url: "/icon.png",
},
},
});
Assert.ok(!normalized.error, "Should not have an error");
});