Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE HTML>
<html>
<!--
Test the login-filter component
-->
<head>
<meta charset="utf-8">
<title>Test the login-filter component</title>
<script type="module" src="chrome://browser/content/aboutlogins/components/login-filter.mjs"></script>
<script type="module" src="chrome://browser/content/aboutlogins/components/login-list.mjs"></script>
<script src="aboutlogins_common.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display">
</p>
<div id="content" style="display: none">
<iframe id="templateFrame" src="chrome://browser/content/aboutlogins/aboutLogins.html"
sandbox="allow-same-origin"></iframe>
</div>
<pre id="test">
</pre>
<script>
/** Test the login-filter component **/
let gLoginFilter;
let gLoginList;
add_setup(async () => {
let templateFrame = document.getElementById("templateFrame");
let displayEl = document.getElementById("display");
importDependencies(templateFrame, displayEl);
gLoginFilter = document.createElement("login-filter");
displayEl.appendChild(gLoginFilter);
gLoginList = document.createElement("login-list");
displayEl.appendChild(gLoginList);
});
add_task(async function test_empty_filter() {
ok(gLoginFilter, "loginFilter exists");
is(gLoginFilter.shadowRoot.querySelector("input").value, "", "Initially empty");
});
add_task(async function test_input_events() {
let filterEvent = null;
window.addEventListener("AboutLoginsFilterLogins", event => filterEvent = event);
let input = SpecialPowers.wrap(gLoginFilter.shadowRoot.querySelector("input"));
input.setUserInput("test");
ok(filterEvent, "Filter event received");
is(filterEvent.detail, "test", "Event includes input value");
});
add_task(async function test_list_filtered() {
const LOGINS = [{
guid: "123456789",
origin: "https://example.com",
username: "user1",
password: "pass1",
}, {
guid: "987654321",
origin: "https://example.com",
username: "user2",
password: "pass2",
}];
gLoginList.setLogins(LOGINS);
let tests = [
["", 2],
[LOGINS[0].username, 1],
[LOGINS[0].username + "-notfound", 0],
[LOGINS[0].username.substr(2, 3), 1],
["", 2],
// The password is also used for search when MP is disabled.
[LOGINS[0].password, 1],
[LOGINS[0].password + "-notfound", 0],
[LOGINS[0].password.substr(2, 3), 1],
["", 2],
[LOGINS[0].origin, 2],
[LOGINS[0].origin + "-notfound", 0],
[LOGINS[0].origin.substr(2, 3), 2],
["", 2],
// The guid is not used for search.
[LOGINS[0].guid, 0],
[LOGINS[0].guid + "-notfound", 0],
[LOGINS[0].guid.substr(0, 2), 0],
["", 2],
];
let loginFilterInput = gLoginFilter.shadowRoot.querySelector("input");
loginFilterInput.focus();
for (let i = 0; i < tests.length; i++) {
info("Testcase: " + i);
let testObj = {
testCase: i,
query: tests[i][0],
resultExpectedCount: tests[i][1],
};
let filterLength = loginFilterInput.value.length;
while (filterLength-- > 0) {
sendKey("BACK_SPACE");
}
sendString(testObj.query);
await SimpleTest.promiseWaitForCondition(() => {
let countElement = gLoginList.shadowRoot.querySelector(".count");
return countElement.hasAttribute("data-l10n-args") &&
JSON.parse(countElement.getAttribute("data-l10n-args")).count == testObj.resultExpectedCount;
}, `Waiting for the search result count to update to ${testObj.resultExpectedCount} (tc#${testObj.testCase})`);
}
});
add_task(async function test_keys_in_filter() {
const LOGINS = [{
guid: "123456789",
origin: "https://example.com",
username: "user1",
password: "pass1",
}, {
guid: "987654321",
origin: "https://example.com",
username: "user2",
password: "pass2",
}, {
guid: "333333333",
origin: "https://example.com",
username: "user3",
password: "pass3",
}];
gLoginList.setLogins(LOGINS);
const ol = gLoginList.shadowRoot.querySelector("ol");
const loginFilterInput = gLoginFilter.shadowRoot.querySelector("input");
loginFilterInput.focus();
// Up/down keys must select previous/next item in the list
function pressKeyAndExpectSelection(key, selectedIndex) {
sendKey(key);
ok(ol.querySelectorAll("login-list-item[data-guid]:not([hidden])")[selectedIndex]?.classList?.contains("keyboard-selected"),
`item ${selectedIndex} should be marked as keyboard-selected`);
is(ol.querySelector(".selected").dataset.guid, LOGINS[selectedIndex].guid, `item ${selectedIndex} must be selected`);
}
pressKeyAndExpectSelection("DOWN", 1);
pressKeyAndExpectSelection("DOWN", 2);
// ENTER key in search box must click on selected item in the list
sendKey("RETURN");
is(ol.querySelector(".selected").dataset.guid, LOGINS[2].guid, "item 2 must still be selected");
pressKeyAndExpectSelection("DOWN", 2);
pressKeyAndExpectSelection("UP", 1);
pressKeyAndExpectSelection("UP", 0);
pressKeyAndExpectSelection("UP", 0);
// ESC must clear search box
async function expectItemCount(count) {
await SimpleTest.promiseWaitForCondition(() =>
JSON.parse(gLoginList.shadowRoot.querySelector(".count").getAttribute("data-l10n-args"))?.count == count,
`Waiting for the search result count to update to ${count}`);
}
sendString("unique string");
await expectItemCount(0);
sendKey("Escape");
ok(!loginFilterInput.value, "ESC must clear filter input");
await expectItemCount(LOGINS.length);
});
</script>
</body>
</html>