Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* 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/. */
"use strict";
const HEURISTIC_FALLBACK_PROVIDERNAME = "HeuristicFallback";
const origin = "example.com";
async function cleanup() {
let suggestPrefs = ["history", "bookmark", "openpage"];
for (let type of suggestPrefs) {
Services.prefs.clearUserPref("browser.urlbar.suggest." + type);
}
await cleanupPlaces();
}
testEngine_setup();
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("browser.urlbar.suggest.quickactions");
});
Services.prefs.setBoolPref("browser.urlbar.suggest.quickactions", false);
// "example.com/" should match http://example.com/. i.e., the search string
// should be treated as if it didn't have the trailing slash.
add_task(async function trailingSlash() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext(`${origin}/`, { isPrivate: false });
await check_results({
context,
autofilled: `${origin}/`,
completed: `http://${origin}/`,
matches: [
makeVisitResult(context, {
uri: `http://${origin}/`,
title: `test visit for http://${origin}/`,
heuristic: true,
}),
],
});
await cleanup();
});
// "example.com/" should match http://www.example.com/. i.e., the search string
// should be treated as if it didn't have the trailing slash.
add_task(async function trailingSlashWWW() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext(`${origin}/`, { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "http://www.example.com/",
matches: [
makeVisitResult(context, {
uri: `http://www.${origin}/`,
title: `test visit for http://www.${origin}/`,
heuristic: true,
}),
],
});
await cleanup();
});
// "ex" should match http://example.com:8888/, and the port should be completed.
add_task(async function port() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext("ex", { isPrivate: false });
await check_results({
context,
autofilled: "example.com:8888/",
completed: "http://example.com:8888/",
matches: [
makeVisitResult(context, {
uri: `http://${origin}:8888/`,
title: `test visit for http://${origin}:8888/`,
heuristic: true,
}),
],
});
await cleanup();
});
// "example.com:8" should match http://example.com:8888/, and the port should
// be completed.
add_task(async function portPartial() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext(`${origin}:8`, { isPrivate: false });
await check_results({
context,
autofilled: "example.com:8888/",
completed: "http://example.com:8888/",
matches: [
makeVisitResult(context, {
uri: `http://${origin}:8888/`,
title: `test visit for http://${origin}:8888/`,
heuristic: true,
}),
],
});
await cleanup();
});
// "EXaM" should match http://example.com/ and the case of the search string
// should be preserved in the autofilled value.
add_task(async function preserveCase() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext("EXaM", { isPrivate: false });
await check_results({
context,
autofilled: "EXaMple.com/",
completed: "http://example.com/",
matches: [
makeVisitResult(context, {
uri: `http://${origin}/`,
title: `test visit for http://${origin}/`,
heuristic: true,
}),
],
});
await cleanup();
});
// "EXaM" should match http://example.com:8888/, the port should be completed,
// and the case of the search string should be preserved in the autofilled
// value.
add_task(async function preserveCasePort() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext("EXaM", { isPrivate: false });
await check_results({
context,
autofilled: "EXaMple.com:8888/",
completed: "http://example.com:8888/",
matches: [
makeVisitResult(context, {
uri: `http://${origin}:8888/`,
title: `test visit for http://${origin}:8888/`,
heuristic: true,
}),
],
});
await cleanup();
});
// "example.com:89" should *not* match http://example.com:8888/.
add_task(async function portNoMatch1() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext(`${origin}:89`, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${origin}:89/`,
fallbackTitle: `http://${origin}:89/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
});
await cleanup();
});
// "example.com:9" should *not* match http://example.com:8888/.
add_task(async function portNoMatch2() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext(`${origin}:9`, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${origin}:9/`,
fallbackTitle: `http://${origin}:9/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
});
await cleanup();
});
// "example/" should *not* match http://example.com/.
add_task(async function trailingSlash_2() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext("example/", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://example/",
fallbackTitle: "http://example/",
iconUri: "page-icon:http://example/",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
});
await cleanup();
});
// multi.dotted.domain, search up to dot.
add_task(async function multidotted() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext("www.example.co.", { isPrivate: false });
await check_results({
context,
autofilled: "www.example.co.jp:8888/",
matches: [
makeVisitResult(context, {
title: "test visit for http://www.example.co.jp:8888/",
heuristic: true,
}),
],
});
await cleanup();
});
add_task(async function test_ip() {
// IP addresses have complicated rules around whether they show
// HeuristicFallback's backup search result. Flip this pref to disable that
// backup search and simplify ths subtest.
Services.prefs.setBoolPref("keyword.enabled", false);
for (let str of [
"192.168.1.1/",
"255.255.255.255:8080/",
"[2001:db8::1428:57ab]/",
"[::c0a8:5909]/",
"[::1]/",
]) {
info("testing " + str);
await PlacesTestUtils.addVisits("http://" + str);
for (let i = 1; i < str.length; ++i) {
let context = createContext(str.substring(0, i), { isPrivate: false });
await check_results({
context,
autofilled: str,
completed: "http://" + str,
matches: [
makeVisitResult(context, {
uri: "http://" + str,
title: `test visit for http://${str}`,
heuristic: true,
}),
],
});
}
await cleanup();
}
Services.prefs.clearUserPref("keyword.enabled");
});
// host starting with large number.
add_task(async function large_number_host() {
await PlacesTestUtils.addVisits([
{
},
]);
let context = createContext("1234", { isPrivate: false });
await check_results({
context,
autofilled: "12345example.it:8888/",
matches: [
makeVisitResult(context, {
title: "test visit for http://12345example.it:8888/",
heuristic: true,
}),
],
});
await cleanup();
});
// When determining which origins should be autofilled, all the origins sharing
// a host should be added together to get their combined frecency -- i.e.,
// prefixes should be collapsed. And then from that list, the origin with the
// highest frecency should be chosen.
add_task(async function groupByHost() {
// Add some visits to the same host, example.com. Add one http and two https
// so that https has a higher frecency and is therefore the origin that should
// be autofilled. Also add another origin that has a higher frecency than
// both so that alone, neither http nor https would be autofilled, but added
// together they should be.
await PlacesTestUtils.addVisits([
{ uri: "http://example.com/" },
{ uri: "https://example.com/" },
{ uri: "https://example.com/" },
{ uri: "https://mozilla.org/" },
{ uri: "https://mozilla.org/" },
{ uri: "https://mozilla.org/" },
{ uri: "https://mozilla.org/" },
]);
let httpFrec = await PlacesTestUtils.getDatabaseValue(
"moz_places",
"frecency",
{ url: "http://example.com/" }
);
let httpsFrec = await PlacesTestUtils.getDatabaseValue(
"moz_places",
"frecency",
);
let otherFrec = await PlacesTestUtils.getDatabaseValue(
"moz_places",
"frecency",
);
Assert.less(httpFrec, httpsFrec, "Sanity check");
Assert.less(httpsFrec, otherFrec, "Sanity check");
// Make sure the frecencies of the three origins are as expected in relation
// to the threshold.
let threshold = await getOriginAutofillThreshold();
Assert.less(httpFrec, threshold, "http origin should be < threshold");
Assert.less(httpsFrec, threshold, "https origin should be < threshold");
Assert.ok(threshold <= otherFrec, "Other origin should cross threshold");
Assert.ok(
threshold <= httpFrec + httpsFrec,
"http and https origin added together should cross threshold"
);
// The https origin should be autofilled.
let context = createContext("ex", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/",
heuristic: true,
}),
],
});
await cleanup();
});
// This is the same as the previous (groupByHost), but it changes the standard
// deviation multiplier by setting the corresponding pref. This makes sure that
// the pref is respected.
add_task(async function groupByHostNonDefaultStddevMultiplier() {
let stddevMultiplier = 1.5;
Services.prefs.setCharPref(
"browser.urlbar.autoFill.stddevMultiplier",
Number(stddevMultiplier).toFixed(1)
);
await PlacesTestUtils.addVisits([
{ uri: "http://example.com/" },
{ uri: "http://example.com/" },
{ uri: "https://example.com/" },
{ uri: "https://example.com/" },
{ uri: "https://example.com/" },
{ uri: "https://foo.com/" },
{ uri: "https://foo.com/" },
{ uri: "https://foo.com/" },
{ uri: "https://mozilla.org/" },
{ uri: "https://mozilla.org/" },
{ uri: "https://mozilla.org/" },
{ uri: "https://mozilla.org/" },
{ uri: "https://mozilla.org/" },
]);
let httpFrec = await PlacesTestUtils.getDatabaseValue(
"moz_places",
"frecency",
{
}
);
let httpsFrec = await PlacesTestUtils.getDatabaseValue(
"moz_places",
"frecency",
{
}
);
let otherFrec = await PlacesTestUtils.getDatabaseValue(
"moz_places",
"frecency",
{
}
);
Assert.less(httpFrec, httpsFrec, "Sanity check");
Assert.less(httpsFrec, otherFrec, "Sanity check");
// Make sure the frecencies of the three origins are as expected in relation
// to the threshold.
let threshold = await getOriginAutofillThreshold();
Assert.less(httpFrec, threshold, "http origin should be < threshold");
Assert.less(httpsFrec, threshold, "https origin should be < threshold");
Assert.ok(threshold <= otherFrec, "Other origin should cross threshold");
Assert.ok(
threshold <= httpFrec + httpsFrec,
"http and https origin added together should cross threshold"
);
// The https origin should be autofilled.
let context = createContext("ex", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/",
heuristic: true,
}),
],
});
Services.prefs.clearUserPref("browser.urlbar.autoFill.stddevMultiplier");
await cleanup();
});
// This is similar to suggestHistoryFalse_bookmark_0 in test_autofill_tasks.js,
// but it adds unbookmarked visits for multiple URLs with the same origin.
add_task(async function suggestHistoryFalse_bookmark_multiple() {
// Force only bookmarked pages to be suggested and therefore only bookmarked
// pages to be completed.
Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
let search = "ex";
let baseURL = "http://example.com/";
let bookmarkedURL = baseURL + "bookmarked";
// Add visits for three different URLs all sharing the same origin, and then
// bookmark the second one. After that, the origin should be autofilled. The
// reason for adding unbookmarked visits before and after adding the
// bookmarked visit is to make sure our aggregate SQL query for determining
// whether an origin is bookmarked is correct.
await PlacesTestUtils.addVisits([
{
uri: baseURL + "other1",
},
]);
let context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
heuristic: true,
}),
],
});
await PlacesTestUtils.addVisits([
{
uri: bookmarkedURL,
},
]);
context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
heuristic: true,
}),
],
});
await PlacesTestUtils.addVisits([
{
uri: baseURL + "other2",
},
]);
context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
heuristic: true,
}),
],
});
// Now bookmark the second URL. It should be suggested and completed.
await PlacesTestUtils.addBookmarkWithDetails({
uri: bookmarkedURL,
});
context = createContext(search, { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: baseURL,
matches: [
makeVisitResult(context, {
uri: baseURL,
fallbackTitle: UrlbarTestUtils.trimURL(baseURL),
heuristic: true,
}),
makeBookmarkResult(context, {
uri: bookmarkedURL,
title: "A bookmark",
}),
],
});
await cleanup();
});
// This is similar to suggestHistoryFalse_bookmark_prefix_0 in
// autofill_test_autofill_originsAndQueries.js, but it adds unbookmarked visits
// for multiple URLs with the same origin.
add_task(async function suggestHistoryFalse_bookmark_prefix_multiple() {
// Force only bookmarked pages to be suggested and therefore only bookmarked
// pages to be completed.
Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
let search = "http://ex";
let baseURL = "http://example.com/";
let bookmarkedURL = baseURL + "bookmarked";
// Add visits for three different URLs all sharing the same origin, and then
// bookmark the second one. After that, the origin should be autofilled. The
// reason for adding unbookmarked visits before and after adding the
// bookmarked visit is to make sure our aggregate SQL query for determining
// whether an origin is bookmarked is correct.
await PlacesTestUtils.addVisits([
{
uri: baseURL + "other1",
},
]);
let context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${search}/`,
fallbackTitle: `${search}/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
});
await PlacesTestUtils.addVisits([
{
uri: bookmarkedURL,
},
]);
context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${search}/`,
fallbackTitle: `${search}/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
});
await PlacesTestUtils.addVisits([
{
uri: baseURL + "other2",
},
]);
context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${search}/`,
fallbackTitle: `${search}/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
});
// Now bookmark the second URL. It should be suggested and completed.
await PlacesTestUtils.addBookmarkWithDetails({
uri: bookmarkedURL,
});
context = createContext(search, { isPrivate: false });
await check_results({
context,
autofilled: "http://example.com/",
completed: baseURL,
matches: [
makeVisitResult(context, {
uri: baseURL,
fallbackTitle: UrlbarTestUtils.trimURL(baseURL),
heuristic: true,
}),
makeBookmarkResult(context, {
uri: bookmarkedURL,
title: "A bookmark",
}),
],
});
await cleanup();
});
// When the autofilled URL is `example.com/`, a visit for `example.com/?` should
// not be included in the results since it dupes the autofill result.
add_task(async function searchParams() {
await PlacesTestUtils.addVisits([
]);
// First, do a search with autofill disabled to make sure the visits were
// properly added. `example.com/?foo` has the highest frecency because it was
// added last; `example.com/?` has the next highest. `example.com/` dupes
// `example.com/?`, so it should not appear.
UrlbarPrefs.set("autoFill", false);
let context = createContext("ex", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for http://example.com/?foo",
}),
makeVisitResult(context, {
title: "test visit for http://example.com/?",
}),
],
});
// Now do a search with autofill enabled. This time `example.com/` will be
// autofilled, and since `example.com/?` dupes it, `example.com/?` should not
// appear.
UrlbarPrefs.clear("autoFill");
context = createContext("ex", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "http://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for http://example.com/",
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for http://example.com/?foo",
}),
],
});
await cleanup();
});
// When the autofilled URL is `example.com/`, a visit for `example.com/?` should
// not be included in the results since it dupes the autofill result. (Same as
// the previous task but with https URLs instead of http. There shouldn't be any
// substantive difference.)
add_task(async function searchParams_https() {
await PlacesTestUtils.addVisits([
]);
// First, do a search with autofill disabled to make sure the visits were
// properly added. `example.com/?foo` has the highest frecency because it was
// added last; `example.com/?` has the next highest. `example.com/` dupes
// `example.com/?`, so it should not appear.
UrlbarPrefs.set("autoFill", false);
let context = createContext("ex", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.com/?foo",
}),
makeVisitResult(context, {
title: "test visit for https://example.com/?",
}),
],
});
// Now do a search with autofill enabled. This time `example.com/` will be
// autofilled, and since `example.com/?` dupes it, `example.com/?` should not
// appear.
UrlbarPrefs.clear("autoFill");
context = createContext("ex", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/",
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.com/?foo",
}),
],
});
await cleanup();
});
// Checks an origin that looks like a prefix: a scheme with no dots + a port.
add_task(async function originLooksLikePrefix() {
let hostAndPort = "localhost:8888";
let address = `http://${hostAndPort}/`;
await PlacesTestUtils.addVisits([{ uri: address }]);
// addTestSuggestionsEngine adds a search engine
// with localhost as a server, so we have to disable the
// TTS result or else it will show up as a second result
// when searching l to localhost
UrlbarPrefs.set("suggest.engines", false);
for (let search of ["lo", "localhost", "localhost:", "localhost:8888"]) {
let context = createContext(search, { isPrivate: false });
await check_results({
context,
autofilled: hostAndPort + "/",
completed: address,
matches: [
makeVisitResult(context, {
uri: address,
title: `test visit for http://${hostAndPort}/`,
heuristic: true,
}),
],
});
}
await cleanup();
});
// Checks an origin whose prefix is "about:".
add_task(async function about() {
const testData = [
{
uri: "about:config",
input: "conf",
results: [
context =>
makeSearchResult(context, {
engineName: "Suggestions",
heuristic: true,
}),
context =>
makeBookmarkResult(context, {
uri: "about:config",
title: "A bookmark",
}),
],
},
{
uri: "about:blank",
input: "about:blan",
results: [
context =>
makeVisitResult(context, {
uri: "about:blan",
fallbackTitle: "about:blan",
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
heuristic: true,
}),
context =>
makeBookmarkResult(context, {
uri: "about:blank",
title: "A bookmark",
}),
],
},
];
for (const { uri, input, results } of testData) {
await PlacesTestUtils.addBookmarkWithDetails({ uri });
const context = createContext(input, { isPrivate: false });
await check_results({
context,
matches: results.map(f => f(context)),
});
await cleanup();
}
});
// Checks an origin whose prefix is "place:".
add_task(async function place() {
const testData = [
{
uri: "place:transition=7&sort=4",
input: "tran",
},
{
uri: "place:transition=7&sort=4",
input: "place:tran",
},
];
for (const { uri, input } of testData) {
await PlacesTestUtils.addBookmarkWithDetails({ uri });
const context = createContext(input, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: "Suggestions",
heuristic: true,
}),
],
});
await cleanup();
}
});
add_task(async function nullTitle() {
await doTitleTest({
visits: [
{
// Set title of visits data to an empty string causes
// the title to be null in the database.
title: "",
frecency: 100,
},
{
title: "high frecency",
frecency: 50,
},
{
title: "low frecency",
frecency: 1,
},
],
input: "example.com",
expected: {
autofilled: "example.com/",
completed: "http://example.com/",
matches: context => [
makeVisitResult(context, {
title: "high frecency",
heuristic: true,
}),
makeVisitResult(context, {
title: "high frecency",
}),
],
},
});
});
add_task(async function domainTitle() {
await doTitleTest({
visits: [
{
title: "example.com",
frecency: 100,
},
{
title: "",
frecency: 50,
},
{
title: "lowest frecency but has title",
frecency: 1,
},
],
input: "example.com",
expected: {
autofilled: "example.com/",
completed: "http://example.com/",
matches: context => [
makeVisitResult(context, {
title: "lowest frecency but has title",
heuristic: true,
}),
makeVisitResult(context, {
title: "www.example.com",
}),
],
},
});
});
add_task(async function exactMatchedTitle() {
await doTitleTest({
visits: [
{
title: "exact match",
frecency: 50,
},
{
title: "high frecency uri",
frecency: 100,
},
],
expected: {
autofilled: "http://example.com/",
completed: "http://example.com/",
matches: context => [
makeVisitResult(context, {
title: "exact match",
heuristic: true,
}),
makeVisitResult(context, {
title: "high frecency uri",
}),
],
},
});
});
async function doTitleTest({ visits, input, expected }) {
await PlacesTestUtils.addVisits(visits);
for (const { uri, frecency } of visits) {
// Prepare data.
await PlacesUtils.withConnectionWrapper("test::doTitleTest", async db => {
await db.execute(
`UPDATE moz_places SET frecency = :frecency, recalc_frecency=0 WHERE url = :url`,
{
frecency,
url: uri,
}
);
await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies();
});
}
const context = createContext(input, { isPrivate: false });
await check_results({
context,
autofilled: expected.autofilled,
completed: expected.completed,
matches: expected.matches(context),
});
await cleanup();
}