Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Errors

/* Any copyright is dedicated to the Public Domain.
/**
* This tests the urlbar adaptive behavior powered by input history.
*/
"use strict";
async function bumpScore(
uri,
searchString,
counts,
useMouseClick = false,
needToLoad = false
) {
if (counts.visits) {
let visits = new Array(counts.visits).fill(uri);
await PlacesTestUtils.addVisits(visits);
}
if (counts.picks) {
for (let i = 0; i < counts.picks; ++i) {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: searchString,
});
let promise = needToLoad
? BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser)
: BrowserTestUtils.waitForDocLoadAndStopIt(
uri,
gBrowser.selectedBrowser
);
// Look for the expected uri.
while (gURLBar.untrimmedValue != uri) {
EventUtils.synthesizeKey("KEY_ArrowDown", {});
}
if (useMouseClick) {
let element = UrlbarTestUtils.getSelectedRow(window);
EventUtils.synthesizeMouseAtCenter(element, {});
} else {
EventUtils.synthesizeKey("KEY_Enter", {});
}
await promise;
}
}
await PlacesTestUtils.promiseAsyncUpdates();
}
async function decayInputHistory() {
await Cc["@mozilla.org/places/frecency-recalculator;1"]
.getService(Ci.nsIObserver)
.wrappedJSObject.decay();
}
async function isPageInInputHistory(url) {
let db = await PlacesUtils.promiseDBConnection();
let rows = await db.executeCached(
`SELECT 1
FROM moz_inputhistory i
JOIN moz_places h ON h.id = i.place_id
WHERE h.url = :url`,
{ url }
);
return rows?.length > 0;
}
async function isInputHistoryUrlInResults(url) {
for (let i = 0; i < UrlbarTestUtils.getResultCount(window); ++i) {
const result = await UrlbarTestUtils.getRowAt(window, i).result;
if (result.providerName == "InputHistory") {
if (result.payload.url == url) {
return true;
}
}
}
return false;
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
// We don't want autofill to influence this test.
["browser.urlbar.autoFill", false],
],
});
registerCleanupFunction(async () => {
await PlacesUtils.history.clear();
await PlacesUtils.bookmarks.eraseEverything();
});
});
add_task(async function test_adaptive_with_search_terms() {
let url1 = "http://site.tld/1";
let url2 = "http://site.tld/2";
info("Same visit count, same picks, one partial match, one exact match");
await PlacesUtils.history.clear();
await bumpScore(url1, "si", { visits: 3, picks: 3 });
await bumpScore(url2, "site", { visits: 3, picks: 3 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url1, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url2, "Check second result");
info(
"Same visit count, same picks, one partial match, one exact match, invert"
);
await PlacesUtils.history.clear();
await bumpScore(url1, "site", { visits: 3, picks: 3 });
await bumpScore(url2, "si", { visits: 3, picks: 3 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url2, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url1, "Check second result");
info("Same visit count, different picks, both exact match");
await PlacesUtils.history.clear();
await bumpScore(url1, "si", { visits: 3, picks: 3 });
await bumpScore(url2, "si", { visits: 3, picks: 1 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url1, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url2, "Check second result");
info("Same visit count, different picks, both exact match, invert");
await PlacesUtils.history.clear();
await bumpScore(url1, "si", { visits: 3, picks: 1 });
await bumpScore(url2, "si", { visits: 3, picks: 3 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url2, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url1, "Check second result");
info("Same visit count, different picks, both partial match");
await PlacesUtils.history.clear();
await bumpScore(url1, "site", { visits: 3, picks: 3 });
await bumpScore(url2, "site", { visits: 3, picks: 1 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url1, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url2, "Check second result");
info("Same visit count, different picks, both partial match, invert");
await PlacesUtils.history.clear();
await bumpScore(url1, "site", { visits: 3, picks: 1 });
await bumpScore(url2, "site", { visits: 3, picks: 3 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url2, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url1, "Check second result");
});
add_task(async function test_adaptive_with_decay() {
let url1 = "http://site.tld/1";
let url2 = "http://site.tld/2";
info("Same visit count, same picks, both exact match, decay first");
await PlacesUtils.history.clear();
await bumpScore(url1, "si", { visits: 3, picks: 3 });
await decayInputHistory();
await bumpScore(url2, "si", { visits: 3, picks: 3 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url2, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url1, "Check second result");
info("Same visit count, same picks, both exact match, decay second");
await PlacesUtils.history.clear();
await bumpScore(url2, "si", { visits: 3, picks: 3 });
await decayInputHistory();
await bumpScore(url1, "si", { visits: 3, picks: 3 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url1, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url2, "Check second result");
});
add_task(async function test_adaptive_limited() {
let url1 = "http://site.tld/1";
let url2 = "http://site.tld/2";
info("Same visit count, same picks, both exact match, decay first");
await PlacesUtils.history.clear();
await bumpScore(url1, "si", { visits: 3, picks: 3 });
await decayInputHistory();
await bumpScore(url2, "si", { visits: 3, picks: 3 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url2, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url1, "Check second result");
info("Same visit count, same picks, both exact match, decay second");
await PlacesUtils.history.clear();
await bumpScore(url2, "si", { visits: 3, picks: 3 });
await decayInputHistory();
await bumpScore(url1, "si", { visits: 3, picks: 3 });
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url1, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url2, "Check second result");
});
add_task(async function test_adaptive_limited() {
info("Up to 3 adaptive results should be added at the top, then enqueued");
await PlacesUtils.history.clear();
await PlacesUtils.bookmarks.eraseEverything();
// Add as many adaptive results as maxRichResults.
let n = UrlbarPrefs.get("maxRichResults");
let urls = Array(n)
.fill(0)
.map((e, i) => "http://site.tld/" + i);
for (let url of urls) {
await bumpScore(url, "site", { visits: 1, picks: 1 });
}
// Add a matching bookmark with an higher frecency.
await PlacesTestUtils.addVisits(url);
let bm = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
title: "test_site_book",
url,
});
// After 1 heuristic and 3 input history results.
let expectedBookmarkIndex = 4;
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "site",
});
let result = await UrlbarTestUtils.getDetailsOfResultAt(
window,
expectedBookmarkIndex
);
Assert.equal(result.url, url, "Check bookmarked result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, n - 1);
Assert.equal(
UrlbarTestUtils.getResultCount(window),
n,
"Check all the results are filled"
);
Assert.ok(
result.url.startsWith("http://site.tld"),
"Check last adaptive result"
);
await PlacesUtils.bookmarks.remove(bm);
});
add_task(async function test_adaptive_behaviors() {
info(
"Check adaptive results are not provided regardless of the requested behavior"
);
await PlacesUtils.history.clear();
await PlacesUtils.bookmarks.eraseEverything();
// Add an adaptive entry.
let historyUrl = "http://site.tld/1";
await bumpScore(historyUrl, "site", { visits: 1, picks: 1 });
let bookmarkURL = "http://bookmarked.site.tld/1";
let bm = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
title: "test_book",
url: bookmarkURL,
});
await SpecialPowers.pushPrefEnv({
set: [
// Search only bookmarks.
["browser.urlbar.suggest.bookmark", true],
["browser.urlbar.suggest.history", false],
],
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "site",
});
let result = (await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1))
.result;
Assert.equal(result.payload.url, bookmarkURL, "Check bookmarked result");
Assert.notEqual(
result.providerName,
"InputHistory",
"The bookmarked result is not from InputHistory."
);
Assert.equal(
UrlbarTestUtils.getResultCount(window),
2,
"Check there are no unexpected results"
);
await PlacesUtils.bookmarks.remove(bm);
// Repeat the previous case but now the bookmark has the same URL as the
// history result. We expect the returned result comes from InputHistory.
bm = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
title: "test_book",
url: historyUrl,
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "sit",
});
result = (await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1))
.result;
Assert.equal(result.payload.url, historyUrl, "Check bookmarked result");
Assert.equal(
result.providerName,
"InputHistory",
"The bookmarked result is from InputHistory."
);
Assert.equal(
result.source,
UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
"The input history result is a bookmark."
);
Assert.equal(
UrlbarTestUtils.getResultCount(window),
2,
"Check there are no unexpected results"
);
await SpecialPowers.popPrefEnv();
await SpecialPowers.pushPrefEnv({
set: [
// Search only open pages. We don't provide an open page, but we want to
// enable at least one of these prefs so that UrlbarProviderInputHistory
// is active.
["browser.urlbar.suggest.bookmark", false],
["browser.urlbar.suggest.history", false],
["browser.urlbar.suggest.openpage", true],
],
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "site",
});
Assert.equal(
UrlbarTestUtils.getResultCount(window),
1,
"There is no adaptive history result because it is not an open page."
);
await SpecialPowers.popPrefEnv();
// Clearing history but not deleting the bookmark. This simulates the case
// where the user has cleared their history or is using permanent private
// browsing mode.
await PlacesUtils.history.clear();
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.suggest.bookmark", true],
["browser.urlbar.suggest.history", false],
["browser.urlbar.suggest.openpage", false],
],
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "sit",
});
result = (await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1))
.result;
Assert.equal(result.payload.url, historyUrl, "Check bookmarked result");
Assert.equal(
result.providerName,
"InputHistory",
"The bookmarked result is from InputHistory."
);
Assert.equal(
result.source,
UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
"The input history result is a bookmark."
);
Assert.equal(
UrlbarTestUtils.getResultCount(window),
2,
"Check there are no unexpected results"
);
await PlacesUtils.bookmarks.remove(bm);
await SpecialPowers.popPrefEnv();
});
add_task(async function test_adaptive_mouse() {
info("Check adaptive results are updated on mouse picks");
let url1 = "http://site.tld/1";
let url2 = "http://site.tld/2";
info("Same visit count, different picks");
await PlacesUtils.history.clear();
await bumpScore(url1, "site", { visits: 3, picks: 3 }, true);
await bumpScore(url2, "site", { visits: 3, picks: 1 }, true);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url1, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url2, "Check second result");
info("Same visit count, different picks, invert");
await PlacesUtils.history.clear();
await bumpScore(url1, "site", { visits: 3, picks: 1 }, true);
await bumpScore(url2, "site", { visits: 3, picks: 3 }, true);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url2, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url1, "Check second result");
});
add_task(async function test_adaptive_searchmode() {
info("Check adaptive history is not shown in search mode.");
let suggestionsEngine = await SearchTestUtils.promiseNewSearchEngine({
url: getRootDirectory(gTestPath) + "searchSuggestionEngine.xml",
});
let url1 = "http://site.tld/1";
let url2 = "http://site.tld/2";
info("Sanity check: adaptive history is shown for a normal search.");
await PlacesUtils.history.clear();
await bumpScore(url1, "site", { visits: 3, picks: 3 }, true);
await bumpScore(url2, "site", { visits: 3, picks: 1 }, true);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(result.url, url1, "Check first result");
result = await UrlbarTestUtils.getDetailsOfResultAt(window, 2);
Assert.equal(result.url, url2, "Check second result");
info("Entering search mode.");
// enterSearchMode checks internally that our site.tld URLs are not shown.
await UrlbarTestUtils.enterSearchMode(window, {
engineName: suggestionsEngine.name,
});
await Services.search.removeEngine(suggestionsEngine);
});
add_task(async function test_ignore_case() {
const url1 = "http://example.com/yes";
const url2 = "http://example.com/no";
await PlacesUtils.history.clear();
await PlacesTestUtils.addVisits([url1, url2]);
await UrlbarUtils.addToInputHistory(url1, "SampLE");
await UrlbarUtils.addToInputHistory(url1, "SaMpLE");
await UrlbarUtils.addToInputHistory(url1, "SAMPLE");
await UrlbarUtils.addToInputHistory(url1, "sample");
await UrlbarUtils.addToInputHistory(url2, "sample");
await UrlbarUtils.addToInputHistory(url2, "sample");
await UrlbarUtils.addToInputHistory(url2, "sample");
await UrlbarUtils.addToInputHistory(url2, "sample");
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "sAM",
});
const result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(
result.url,
url1,
"Seaching for input history is case-insensitive"
);
});
add_task(async function test_adaptive_history_in_privatewindow() {
info(
"Check adaptive history is not shown in private window as tab switching candidate."
);
await PlacesUtils.history.clear();
info("Add a test url as an input history.");
const url = "http://example.com/";
// We need to wait for loading the page in order to register the url into
// moz_openpages_temp table.
await bumpScore(url, "exa", { visits: 1, picks: 1 }, false, true);
info("Check the url could be registered properly.");
const connection = await PlacesUtils.promiseLargeCacheDBConnection();
const rows = await connection.executeCached(
"SELECT userContextId FROM moz_openpages_temp WHERE url = :url",
{ url }
);
Assert.equal(rows.length, 1, "Length of rows for the url is 1.");
Assert.greaterOrEqual(
rows[0].getResultByName("userContextId"),
0,
"The url is registered as non-private-browsing context."
);
info("Open popup in private window.");
const privateWindow = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window: privateWindow,
value: "ex",
});
info("Check the popup results.");
let hasResult = false;
for (let i = 0; i < UrlbarTestUtils.getResultCount(privateWindow); i++) {
const result = await UrlbarTestUtils.getDetailsOfResultAt(privateWindow, i);
if (result.url !== url) {
continue;
}
Assert.notEqual(
result.type,
UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
"Result type of the url is not for tab switch."
);
hasResult = true;
}
Assert.ok(hasResult, "Popup has a result for the url.");
await BrowserTestUtils.closeWindow(privateWindow);
});
add_task(async function test_adaptive_dismiss() {
info("Check dismissing an adaptive history result");
let url1 = "http://site.tld/1";
let url2 = "http://site.tld/2";
info("Sanity check: adaptive history is shown for a normal search.");
await PlacesUtils.history.clear();
await bumpScore(url1, "site", { visits: 3, picks: 3 }, true);
await bumpScore(url2, "site", { visits: 3, picks: 1 }, true);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
let result = UrlbarTestUtils.getRowAt(window, 1).result;
Assert.equal(result.payload.url, url1, "Check result #1 URL");
Assert.equal(result.providerName, "InputHistory", "Check result #1 provider");
result = UrlbarTestUtils.getRowAt(window, 2).result;
Assert.equal(result.payload.url, url2, "Check result #2 URL");
Assert.equal(result.providerName, "InputHistory", "Check result #2 provider");
let waitForHistoryRemoval =
PlacesTestUtils.waitForNotification("page-removed");
await UrlbarTestUtils.openResultMenuAndClickItem(window, "dismiss", {
resultIndex: 1,
});
await waitForHistoryRemoval;
Assert.ok(
gURLBar.view.isOpen,
"The view should remain open after clicking the command"
);
Assert.ok(
!(await isInputHistoryUrlInResults(url1)),
"Check result has been removed"
);
Assert.strictEqual(
await PlacesUtils.history.fetch(url1),
null,
"The removed page should not be in browsing history"
);
Assert.ok(
!(await isPageInInputHistory(url1)),
"The removed page should not be in input history"
);
Assert.ok(
await isInputHistoryUrlInResults(url2),
"Check result has been retained"
);
Assert.notStrictEqual(
await PlacesUtils.history.fetch(url2),
null,
"The non removed page should still be in history"
);
Assert.ok(
await isPageInInputHistory(url2),
"The non removed page should still be in input history"
);
});
add_task(async function test_bookmarked_adaptive_dismiss() {
info("Check dismissing a bookmarked adaptive history result");
let url = "http://mysite.tld/";
info("Sanity check: adaptive history is shown for a normal search.");
await PlacesUtils.history.clear();
await bumpScore(url, "site", { visits: 3, picks: 3 }, true);
await PlacesUtils.bookmarks.insert({
url,
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "si",
});
let result = UrlbarTestUtils.getRowAt(window, 1).result;
Assert.equal(result.payload.url, url, "Check result #1 URL");
Assert.equal(result.providerName, "InputHistory", "Check result #1 provider");
let waitForHistoryRemoval =
PlacesTestUtils.waitForNotification("page-removed");
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Delete", { shiftKey: true });
await waitForHistoryRemoval;
Assert.ok(
gURLBar.view.isOpen,
"The view should remain open after removing history"
);
Assert.ok(
!(await isInputHistoryUrlInResults(url)),
"Check result has been removed"
);
Assert.ok(
!(await PlacesUtils.history.hasVisits(url)),
"The removed page should not be in browsing history"
);
Assert.ok(
!(await isPageInInputHistory(url)),
"The removed page should be in input history"
);
});