/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ /* eslint-disable mozilla/no-arbitrary-setTimeout */ const OS_REAUTH_PREF = "signon.management.page.os-auth.enabled"; async function openRemoveAllDialog(browser) { await SimpleTest.promiseFocus(browser); await BrowserTestUtils.synthesizeMouseAtCenter("menu-button", {}, browser); await SpecialPowers.spawn(browser, [], async () => { let menuButton = content.document.querySelector("menu-button"); let menu = menuButton.shadowRoot.querySelector("ul.menu"); await ContentTaskUtils.waitForCondition(() => !menu.hidden); }); function getRemoveAllMenuButton() { let menuButton = window.document.querySelector("menu-button"); return menuButton.shadowRoot.querySelector(".menuitem-remove-all-logins"); } await BrowserTestUtils.synthesizeMouseAtCenter( getRemoveAllMenuButton, {}, browser ); info("remove all dialog should be opened"); } async function activateLoginItemEdit(browser) { await SimpleTest.promiseFocus(browser); await SpecialPowers.spawn(browser, [], async () => { let loginItem = content.document.querySelector("login-item"); Assert.ok(loginItem, "Login item should exist"); }); function getLoginItemEditButton() { let loginItem = window.document.querySelector("login-item"); return loginItem.shadowRoot.querySelector(".edit-button"); } await BrowserTestUtils.synthesizeMouseAtCenter( getLoginItemEditButton, {}, browser ); await SpecialPowers.spawn(browser, [], async () => { let loginItem = content.document.querySelector("login-item"); loginItem.shadowRoot.querySelector(".edit-button").click(); await ContentTaskUtils.waitForCondition( () => loginItem.dataset.editing, "Waiting for login-item to enter edit mode" ); }); info("login-item should be in edit mode"); } async function activateCreateNewLogin(browser) { await SimpleTest.promiseFocus(browser); function getCreateNewLoginButton() { let loginList = window.document.querySelector("login-list"); return loginList.shadowRoot.querySelector(".create-login-button"); } await BrowserTestUtils.synthesizeMouseAtCenter( getCreateNewLoginButton, {}, browser ); } async function waitForRemoveAllLogins() { return new Promise(resolve => { Services.obs.addObserver(function observer(subject, topic, changeType) { if (changeType != "removeAllLogins") { return; } Services.obs.removeObserver(observer, "passwordmgr-storage-changed"); resolve(); }, "passwordmgr-storage-changed"); }); } add_setup(async function () { await SpecialPowers.pushPrefEnv({ set: [[OS_REAUTH_PREF, false]], }); await BrowserTestUtils.openNewForegroundTab({ gBrowser, url: "about:logins", }); registerCleanupFunction(async () => { BrowserTestUtils.removeTab(gBrowser.selectedTab); Services.logins.removeAllUserFacingLogins(); await SpecialPowers.popPrefEnv(); }); TEST_LOGIN1 = await addLogin(TEST_LOGIN1); }); add_task(async function test_remove_all_dialog_l10n() { Assert.ok(TEST_LOGIN1, "test_login1"); let browser = gBrowser.selectedBrowser; await openRemoveAllDialog(browser); await SpecialPowers.spawn(browser, [], async () => { const EventUtils = ContentTaskUtils.getEventUtils(content); let dialog = Cu.waiveXrays( content.document.querySelector("remove-logins-dialog") ); Assert.ok(!dialog.hidden); let title = dialog.shadowRoot.querySelector(".title"); let message = dialog.shadowRoot.querySelector(".message"); let label = dialog.shadowRoot.querySelector(".checkbox-text"); let cancelButton = dialog.shadowRoot.querySelector(".cancel-button"); let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button"); await content.document.l10n.translateElements([ title, message, label, cancelButton, removeAllButton, ]); Assert.equal( title.dataset.l10nId, "about-logins-confirm-remove-all-dialog-title", "Title contents should match l10n-id attribute set on element" ); Assert.equal( message.dataset.l10nId, "about-logins-confirm-remove-all-dialog-message", "Message contents should match l10n-id attribute set on element" ); Assert.equal( label.dataset.l10nId, "about-logins-confirm-remove-all-dialog-checkbox-label", "Label contents should match l10n-id attribute set on outer element" ); Assert.equal( cancelButton.dataset.l10nId, "confirmation-dialog-cancel-button", "Cancel button contents should match l10n-id attribute set on outer element" ); Assert.equal( removeAllButton.dataset.l10nId, "about-logins-confirm-remove-all-dialog-confirm-button-label", "Remove all button contents should match l10n-id attribute set on outer element" ); Assert.equal( JSON.parse(title.dataset.l10nArgs).count, 1, "Title contents should match l10n-args attribute set on element" ); Assert.equal( JSON.parse(message.dataset.l10nArgs).count, 1, "Message contents should match l10n-args attribute set on element" ); Assert.equal( JSON.parse(label.dataset.l10nArgs).count, 1, "Label contents should match l10n-id attribute set on outer element" ); EventUtils.synthesizeMouseAtCenter( dialog.shadowRoot.querySelector(".cancel-button"), {}, content ); await ContentTaskUtils.waitForCondition( () => dialog.hidden, "Waiting for the dialog to be hidden after clicking cancel button" ); }); }); add_task(async function test_remove_all_dialog_keyboard_navigation() { let browser = gBrowser.selectedBrowser; await openRemoveAllDialog(browser); await SpecialPowers.spawn(browser, [], async () => { const EventUtils = ContentTaskUtils.getEventUtils(content); let dialog = Cu.waiveXrays( content.document.querySelector("remove-logins-dialog") ); let cancelButton = dialog.shadowRoot.querySelector(".cancel-button"); let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button"); Assert.equal( removeAllButton.disabled, true, "Remove all should be disabled on dialog open" ); await EventUtils.synthesizeKey(" ", {}, content); Assert.equal( removeAllButton.disabled, false, "Remove all should be enabled when activating the checkbox" ); await EventUtils.synthesizeKey(" ", {}, content); Assert.equal( removeAllButton.disabled, true, "Remove all should be disabled after deactivating the checkbox" ); await EventUtils.synthesizeKey("KEY_Tab", {}, content); Assert.equal( dialog.shadowRoot.activeElement, cancelButton, "Cancel button should be the next element in tab order" ); await EventUtils.synthesizeKey(" ", {}, content); await ContentTaskUtils.waitForCondition( () => dialog.hidden, "Waiting for the dialog to be hidden after activating cancel button via Space key" ); }); await openRemoveAllDialog(browser); await SpecialPowers.spawn(browser, [], async () => { let dialog = Cu.waiveXrays( content.document.querySelector("remove-logins-dialog") ); await EventUtils.synthesizeKey("KEY_Escape", {}, content); await ContentTaskUtils.waitForCondition( () => dialog.hidden, "Waiting for the dialog to be hidden after activating Escape key" ); }); await openRemoveAllDialog(browser); await SpecialPowers.spawn(browser, [], async () => { let dialog = Cu.waiveXrays( content.document.querySelector("remove-logins-dialog") ); let dismissButton = dialog.shadowRoot.querySelector(".dismiss-button"); await EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true }, content); Assert.equal( dialog.shadowRoot.activeElement, dismissButton, "dismiss button should be focused" ); await EventUtils.synthesizeKey(" ", {}, content); await ContentTaskUtils.waitForCondition( () => dialog.hidden, "Waiting for the dialog to be hidden after activating X button" ); }); }); add_task(async function test_remove_all_dialog_remove_logins() { TEST_LOGIN2 = await addLogin(TEST_LOGIN2); let browser = gBrowser.selectedBrowser; let removeAllPromise = waitForRemoveAllLogins(); await openRemoveAllDialog(browser); await SpecialPowers.spawn(browser, [], async () => { let dialog = Cu.waiveXrays( content.document.querySelector("remove-logins-dialog") ); let title = dialog.shadowRoot.querySelector(".title"); let message = dialog.shadowRoot.querySelector(".message"); let label = dialog.shadowRoot.querySelector(".checkbox-text"); let cancelButton = dialog.shadowRoot.querySelector(".cancel-button"); let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button"); let checkbox = dialog.shadowRoot.querySelector(".checkbox"); await content.document.l10n.translateElements([ title, message, cancelButton, removeAllButton, label, checkbox, ]); Assert.equal( dialog.shadowRoot.activeElement, checkbox, "Checkbox should be the focused element on dialog open" ); Assert.equal( title.dataset.l10nId, "about-logins-confirm-remove-all-dialog-title", "Title contents should match l10n-id attribute set on element" ); Assert.equal( JSON.parse(title.dataset.l10nArgs).count, 2, "Title contents should match l10n-args attribute set on element" ); Assert.equal( message.dataset.l10nId, "about-logins-confirm-remove-all-dialog-message", "Message contents should match l10n-id attribute set on element" ); Assert.equal( JSON.parse(message.dataset.l10nArgs).count, 2, "Message contents should match l10n-args attribute set on element" ); Assert.equal( label.dataset.l10nId, "about-logins-confirm-remove-all-dialog-checkbox-label", "Label contents should match l10n-id attribute set on outer element" ); Assert.equal( JSON.parse(label.dataset.l10nArgs).count, 2, "Label contents should match l10n-id attribute set on outer element" ); Assert.equal( cancelButton.dataset.l10nId, "confirmation-dialog-cancel-button", "Cancel button contents should match l10n-id attribute set on outer element" ); Assert.equal( removeAllButton.dataset.l10nId, "about-logins-confirm-remove-all-dialog-confirm-button-label", "Remove all button contents should match l10n-id attribute set on outer element" ); Assert.equal( removeAllButton.disabled, true, "Remove all button should be disabled on dialog open" ); }); function activateConfirmCheckbox() { let dialog = window.document.querySelector("remove-logins-dialog"); return dialog.shadowRoot.querySelector(".checkbox"); } await BrowserTestUtils.synthesizeMouseAtCenter( activateConfirmCheckbox, {}, browser ); await SpecialPowers.spawn(browser, [], async () => { let dialog = Cu.waiveXrays( content.document.querySelector("remove-logins-dialog") ); let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button"); Assert.equal( removeAllButton.disabled, false, "Remove all should be enabled after clicking the checkbox" ); }); function getDialogRemoveAllButton() { let dialog = window.document.querySelector("remove-logins-dialog"); return dialog.shadowRoot.querySelector(".confirm-button"); } await BrowserTestUtils.synthesizeMouseAtCenter( getDialogRemoveAllButton, {}, browser ); await removeAllPromise; await SpecialPowers.spawn(browser, [], async () => { let loginList = Cu.waiveXrays(content.document.querySelector("login-list")); await ContentTaskUtils.waitForCondition( () => content.document.documentElement.classList.contains("no-logins"), "Waiting for no logins view since all logins should be deleted" ); await ContentTaskUtils.waitForCondition( () => !content.document.documentElement.classList.contains("login-selected"), "Waiting for the FxA Sync illustration to reappear" ); await ContentTaskUtils.waitForCondition( () => loginList.classList.contains("no-logins"), "Waiting for login-list to be in no logins view as all logins should be deleted" ); }); await BrowserTestUtils.synthesizeMouseAtCenter("menu-button", {}, browser); await SpecialPowers.spawn(browser, [], async () => { let menuButton = content.document.querySelector("menu-button"); let removeAllMenuButton = menuButton.shadowRoot.querySelector( ".menuitem-remove-all-logins" ); Assert.ok( removeAllMenuButton.disabled, "Remove all logins menu button is disabled if there are no logins" ); }); await SpecialPowers.spawn(browser, [], async () => { let menuButton = Cu.waiveXrays( content.document.querySelector("menu-button") ); let menu = menuButton.shadowRoot.querySelector("ul.menu"); await EventUtils.synthesizeKey("KEY_Escape", {}, content); await ContentTaskUtils.waitForCondition( () => menu.hidden, "Waiting for menu to close" ); }); }); add_task(async function test_edit_mode_resets_on_remove_all_with_login() { TEST_LOGIN2 = await addLogin(TEST_LOGIN2); let removeAllPromise = waitForRemoveAllLogins(); let browser = gBrowser.selectedBrowser; await activateLoginItemEdit(browser); await openRemoveAllDialog(browser); await SpecialPowers.spawn(browser, [], async () => { let loginItem = content.document.querySelector("login-item"); Assert.ok( loginItem.dataset.editing, "Login item is still in edit mode when the remove all dialog opens" ); }); function getDialogCancelButton() { let dialog = window.document.querySelector("remove-logins-dialog"); return dialog.shadowRoot.querySelector(".cancel-button"); } await BrowserTestUtils.synthesizeMouseAtCenter( getDialogCancelButton, {}, browser ); await TestUtils.waitForTick(); await SpecialPowers.spawn(browser, [], async () => { let loginItem = content.document.querySelector("login-item"); Assert.ok( loginItem.dataset.editing, "Login item should be in editing mode after activating the cancel button in the remove all dialog" ); }); await openRemoveAllDialog(browser); function activateConfirmCheckbox() { let dialog = window.document.querySelector("remove-logins-dialog"); return dialog.shadowRoot.querySelector(".checkbox"); } await BrowserTestUtils.synthesizeMouseAtCenter( activateConfirmCheckbox, {}, browser ); await SpecialPowers.spawn(browser, [], async () => { let dialog = Cu.waiveXrays( content.document.querySelector("remove-logins-dialog") ); let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button"); Assert.equal( removeAllButton.disabled, false, "Remove all should be enabled after clicking the checkbox" ); }); function getDialogRemoveAllButton() { let dialog = window.document.querySelector("remove-logins-dialog"); return dialog.shadowRoot.querySelector(".confirm-button"); } await BrowserTestUtils.synthesizeMouseAtCenter( getDialogRemoveAllButton, {}, browser ); await TestUtils.waitForTick(); await SpecialPowers.spawn(browser, [], async () => { let loginItem = content.document.querySelector("login-item"); Assert.ok( !loginItem.dataset.editing, "Login item should not be in editing mode after activating the confirm button in the remove all dialog" ); }); await removeAllPromise; }); add_task(async function test_remove_all_when_creating_new_login() { TEST_LOGIN2 = await addLogin(TEST_LOGIN2); let removeAllPromise = waitForRemoveAllLogins(); let browser = gBrowser.selectedBrowser; await activateCreateNewLogin(browser); await openRemoveAllDialog(browser); await SpecialPowers.spawn(browser, [], async () => { let loginItem = content.document.querySelector("login-item"); Assert.ok( loginItem.dataset.editing, "Login item should be in edit mode when the remove all dialog opens" ); Assert.ok( loginItem.dataset.isNewLogin, "Login item should be in the 'new login' state when the remove all dialog opens" ); }); function getDialogCancelButton() { let dialog = window.document.querySelector("remove-logins-dialog"); return dialog.shadowRoot.querySelector(".cancel-button"); } await BrowserTestUtils.synthesizeMouseAtCenter( getDialogCancelButton, {}, browser ); await SpecialPowers.spawn(browser, [], async () => { let loginItem = content.document.querySelector("login-item"); Assert.ok( loginItem.dataset.editing, "Login item is still in edit mode after cancelling out of the remove all dialog" ); Assert.ok( loginItem.dataset.isNewLogin, "Login item should be in the 'newLogin' state after cancelling out of the remove all dialog" ); }); await openRemoveAllDialog(browser); function activateConfirmCheckbox() { let dialog = window.document.querySelector("remove-logins-dialog"); return dialog.shadowRoot.querySelector(".checkbox"); } await BrowserTestUtils.synthesizeMouseAtCenter( activateConfirmCheckbox, {}, browser ); await SpecialPowers.spawn(browser, [], async () => { let dialog = Cu.waiveXrays( content.document.querySelector("remove-logins-dialog") ); let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button"); Assert.equal( removeAllButton.disabled, false, "Remove all should be enabled after clicking the checkbox" ); }); function getDialogRemoveAllButton() { let dialog = window.document.querySelector("remove-logins-dialog"); return dialog.shadowRoot.querySelector(".confirm-button"); } await BrowserTestUtils.synthesizeMouseAtCenter( getDialogRemoveAllButton, {}, browser ); await SpecialPowers.spawn(browser, [], async () => { let loginItem = content.document.querySelector("login-item"); Assert.ok( !loginItem.dataset.editing, "Login item should not be in editing mode after activating the confirm button in the remove all dialog" ); Assert.ok( !loginItem.dataset.isNewLogin, "Login item should not be in 'new login' mode after activating the confirm button in the remove all dialog" ); }); await removeAllPromise; }); add_task(async function test_ensure_icons_are_not_draggable() { TEST_LOGIN2 = await addLogin(TEST_LOGIN2); let browser = gBrowser.selectedBrowser; await openRemoveAllDialog(browser); await SpecialPowers.spawn(browser, [], async () => { let dialog = content.document.querySelector("remove-logins-dialog"); let warningIcon = dialog.shadowRoot.querySelector(".warning-icon"); Assert.ok(!warningIcon.draggable, "Warning icon should not be draggable"); let dismissIcon = dialog.shadowRoot.querySelector(".dismiss-icon"); Assert.ok(!dismissIcon.draggable, "Dismiss icon should not be draggable"); }); });