gecko-dev/browser/components/urlbar/tests/browser-updateResults/browser_appendSpanCount.js
Drew Willcoxon 3dd0ab83c1 Bug 1701193 - Don't place suggestedIndex results in the wrong spot during view updates. r=mak
This should fix flickering related to suggested indexes once and for all, knock
on wood. It fixes the view-update logic so that if we encounter a new
suggestedIndex result that can't be placed in the correct spot during the first
loop, we stop trying to update rows at that point and instead mark the remaining
rows as stale. Then we reach the loop that appends the remaining results, and we
append them all starting with the suggestedIndex result. Those results are
hidden at first so that the suggestedIndex result never appears in the wrong
spot.

This fixes bug 1701193 and the flickering problem I noted in bug 1701136. It
also fixes the flicker we have right now with the tab-to-search onboarding
result, where during the view update we briefly have 10 results in the view even
though there should only be 9 since the tab-to-search has a span of 2.

At first I had one big test file for this, but not surprisingly it timed out on
some try machines. So I split it up, moved the new files to a new directory, and
moved the two existing browser_updateRows tests there too.

The new tests all do two searches where the first search returns search
suggestions and the second returns URL results. It would be good to test the
opposite too but this patch is already big enough.

Differential Revision: https://phabricator.services.mozilla.com/D110365
2021-04-01 19:26:43 +00:00

180 lines
6.1 KiB
JavaScript

/* 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/. */
// This test makes sure that when the view updates itself and appends new rows,
// the new rows start out hidden when they exceed the current visible result
// span count. It includes a tip result so that it tests a row with > 1 result
// span.
"use strict";
add_task(async function viewUpdateAppendHidden() {
// We'll use this test provider to test specific results. We assume that
// history and bookmarks have been cleared (by init() above).
let provider = new DelayingTestProvider();
UrlbarProvidersManager.registerProvider(provider);
registerCleanupFunction(() => {
UrlbarProvidersManager.unregisterProvider(provider);
});
// We do two searches below without closing the panel. Use "firefox cach" as
// the first query and "firefox cache" as the second so that (1) an
// intervention tip is triggered both times but also so that (2) the queries
// are different each time.
let baseQuery = "firefox cache";
let queries = [baseQuery.substring(0, baseQuery.length - 1), baseQuery];
let maxResults = UrlbarPrefs.get("maxRichResults");
let queryStrings = [];
for (let i = 0; i < maxResults; i++) {
queryStrings.push(`${baseQuery} ${i}`);
}
// First search: Trigger the intervention tip and a view full of search
// suggestions.
provider._results = queryStrings.map(
suggestion =>
new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.SEARCH,
{
query: queries[0],
suggestion,
lowerCaseSuggestion: suggestion.toLocaleLowerCase(),
engine: Services.search.defaultEngine.name,
}
)
);
provider.finishQueryPromise = Promise.resolve();
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: queries[0],
});
// Sanity check the tip result and row count.
let tipResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
Assert.equal(
tipResult.type,
UrlbarUtils.RESULT_TYPE.TIP,
"Result at index 1 is a tip"
);
let tipResultSpan = UrlbarUtils.getSpanForResult(
tipResult.element.row.result
);
Assert.greater(tipResultSpan, 1, "Sanity check: Tip has large result span");
let expectedRowCount = maxResults - tipResultSpan + 1;
Assert.equal(
gURLBar.view._rows.children.length,
expectedRowCount,
"Sanity check: Initial row count takes tip result span into account"
);
// Second search: Change the provider's results so that it has enough history
// to fill up the view. Search suggestion rows cannot be updated to history
// results, so the view will append the history results as new rows.
provider._results = queryStrings.map(title => {
let url = "http://example.com/" + title;
return new UrlbarResult(
UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.RESULT_SOURCE.HISTORY,
{
title,
url,
displayUrl: "http://example.com/" + title,
}
);
});
// Don't allow the search to finish until we check the updated rows. We'll
// accomplish that by adding a mutation observer on the rows and delaying
// resolving the provider's finishQueryPromise. When all new rows have been
// added, we expect the new row count to be:
//
// expectedRowCount // the original row count
// + (expectedRowCount - 2) // the newly added history row count (hidden)
// --------------------------
// (2 * expectedRowCount) - 2
//
// The `- 2` subtracts the heuristic and tip result.
let newExpectedRowCount = 2 * expectedRowCount - 2;
let mutationPromise = new Promise(resolve => {
let observer = new MutationObserver(mutations => {
let childCount = gURLBar.view._rows.children.length;
info(`Rows mutation observer called, childCount now ${childCount}`);
if (newExpectedRowCount <= gURLBar.view._rows.children.length) {
observer.disconnect();
resolve();
}
});
observer.observe(gURLBar.view._rows, { childList: true });
});
// Now do the second search but don't wait for it to finish.
let resolveQuery;
provider.finishQueryPromise = new Promise(
resolve => (resolveQuery = resolve)
);
let queryPromise = UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: queries[1],
});
// Wait for the history rows to be added.
await mutationPromise;
// Check the rows. We can't use UrlbarTestUtils.getDetailsOfResultAt() here
// because it waits for the query to finish.
Assert.equal(
gURLBar.view._rows.children.length,
newExpectedRowCount,
"New expected row count"
);
// stale search rows
for (let i = 2; i < expectedRowCount; i++) {
let row = gURLBar.view._rows.children[i];
Assert.equal(
row.result.type,
UrlbarUtils.RESULT_TYPE.SEARCH,
`Result at index ${i} is a search result`
);
Assert.ok(
gURLBar.view._isElementVisible(row),
`Search result at index ${i} is visible`
);
Assert.equal(
row.getAttribute("stale"),
"true",
`Search result at index ${i} is stale`
);
}
// new hidden history rows
for (let i = expectedRowCount; i < newExpectedRowCount; i++) {
let row = gURLBar.view._rows.children[i];
Assert.equal(
row.result.type,
UrlbarUtils.RESULT_TYPE.URL,
`Result at index ${i} is a URL result`
);
Assert.ok(
!gURLBar.view._isElementVisible(row),
`URL result at index ${i} is hidden`
);
Assert.ok(
!row.hasAttribute("stale"),
`URL result at index ${i} is not stale`
);
}
// Finish the query, and we're done.
resolveQuery();
await queryPromise;
await UrlbarTestUtils.promisePopupClose(window);
gURLBar.handleRevert();
// We unregister the provider above in a cleanup function so we don't
// accidentally interfere with later tests, but do it here too in case we add
// more tasks to this test. It's harmless to call more than once.
UrlbarProvidersManager.unregisterProvider(provider);
});