Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test runs only with pattern: os != 'android'
- Manifest: browser/components/urlbar/tests/unit/xpcshell.toml
/* Any copyright is dedicated to the Public Domain.
// Tests the in-memory adaptive-autofill backspace counter
"use strict";
const BACKSPACE_THRESHOLD = UrlbarPrefs.get("autoFill.backspaceThreshold");
function resetCounts() {
UrlbarUtils._backspaceBlocks.clear();
}
registerCleanupFunction(async () => {
resetCounts();
await PlacesUtils.history.clear();
});
add_task(async function backspaceBlockKey_return_values() {
Assert.equal(
"origin:example.com",
"Origin URL maps to origin: scope"
);
Assert.equal(
"page:example.com",
"Page URL maps to page: scope"
);
Assert.equal(
"page:example.com",
"www. prefix is stripped from the basehost"
);
Assert.equal(
"page:example.com",
"URL with query string is a page URL"
);
Assert.equal(
UrlbarUtils._backspaceBlockKey("not a url"),
null,
"Unparseable URL returns null"
);
});
add_task(async function recordAutofillBackspace_first_call_inserts_one() {
resetCounts();
Assert.equal(
UrlbarUtils._backspaceBlocks.size,
1,
"Map has one entry after the first call"
);
Assert.equal(
UrlbarUtils._backspaceBlocks.get("page:example.com").count,
1,
"Count is 1 after the first call"
);
});
add_task(async function recordAutofillBackspace_below_threshold_no_block() {
resetCounts();
await PlacesTestUtils.addVisits(url);
for (let i = 0; i < BACKSPACE_THRESHOLD - 1; i++) {
await UrlbarUtils.recordAutofillBackspace(url);
}
Assert.equal(
UrlbarUtils._backspaceBlocks.get("page:example.com").count,
BACKSPACE_THRESHOLD - 1,
"Count is at threshold - 1"
);
Assert.equal(
await getOriginColumn(url, "block_pages_until_ms"),
null,
"block_pages_until_ms is not set below threshold"
);
await PlacesUtils.history.clear();
});
add_task(async function recordAutofillBackspace_threshold_blocks_page() {
resetCounts();
await PlacesTestUtils.addVisits(url);
for (let i = 0; i < BACKSPACE_THRESHOLD; i++) {
await UrlbarUtils.recordAutofillBackspace(url);
}
Assert.equal(
UrlbarUtils._backspaceBlocks.get("page:example.com")?.count,
undefined,
"Count is cleared once the threshold fires"
);
Assert.greater(
UrlbarUtils._backspaceBlocks.get("page:example.com")?.blockedAt,
0,
"blockedAt is set once the threshold fires"
);
Assert.greater(
await getOriginColumn(url, "block_pages_until_ms"),
Date.now() - 1000,
"block_pages_until_ms is set for a page URL when the threshold fires"
);
Assert.equal(
await getOriginColumn(url, "block_until_ms"),
null,
"block_until_ms is not set for a page URL"
);
await PlacesUtils.history.clear();
});
add_task(async function recordAutofillBackspace_threshold_blocks_origin() {
resetCounts();
await PlacesTestUtils.addVisits(url);
for (let i = 0; i < BACKSPACE_THRESHOLD; i++) {
await UrlbarUtils.recordAutofillBackspace(url);
}
Assert.equal(
UrlbarUtils._backspaceBlocks.get("origin:example.com")?.count,
undefined,
"Count is cleared once the threshold fires"
);
Assert.greater(
UrlbarUtils._backspaceBlocks.get("origin:example.com")?.blockedAt,
0,
"blockedAt is set once the threshold fires"
);
Assert.greater(
await getOriginColumn(url, "block_until_ms"),
Date.now() - 1000,
"block_until_ms is set for an origin URL when the threshold fires"
);
Assert.equal(
await getOriginColumn(url, "block_pages_until_ms"),
null,
"block_pages_until_ms is not set for an origin URL"
);
await PlacesUtils.history.clear();
});
add_task(async function recordAutofillBackspace_origin_and_page_independent() {
resetCounts();
await PlacesTestUtils.addVisits([originUrl, pageUrl]);
// Drive the origin scope to threshold; the page scope must stay clean.
for (let i = 0; i < BACKSPACE_THRESHOLD; i++) {
await UrlbarUtils.recordAutofillBackspace(originUrl);
}
Assert.greater(
await getOriginColumn(originUrl, "block_until_ms"),
Date.now() - 1000,
"Origin scope blocked"
);
Assert.equal(
await getOriginColumn(pageUrl, "block_pages_until_ms"),
null,
"Page scope is unaffected by origin-scope backspaces"
);
Assert.ok(
!UrlbarUtils._backspaceBlocks.has("page:example.com"),
"No page-scope entry was created"
);
await PlacesUtils.history.clear();
});
add_task(async function recordAutofillBackspace_www_collapses_to_same_key() {
resetCounts();
// Alternate calls between the www and non-www variants of the same URL.
// They must accumulate in a single map entry keyed by basehost.
Assert.equal(UrlbarUtils._backspaceBlocks.size, 1, "Map has only one entry");
Assert.equal(
UrlbarUtils._backspaceBlocks.get("page:example.com").count,
2,
"Both www. and non-www. backspaces accumulate in the same key"
);
});
add_task(async function clearAutofillBackspaceEntryForUrl_clears_one_scope() {
resetCounts();
await UrlbarUtils.recordAutofillBackspace(originUrl);
await UrlbarUtils.recordAutofillBackspace(pageUrl);
Assert.equal(
UrlbarUtils._backspaceBlocks.size,
2,
"Both scopes are populated"
);
UrlbarUtils.clearAutofillBackspaceEntryForUrl(pageUrl);
Assert.ok(
!UrlbarUtils._backspaceBlocks.has("page:example.com"),
"Page-scope entry is cleared"
);
Assert.ok(
UrlbarUtils._backspaceBlocks.has("origin:example.com"),
"Origin-scope entry is preserved"
);
});
add_task(async function clearAutofillBackspaceEntryForUrl_noop_for_missing() {
resetCounts();
// Clearing a URL that has no corresponding map entry is a no-op.
Assert.equal(
UrlbarUtils._backspaceBlocks.size,
1,
"Unrelated entry is untouched"
);
// Clearing with an unparseable URL is a no-op.
UrlbarUtils.clearAutofillBackspaceEntryForUrl("not a url");
Assert.equal(
UrlbarUtils._backspaceBlocks.size,
1,
"Unparseable URL is a no-op"
);
});
add_task(async function recordAutofillBackspace_lru_eviction() {
resetCounts();
let cap = UrlbarUtils._BACKSPACE_BLOCKS_MAX;
for (let i = 0; i < cap; i++) {
}
Assert.equal(UrlbarUtils._backspaceBlocks.size, cap, "Map is at capacity");
Assert.ok(
UrlbarUtils._backspaceBlocks.has("page:host-0.example"),
"Oldest key is present before the cap-exceeding insert"
);
Assert.equal(
UrlbarUtils._backspaceBlocks.size,
cap,
"Size stays at capacity after overflow"
);
Assert.ok(
!UrlbarUtils._backspaceBlocks.has("page:host-0.example"),
"Oldest entry was evicted"
);
Assert.ok(
UrlbarUtils._backspaceBlocks.has("page:overflow.example"),
"New entry is present"
);
resetCounts();
});
add_task(async function recordAutofillBackspace_lru_touch_on_increment() {
resetCounts();
// Insert max unique entries; entry 0 is the oldest.
for (let i = 0; i < UrlbarUtils._BACKSPACE_BLOCKS_MAX; i++) {
}
// Backspace 0 so it becomes most-recent.
// Force an eviction.
Assert.ok(
UrlbarUtils._backspaceBlocks.has("page:host-0.example"),
"Entry was not evicted"
);
Assert.ok(
!UrlbarUtils._backspaceBlocks.has("page:host-1.example"),
"The new oldest entry (host-1) was evicted instead"
);
resetCounts();
});
add_task(async function recordAutofillBackspace_respects_threshold_pref() {
resetCounts();
await PlacesTestUtils.addVisits(url);
UrlbarPrefs.set("autoFill.backspaceThreshold", 5);
try {
for (let i = 0; i < 4; i++) {
await UrlbarUtils.recordAutofillBackspace(url);
}
Assert.equal(
await getOriginColumn(url, "block_pages_until_ms"),
null,
"No block at 4 with threshold = 5"
);
await UrlbarUtils.recordAutofillBackspace(url);
Assert.greater(
await getOriginColumn(url, "block_pages_until_ms"),
Date.now() - 1000,
"Block fires on the 5th call when threshold = 5"
);
} finally {
UrlbarPrefs.clear("autoFill.backspaceThreshold");
}
await PlacesUtils.history.clear();
});
add_task(async function recordAutofillBackspace_uses_block_duration_pref() {
resetCounts();
await PlacesTestUtils.addVisits(url);
const durationMs = 60 * 60 * 1000;
UrlbarPrefs.set("autoFill.backspaceBlockDurationMs", durationMs);
try {
let before = Date.now();
for (let i = 0; i < BACKSPACE_THRESHOLD; i++) {
await UrlbarUtils.recordAutofillBackspace(url);
}
let after = Date.now();
let stored = await getOriginColumn(url, "block_pages_until_ms");
Assert.greaterOrEqual(
stored,
before + durationMs,
"block_pages_until_ms is at least before + duration"
);
Assert.lessOrEqual(
stored,
after + durationMs,
"block_pages_until_ms is at most after + duration"
);
} finally {
UrlbarPrefs.clear("autoFill.backspaceBlockDurationMs");
}
await PlacesUtils.history.clear();
});
add_task(async function recordAutofillBackspace_ignores_unparseable_url() {
resetCounts();
await UrlbarUtils.recordAutofillBackspace("not a url");
Assert.equal(UrlbarUtils._backspaceBlocks.size, 0, "Map is unchanged");
});