зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1563769 - Create login-list-item as a DOM fragment instead of a custom element to reduce overhead. r=MattN
Each custom element had its own shadowRoot, duplicated instances of the style sheet, and localization root. This patch also moves to a single 'click' event listener on the list instead of one for each item. Differential Revision: https://phabricator.services.mozilla.com/D37143 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
423635cba5
Коммит
091478789a
|
@ -73,11 +73,10 @@
|
|||
</template>
|
||||
|
||||
<template id="login-list-item-template">
|
||||
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
|
||||
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/common.css">
|
||||
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/components/login-list-item.css">
|
||||
<li class="login-list-item">
|
||||
<span class="title"></span>
|
||||
<span class="username"></span>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<template id="login-item-template">
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
padding-inline-end: 18px;
|
||||
padding-inline-start: 14px;
|
||||
border-inline-start: 4px solid transparent;
|
||||
border-bottom: 1px solid var(--in-content-box-border-color);
|
||||
}
|
||||
|
||||
:host(:hover) {
|
||||
background-color: var(--in-content-box-background-hover);
|
||||
}
|
||||
|
||||
:host(:hover:active) {
|
||||
background-color: var(--in-content-box-background-active);
|
||||
}
|
||||
|
||||
:host(.keyboard-selected) {
|
||||
border-inline-start-color: var(--in-content-border-active-shadow);
|
||||
background-color: var(--in-content-box-background-odd);
|
||||
}
|
||||
|
||||
:host(.selected) {
|
||||
border-inline-start-color: var(--in-content-border-highlight);
|
||||
background-color: var(--in-content-box-background-hover);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.title,
|
||||
.username {
|
||||
display: block;
|
||||
max-width: 50ch;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
|
@ -2,96 +2,49 @@
|
|||
* 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/. */
|
||||
|
||||
import { recordTelemetryEvent } from "../aboutLoginsUtils.js";
|
||||
|
||||
export default class LoginListItem extends HTMLElement {
|
||||
constructor(login) {
|
||||
super();
|
||||
this._login = login;
|
||||
this.id = login.guid
|
||||
? // Prepend the ID with a string since IDs must not begin with a number.
|
||||
"lli-" + this._login.guid
|
||||
: "new-login-list-item";
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if (this.shadowRoot) {
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* LoginListItemFactory is used instead of the "login-list-item" custom element
|
||||
* since there may be 100s of login-list-items on about:logins and each
|
||||
* custom element carries with it significant overhead when used in large
|
||||
* numbers.
|
||||
*/
|
||||
export default class LoginListItemFactory {
|
||||
static create(login) {
|
||||
let loginListItemTemplate = document.querySelector(
|
||||
"#login-list-item-template"
|
||||
);
|
||||
let shadowRoot = this.attachShadow({ mode: "open" });
|
||||
document.l10n.connectRoot(shadowRoot);
|
||||
shadowRoot.appendChild(loginListItemTemplate.content.cloneNode(true));
|
||||
let loginListItem = loginListItemTemplate.content.cloneNode(true);
|
||||
let listItem = loginListItem.querySelector("li");
|
||||
let title = loginListItem.querySelector(".title");
|
||||
let username = loginListItem.querySelector(".username");
|
||||
|
||||
this._title = this.shadowRoot.querySelector(".title");
|
||||
this._username = this.shadowRoot.querySelector(".username");
|
||||
this.setAttribute("role", "option");
|
||||
listItem.setAttribute("role", "option");
|
||||
|
||||
this.addEventListener("click", this);
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this._login.guid) {
|
||||
delete this.dataset.guid;
|
||||
if (!login.guid) {
|
||||
listItem.id = "new-login-list-item";
|
||||
document.l10n.setAttributes(title, "login-list-item-title-new-login");
|
||||
document.l10n.setAttributes(
|
||||
this._title,
|
||||
"login-list-item-title-new-login"
|
||||
);
|
||||
document.l10n.setAttributes(
|
||||
this._username,
|
||||
username,
|
||||
"login-list-item-subtitle-new-login"
|
||||
);
|
||||
return;
|
||||
return listItem;
|
||||
}
|
||||
|
||||
this.dataset.guid = this._login.guid;
|
||||
this._title.textContent = this._login.title;
|
||||
if (this._login.username.trim()) {
|
||||
this._username.removeAttribute("data-l10n-id");
|
||||
this._username.textContent = this._login.username.trim();
|
||||
// Prepend the ID with a string since IDs must not begin with a number.
|
||||
listItem.id = "lli-" + login.guid;
|
||||
listItem.dataset.guid = login.guid;
|
||||
listItem._login = login;
|
||||
title.textContent = login.title;
|
||||
if (login.username.trim()) {
|
||||
username.removeAttribute("data-l10n-id");
|
||||
username.textContent = login.username.trim();
|
||||
} else {
|
||||
document.l10n.setAttributes(
|
||||
this._username,
|
||||
username,
|
||||
"login-list-item-subtitle-missing-username"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "click": {
|
||||
if (!this._login.guid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsLoginSelected", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: this._login,
|
||||
})
|
||||
);
|
||||
|
||||
recordTelemetryEvent({ object: "existing_login", method: "select" });
|
||||
return listItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cached login object with new values.
|
||||
*
|
||||
* @param {login} login The login object to display. The login object is
|
||||
* a plain JS object representation of nsILoginInfo/nsILoginMetaInfo.
|
||||
*/
|
||||
update(login) {
|
||||
this._login = login;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
customElements.define("login-list-item", LoginListItem);
|
||||
|
|
|
@ -37,3 +37,42 @@ ol {
|
|||
.create-login-button {
|
||||
margin: 18px;
|
||||
}
|
||||
|
||||
.login-list-item {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
padding-inline-end: 18px;
|
||||
padding-inline-start: 14px;
|
||||
border-inline-start: 4px solid transparent;
|
||||
border-bottom: 1px solid var(--in-content-box-border-color);
|
||||
}
|
||||
|
||||
.login-list-item:hover {
|
||||
background-color: var(--in-content-box-background-hover);
|
||||
}
|
||||
|
||||
.login-list-item:hover:active {
|
||||
background-color: var(--in-content-box-background-active);
|
||||
}
|
||||
|
||||
.login-list-item.keyboard-selected {
|
||||
border-inline-start-color: var(--in-content-border-active-shadow);
|
||||
background-color: var(--in-content-box-background-odd);
|
||||
}
|
||||
|
||||
.login-list-item.selected {
|
||||
border-inline-start-color: var(--in-content-border-highlight);
|
||||
background-color: var(--in-content-box-background-hover);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.title,
|
||||
.username {
|
||||
display: block;
|
||||
max-width: 50ch;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
import LoginListItem from "./login-list-item.js";
|
||||
import LoginListItemFactory from "./login-list-item.js";
|
||||
import { recordTelemetryEvent } from "../aboutLoginsUtils.js";
|
||||
|
||||
const collator = new Intl.Collator();
|
||||
|
@ -18,7 +18,7 @@ export default class LoginList extends HTMLElement {
|
|||
this._logins = [];
|
||||
this._filter = "";
|
||||
this._selectedGuid = null;
|
||||
this._blankLoginListItem = new LoginListItem({});
|
||||
this._blankLoginListItem = LoginListItemFactory.create({});
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
@ -44,6 +44,7 @@ export default class LoginList extends HTMLElement {
|
|||
window.addEventListener("AboutLoginsCreateLogin", this);
|
||||
window.addEventListener("AboutLoginsLoginSelected", this);
|
||||
window.addEventListener("AboutLoginsFilterLogins", this);
|
||||
this._list.addEventListener("click", this);
|
||||
this.addEventListener("keydown", this);
|
||||
this._createLoginButton.addEventListener("click", this);
|
||||
}
|
||||
|
@ -85,7 +86,7 @@ export default class LoginList extends HTMLElement {
|
|||
let chunkSize = 5;
|
||||
for (let i = 0; i < this._logins.length; i++) {
|
||||
let login = this._logins[i];
|
||||
let listItem = new LoginListItem(login);
|
||||
let listItem = LoginListItemFactory.create(login);
|
||||
if (login.guid == this._selectedGuid) {
|
||||
this._setListItemAsSelected(listItem);
|
||||
}
|
||||
|
@ -109,17 +110,35 @@ export default class LoginList extends HTMLElement {
|
|||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "click": {
|
||||
if (event.originalTarget == this._createLoginButton) {
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsCreateLogin"));
|
||||
recordTelemetryEvent({ object: "new_login", method: "new" });
|
||||
return;
|
||||
}
|
||||
|
||||
let loginListItem = event.originalTarget.closest(".login-list-item");
|
||||
if (!loginListItem || !loginListItem.dataset.guid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsLoginSelected", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: loginListItem._login,
|
||||
})
|
||||
);
|
||||
|
||||
recordTelemetryEvent({ object: "existing_login", method: "select" });
|
||||
break;
|
||||
}
|
||||
case "change": {
|
||||
const sort = this._sortSelect.value;
|
||||
this._logins = this._logins.sort((a, b) => sortFnOptions[sort](a, b));
|
||||
this.render();
|
||||
break;
|
||||
}
|
||||
case "click": {
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsCreateLogin"));
|
||||
recordTelemetryEvent({ object: "new_login", method: "new" });
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsClearSelection": {
|
||||
if (!this._logins.length) {
|
||||
return;
|
||||
|
@ -147,7 +166,7 @@ export default class LoginList extends HTMLElement {
|
|||
}
|
||||
|
||||
let listItem = this._list.querySelector(
|
||||
`login-list-item[data-guid="${event.detail.guid}"]`
|
||||
`.login-list-item[data-guid="${event.detail.guid}"]`
|
||||
);
|
||||
if (listItem) {
|
||||
this._setListItemAsSelected(listItem);
|
||||
|
@ -179,7 +198,7 @@ export default class LoginList extends HTMLElement {
|
|||
) {
|
||||
// Select the first visible login after any possible filter is applied.
|
||||
let firstVisibleListItem = this._list.querySelector(
|
||||
"login-list-item[data-guid]:not([hidden])"
|
||||
".login-list-item[data-guid]:not([hidden])"
|
||||
);
|
||||
if (firstVisibleListItem) {
|
||||
this._selectedGuid = firstVisibleListItem.dataset.guid;
|
||||
|
|
|
@ -11,7 +11,6 @@ browser.jar:
|
|||
content/browser/aboutlogins/components/login-item.js (content/components/login-item.js)
|
||||
content/browser/aboutlogins/components/login-list.css (content/components/login-list.css)
|
||||
content/browser/aboutlogins/components/login-list.js (content/components/login-list.js)
|
||||
content/browser/aboutlogins/components/login-list-item.css (content/components/login-list-item.css)
|
||||
content/browser/aboutlogins/components/login-list-item.js (content/components/login-list-item.js)
|
||||
content/browser/aboutlogins/components/menu-button.css (content/components/menu-button.css)
|
||||
content/browser/aboutlogins/components/menu-button.js (content/components/menu-button.js)
|
||||
|
|
|
@ -51,7 +51,7 @@ add_task(async function test_telemetry_events() {
|
|||
await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
|
||||
let loginList = content.document.querySelector("login-list");
|
||||
let loginListItem = loginList.shadowRoot.querySelector(
|
||||
"login-list-item:nth-child(2)"
|
||||
".login-list-item:nth-child(2)"
|
||||
);
|
||||
loginListItem.click();
|
||||
});
|
||||
|
@ -128,7 +128,7 @@ add_task(async function test_telemetry_events() {
|
|||
await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
|
||||
let loginList = content.document.querySelector("login-list");
|
||||
let loginListItem = loginList.shadowRoot.querySelector(
|
||||
"login-list-item[data-guid]"
|
||||
".login-list-item[data-guid]"
|
||||
);
|
||||
loginListItem.click();
|
||||
});
|
||||
|
|
|
@ -86,7 +86,7 @@ add_task(async function test_create_login() {
|
|||
ok(loginFound, "Expected number of logins found in login-list");
|
||||
|
||||
let loginListItem = [
|
||||
...loginList.shadowRoot.querySelectorAll("login-list-item"),
|
||||
...loginList.shadowRoot.querySelectorAll(".login-list-item"),
|
||||
].find(l => l._login.origin == aOriginTuple[1]);
|
||||
ok(
|
||||
!!loginListItem,
|
||||
|
|
|
@ -45,7 +45,7 @@ add_task(async function test_login_item() {
|
|||
await ContentTask.spawn(browser, [TEST_LOGIN1, TEST_LOGIN2], async logins => {
|
||||
let loginList = content.document.querySelector("login-list");
|
||||
let loginListItem = loginList.shadowRoot.querySelector(
|
||||
"login-list-item[data-guid]"
|
||||
".login-list-item[data-guid]"
|
||||
);
|
||||
info("Clicking on the first login");
|
||||
loginListItem.click();
|
||||
|
|
|
@ -71,10 +71,10 @@ add_task(async function test_query_parameter_filter() {
|
|||
);
|
||||
|
||||
let hiddenLoginListItems = loginList.shadowRoot.querySelectorAll(
|
||||
"login-list-item[hidden]"
|
||||
".login-list-item[hidden]"
|
||||
);
|
||||
let visibleLoginListItems = loginList.shadowRoot.querySelectorAll(
|
||||
"login-list-item:not([hidden])"
|
||||
".login-list-item:not([hidden])"
|
||||
);
|
||||
is(visibleLoginListItems.length, 1, "The one login should be visible");
|
||||
is(
|
||||
|
|
|
@ -34,7 +34,7 @@ add_task(async function test_login_item() {
|
|||
async login => {
|
||||
let loginList = content.document.querySelector("login-list");
|
||||
let loginListItem = Cu.waiveXrays(
|
||||
loginList.shadowRoot.querySelector("login-list-item[data-guid]")
|
||||
loginList.shadowRoot.querySelector(".login-list-item[data-guid]")
|
||||
);
|
||||
loginListItem.click();
|
||||
|
||||
|
@ -103,7 +103,7 @@ add_task(async function test_login_item() {
|
|||
);
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
loginListItem = Cu.waiveXrays(
|
||||
loginList.shadowRoot.querySelector("login-list-item")
|
||||
loginList.shadowRoot.querySelector(".login-list-item")
|
||||
);
|
||||
return (
|
||||
loginListItem._login.username == usernameInput.value &&
|
||||
|
@ -132,7 +132,7 @@ add_task(async function test_login_item() {
|
|||
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
loginListItem = Cu.waiveXrays(
|
||||
loginList.shadowRoot.querySelector("login-list-item")
|
||||
loginList.shadowRoot.querySelector(".login-list-item")
|
||||
);
|
||||
return !loginListItem;
|
||||
}, "Waiting for login to be removed from list");
|
||||
|
|
|
@ -124,35 +124,33 @@ add_task(async function test_empty_login_username_in_list() {
|
|||
}));
|
||||
|
||||
gLoginList.setLogins([TEST_LOGIN_3]);
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
is(loginListItems.length, 1, "The one stored login should be displayed");
|
||||
is(loginListItems[0].dataset.guid, TEST_LOGIN_3.guid, "login-list-item should have correct guid attribute");
|
||||
|
||||
loginListItems[0].render();
|
||||
let loginUsername = loginListItems[0].shadowRoot.querySelector(".username");
|
||||
let loginUsername = loginListItems[0].querySelector(".username");
|
||||
is(loginUsername.getAttribute("data-l10n-id"), "login-list-item-subtitle-missing-username", "login should show missing username text");
|
||||
});
|
||||
|
||||
add_task(async function test_populated_list() {
|
||||
gLoginList.setLogins([TEST_LOGIN_1, TEST_LOGIN_2]);
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
is(loginListItems.length, 2, "The two stored logins should be displayed");
|
||||
is(loginListItems[0].dataset.guid, TEST_LOGIN_1.guid, "login-list-item should have correct guid attribute");
|
||||
is(loginListItems[0].shadowRoot.querySelector(".title").textContent, TEST_LOGIN_1.title,
|
||||
is(loginListItems[0].querySelector(".title").textContent, TEST_LOGIN_1.title,
|
||||
"login-list-item origin should match");
|
||||
is(loginListItems[0].shadowRoot.querySelector(".username").textContent, TEST_LOGIN_1.username,
|
||||
is(loginListItems[0].querySelector(".username").textContent, TEST_LOGIN_1.username,
|
||||
"login-list-item username should match");
|
||||
ok(loginListItems[0].classList.contains("selected"), "The first item should be selected by default");
|
||||
ok(!loginListItems[1].classList.contains("selected"), "The second item should not be selected by default");
|
||||
loginListItems[0].click();
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
is(loginListItems.length, 2, "After selecting one, only the two stored logins should be displayed");
|
||||
ok(loginListItems[0].classList.contains("selected"), "The first item should be selected");
|
||||
ok(!loginListItems[1].classList.contains("selected"), "The second item should still not be selected");
|
||||
});
|
||||
|
||||
add_task(async function test_filtered_list() {
|
||||
is(gLoginList.shadowRoot.querySelectorAll("login-list-item:not([hidden])").length, 2, "Both logins should be visible");
|
||||
is(gLoginList.shadowRoot.querySelectorAll(".login-list-item:not([hidden])").length, 2, "Both logins should be visible");
|
||||
let countSpan = gLoginList.shadowRoot.querySelector(".count");
|
||||
is(JSON.parse(countSpan.getAttribute("data-l10n-args")).count, 2, "Count should match full list length");
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsFilterLogins", {
|
||||
|
@ -160,8 +158,8 @@ add_task(async function test_filtered_list() {
|
|||
detail: "user1",
|
||||
}));
|
||||
is(JSON.parse(countSpan.getAttribute("data-l10n-args")).count, 1, "Count should match result amount");
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
is(loginListItems[0].shadowRoot.querySelector(".username").textContent, "user1", "user1 is expected first");
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
is(loginListItems[0].querySelector(".username").textContent, "user1", "user1 is expected first");
|
||||
ok(!loginListItems[0].hidden, "user1 should remain visible");
|
||||
ok(loginListItems[1].hidden, "user2 should be hidden");
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsFilterLogins", {
|
||||
|
@ -169,7 +167,7 @@ add_task(async function test_filtered_list() {
|
|||
detail: "user2",
|
||||
}));
|
||||
is(JSON.parse(countSpan.getAttribute("data-l10n-args")).count, 1, "Count should match result amount");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
ok(loginListItems[0].hidden, "user1 should be hidden");
|
||||
ok(!loginListItems[1].hidden, "user2 should be visible");
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsFilterLogins", {
|
||||
|
@ -177,7 +175,7 @@ add_task(async function test_filtered_list() {
|
|||
detail: "user",
|
||||
}));
|
||||
is(JSON.parse(countSpan.getAttribute("data-l10n-args")).count, 2, "Count should match result amount");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
ok(!loginListItems[0].hidden, "user1 should be visible");
|
||||
ok(!loginListItems[1].hidden, "user2 should be visible");
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsFilterLogins", {
|
||||
|
@ -185,7 +183,7 @@ add_task(async function test_filtered_list() {
|
|||
detail: "foo",
|
||||
}));
|
||||
is(JSON.parse(countSpan.getAttribute("data-l10n-args")).count, 0, "Count should match result amount");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
ok(loginListItems[0].hidden, "user1 should be hidden");
|
||||
ok(loginListItems[1].hidden, "user2 should be hidden");
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsFilterLogins", {
|
||||
|
@ -193,7 +191,7 @@ add_task(async function test_filtered_list() {
|
|||
detail: "",
|
||||
}));
|
||||
is(JSON.parse(countSpan.getAttribute("data-l10n-args")).count, 2, "Count should be reset to full list length");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
ok(!loginListItems[0].hidden, "user1 should be visible");
|
||||
ok(!loginListItems[1].hidden, "user2 should be visible");
|
||||
});
|
||||
|
@ -202,14 +200,14 @@ add_task(async function test_login_modified() {
|
|||
let modifiedLogin = Object.assign(TEST_LOGIN_1, {username: "user11"});
|
||||
gLoginList.loginModified(modifiedLogin);
|
||||
await asyncElementRendered();
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
is(loginListItems.length, 2, "Both logins should be displayed");
|
||||
is(loginListItems[0].dataset.guid, TEST_LOGIN_1.guid, "login-list-item should have correct guid attribute");
|
||||
is(loginListItems[0].shadowRoot.querySelector(".title").textContent, TEST_LOGIN_1.title,
|
||||
is(loginListItems[0].querySelector(".title").textContent, TEST_LOGIN_1.title,
|
||||
"login-list-item origin should match");
|
||||
is(loginListItems[0].shadowRoot.querySelector(".username").textContent, modifiedLogin.username,
|
||||
is(loginListItems[0].querySelector(".username").textContent, modifiedLogin.username,
|
||||
"login-list-item username should have been updated");
|
||||
is(loginListItems[1].shadowRoot.querySelector(".username").textContent, TEST_LOGIN_2.username,
|
||||
is(loginListItems[1].querySelector(".username").textContent, TEST_LOGIN_2.username,
|
||||
"login-list-item2 username should remain unchanged");
|
||||
});
|
||||
|
||||
|
@ -217,21 +215,21 @@ add_task(async function test_login_added() {
|
|||
let newLogin = Object.assign({}, TEST_LOGIN_1, {username: "user22", guid: "111222"});
|
||||
gLoginList.loginAdded(newLogin);
|
||||
await asyncElementRendered();
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
is(loginListItems.length, 3, "New login should be added to the list");
|
||||
is(loginListItems[0].dataset.guid, TEST_LOGIN_1.guid, "login-list-item1 should have correct guid attribute");
|
||||
is(loginListItems[1].dataset.guid, TEST_LOGIN_2.guid, "login-list-item2 should have correct guid attribute");
|
||||
is(loginListItems[2].dataset.guid, newLogin.guid, "login-list-item3 should have correct guid attribute");
|
||||
is(loginListItems[2].shadowRoot.querySelector(".title").textContent, newLogin.title,
|
||||
is(loginListItems[2].querySelector(".title").textContent, newLogin.title,
|
||||
"login-list-item origin should match");
|
||||
is(loginListItems[2].shadowRoot.querySelector(".username").textContent, newLogin.username,
|
||||
is(loginListItems[2].querySelector(".username").textContent, newLogin.username,
|
||||
"login-list-item username should have been updated");
|
||||
});
|
||||
|
||||
add_task(async function test_login_removed() {
|
||||
gLoginList.loginRemoved({guid: "111222"});
|
||||
await asyncElementRendered();
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
is(loginListItems.length, 2, "New login should be removed from the list");
|
||||
is(loginListItems[0].dataset.guid, TEST_LOGIN_1.guid, "login-list-item1 should have correct guid attribute");
|
||||
is(loginListItems[1].dataset.guid, TEST_LOGIN_2.guid, "login-list-item2 should have correct guid attribute");
|
||||
|
@ -250,7 +248,7 @@ add_task(async function test_login_added_filtered() {
|
|||
let newLogin = Object.assign({}, TEST_LOGIN_1, {username: "user22", guid: "111222"});
|
||||
gLoginList.loginAdded(newLogin);
|
||||
await asyncElementRendered();
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
is(loginListItems.length, 3, "New login should be added to the list");
|
||||
is(loginListItems[0].dataset.guid, TEST_LOGIN_1.guid, "login-list-item1 should have correct guid attribute");
|
||||
is(loginListItems[1].dataset.guid, TEST_LOGIN_2.guid, "login-list-item2 should have correct guid attribute");
|
||||
|
@ -269,7 +267,7 @@ add_task(async function test_sorted_list() {
|
|||
|
||||
// sort by last used
|
||||
gLoginList.shadowRoot.getElementById("login-sort").selectedIndex = 1;
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
is(loginListItems.length, 3, "The list should contain the three stored logins");
|
||||
let timeUsed = loginListItems[0]._login.timeLastUsed;
|
||||
let timeUsed2 = loginListItems[1]._login.timeLastUsed;
|
||||
|
@ -277,14 +275,14 @@ add_task(async function test_sorted_list() {
|
|||
|
||||
// sort by name
|
||||
gLoginList.shadowRoot.getElementById("login-sort").selectedIndex = 0;
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
let title = loginListItems[0]._login.title;
|
||||
let title2 = loginListItems[1]._login.title;
|
||||
is(title.localeCompare(title2), -1, "Logins should be sorted alphabetically by hostname");
|
||||
|
||||
// sort by last changed
|
||||
gLoginList.shadowRoot.getElementById("login-sort").selectedIndex = 2;
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
|
||||
loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
let pwChanged = loginListItems[0]._login.timePasswordChanged;
|
||||
let pwChanged2 = loginListItems[1]._login.timePasswordChanged;
|
||||
is(pwChanged2 > pwChanged, true, "Login with most recently changed password should be displayed at top of list");
|
||||
|
|
Загрузка…
Ссылка в новой задаче