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/. */
/**
* Tests that old results from UrlbarProviderAutofill do not overwrite results
* from UrlbarProviderHeuristicFallback after the autofillable query is
* cancelled. See bug 1653436.
*/
const { setTimeout } = ChromeUtils.importESModule(
"resource://gre/modules/Timer.sys.mjs"
);
ChromeUtils.defineESModuleGetters(this, {
UrlbarProviderAutofill: "resource:///modules/UrlbarProviderAutofill.sys.mjs",
});
/**
* A test provider that waits before returning results to simulate a slow DB
* lookup.
*/
class SlowHeuristicProvider extends UrlbarTestUtils.TestProvider {
constructor({ results }) {
const delayResultsPromise = new Promise(resolve =>
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(resolve, 300)
);
super({
name: "MyProvider",
type: UrlbarUtils.PROVIDER_TYPE.HEURISTIC,
results,
delayResultsPromise,
});
}
}
/**
* A fast provider that alerts the test when it has added its results.
*/
class FastHeuristicProvider extends UrlbarTestUtils.TestProvider {
get type() {
return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
}
async startQuery(context, add) {
this._context = context;
for (let result of this.results) {
add(this, result);
}
Services.obs.notifyObservers(null, "results-added");
}
}
add_setup(async function () {
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("browser.urlbar.suggest.searches");
});
Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
});
/**
* Tests that UrlbarProvidersManager._heuristicProviderTimer is cancelled when
* a query is cancelled.
*/
add_task(async function timerIsCancelled() {
let context = createContext("m", { isPrivate: false });
await PlacesTestUtils.promiseAsyncUpdates();
info("Manually set up query and then overwrite it.");
// slowProvider is a stand-in for a slow UrlbarProviderPlaces returning a
// non-heuristic result.
let slowProvider = new SlowHeuristicProvider({
results: [
makeVisitResult(context, {
title: `mozilla.org/`,
}),
],
});
UrlbarProvidersManager.registerProvider(slowProvider);
// fastProvider is a stand-in for a fast Autofill returning a heuristic
// result.
let fastProvider = new FastHeuristicProvider({
results: [
makeVisitResult(context, {
title: `mozilla.com/`,
heuristic: true,
}),
],
});
UrlbarProvidersManager.registerProvider(fastProvider);
let firstContext = createContext("m", {
providers: [slowProvider.name, fastProvider.name],
});
let secondContext = createContext("ma", {
providers: [slowProvider.name, fastProvider.name],
});
let controller = UrlbarTestUtils.newMockController();
let queryRecieved, queryCancelled;
const controllerListener = {
onQueryResults(queryContext) {
Assert.equal(
queryContext,
secondContext,
"Only the second query should finish."
);
queryRecieved = true;
},
onQueryCancelled(queryContext) {
Assert.equal(
queryContext,
firstContext,
"The first query should be cancelled."
);
Assert.ok(!queryCancelled, "No more than one query should be cancelled.");
queryCancelled = true;
},
};
controller.addQueryListener(controllerListener);
// Wait until FastProvider sends its results to the providers manager.
// Then they will be queued up in a _heuristicProvidersTimer, waiting for
// the results from SlowProvider.
let resultsAddedPromise = new Promise(resolve => {
let observe = async () => {
Services.obs.removeObserver(observe, "results-added");
// Fire the second query to cancel the first.
await controller.startQuery(secondContext);
resolve();
};
Services.obs.addObserver(observe, "results-added");
});
controller.startQuery(firstContext);
await resultsAddedPromise;
Assert.ok(queryCancelled, "At least one query was cancelled.");
Assert.ok(queryRecieved, "At least one query finished.");
controller.removeQueryListener(controllerListener);
});
/**
* Tests that old autofill results aren't displayed after a query is cancelled.
* See bug 1653436.
*/
add_task(async function autofillIsCleared() {
/**
* Steps:
* 1. Start query.
* 2. Allow UrlbarProviderAutofill to start _getAutofillResult.
* 3. Execute a new query with no autofill match, cancelling the first
* query.
* 4. Test that the old result from UrlbarProviderAutofill isn't displayed.
*/
await PlacesTestUtils.addVisits("http://example.com");
let firstContext = createContext("e", {
providers: ["Autofill", "HeuristicFallback"],
});
let secondContext = createContext("em", {
providers: ["Autofill", "HeuristicFallback"],
});
info("Sanity check: The first query autofills and the second does not.");
await check_results({
firstContext,
autofilled: "example.com",
completed: "http://example.com/",
matches: [
makeVisitResult(firstContext, {
title: "example.com",
heuristic: true,
}),
],
});
await check_results({
secondContext,
matches: [
makeSearchResult(secondContext, {
engineName: (await Services.search.getDefault()).name,
providerName: "HeuristicFallback",
heuristic: true,
}),
],
});
// Refresh our queries
firstContext = createContext("e", {
providers: ["Autofill", "HeuristicFallback"],
});
secondContext = createContext("em", {
providers: ["Autofill", "HeuristicFallback"],
});
// Set up controller to observe queries.
let controller = UrlbarTestUtils.newMockController();
let queryRecieved, queryCancelled;
const controllerListener = {
onQueryResults(queryContext) {
Assert.equal(
queryContext,
secondContext,
"Only the second query should finish."
);
queryRecieved = true;
},
onQueryCancelled(queryContext) {
Assert.equal(
queryContext,
firstContext,
"The first query should be cancelled."
);
Assert.ok(
!UrlbarProviderAutofill._autofillData,
"The first result should not have populated autofill data."
);
Assert.ok(!queryCancelled, "No more than one query should be cancelled.");
queryCancelled = true;
},
};
controller.addQueryListener(controllerListener);
// Intentionally do not await this first query.
controller.startQuery(firstContext);
await controller.startQuery(secondContext);
Assert.ok(queryCancelled, "At least one query was cancelled.");
Assert.ok(queryRecieved, "At least one query finished.");
controller.removeQueryListener(controllerListener);
await cleanupPlaces();
});