1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5"use strict"; 6 7const EXPORTED_SYMBOLS = [ 8 "openAccountSetup", 9 "openAccountSettings", 10 "open_advanced_settings", 11 "click_account_tree_row", 12 "get_account_tree_row", 13 "remove_account", 14 "wait_for_account_tree_load", 15]; 16 17var utils = ChromeUtils.import("resource://testing-common/mozmill/utils.jsm"); 18 19var fdh = ChromeUtils.import( 20 "resource://testing-common/mozmill/FolderDisplayHelpers.jsm" 21); 22var wh = ChromeUtils.import( 23 "resource://testing-common/mozmill/WindowHelpers.jsm" 24); 25 26var { 27 content_tab_e, 28 open_content_tab_with_url, 29 wait_for_content_tab_load, 30} = ChromeUtils.import( 31 "resource://testing-common/mozmill/ContentTabHelpers.jsm" 32); 33 34var mc = fdh.mc; 35 36/** 37 * Waits until the Account Manager tree fully loads after first open. 38 */ 39function wait_for_account_tree_load(tab) { 40 mc.waitFor( 41 () => tab.browser.contentWindow.currentAccount != null, 42 "Timeout waiting for currentAccount to become non-null" 43 ); 44} 45 46async function openAccountSettings() { 47 return new Promise(resolve => { 48 let tab = open_content_tab_with_url("about:accountsettings"); 49 wait_for_account_tree_load(tab); 50 resolve(tab); 51 }); 52} 53 54/** 55 * Opens the Account Manager. 56 * @callback tabCallback 57 * 58 * @param {tabCallback} callback - The callback for the account manager tab that is opened. 59 */ 60async function open_advanced_settings(callback) { 61 let tab = open_content_tab_with_url("about:accountsettings"); 62 wait_for_account_tree_load(tab); 63 await callback(tab); 64 mc.tabmail.closeTab(tab); 65} 66 67async function openAccountSetup() { 68 return new Promise(resolve => { 69 let tab = open_content_tab_with_url("about:accountsetup"); 70 wait_for_content_tab_load(tab, "about:accountsetup", 10000); 71 resolve(tab); 72 }); 73} 74 75/** 76 * Click a row in the account settings tree. 77 * 78 * @param {Object} tab - The account manager tab controller that opened. 79 * @param {Number} rowIndex - The row to click. 80 */ 81function click_account_tree_row(tab, rowIndex) { 82 utils.waitFor( 83 () => tab.browser.contentWindow.currentAccount != null, 84 "Timeout waiting for currentAccount to become non-null" 85 ); 86 87 let tree = content_tab_e(tab, "accounttree"); 88 89 fdh.click_tree_row(tree, rowIndex, mc); 90 91 utils.waitFor( 92 () => tab.browser.contentWindow.pendingAccount == null, 93 "Timeout waiting for pendingAccount to become null" 94 ); 95 96 // Ensure the page is fully loaded (e.g. onInit functions). 97 wh.wait_for_frame_load( 98 content_tab_e(tab, "contentFrame"), 99 tab.browser.contentWindow.pageURL( 100 tree.view.getItemAtIndex(rowIndex).getAttribute("PageTag") 101 ) 102 ); 103} 104 105/** 106 * Returns the index of the row in account tree corresponding to the wanted 107 * account and its settings pane. 108 * 109 * @param {Number} accountKey - The key of the account to return. 110 * If 'null', the SMTP pane is returned. 111 * @param {Number} paneId - The ID of the account settings pane to select. 112 * 113 * 114 * @returns {Number} The row index of the account and pane. If it was not found return -1. 115 * Do not throw as callers may intentionally just check if a row exists. 116 * Just dump into the log so that a subsequent throw in 117 * click_account_tree_row has a useful context. 118 */ 119function get_account_tree_row(accountKey, paneId, tab) { 120 let rowIndex = 0; 121 let accountTreeNode = content_tab_e(tab, "account-tree-children"); 122 123 for (let i = 0; i < accountTreeNode.children.length; i++) { 124 if ("_account" in accountTreeNode.children[i]) { 125 let accountHead = accountTreeNode.children[i]; 126 if (accountKey == accountHead._account.key) { 127 // If this is the wanted account, find the wanted settings pane. 128 let accountBlock = accountHead.querySelectorAll("[PageTag]"); 129 // A null paneId means the main pane. 130 if (!paneId) { 131 return rowIndex; 132 } 133 134 // Otherwise find the pane in the children. 135 for (let j = 0; j < accountBlock.length; j++) { 136 if (accountBlock[j].getAttribute("PageTag") == paneId) { 137 return rowIndex + j + 1; 138 } 139 } 140 141 // The pane was not found. 142 dump( 143 "The treerow for pane " + 144 paneId + 145 " of account " + 146 accountKey + 147 " was not found!\n" 148 ); 149 return -1; 150 } 151 // If this is not the wanted account, skip all of its settings panes. 152 rowIndex += accountHead.querySelectorAll("[PageTag]").length; 153 } else if (accountKey == null) { 154 // A row without _account should be the SMTP server. 155 return rowIndex; 156 } 157 rowIndex++; 158 } 159 160 // The account was not found. 161 dump("The treerow for account " + accountKey + " was not found!\n"); 162 return -1; 163} 164 165/** 166 * Remove an account via the account manager UI. 167 * 168 * @param {Object} account - The account to remove. 169 * @param {Object} tab - The account manager tab that opened. 170 * @param {boolean} removeAccount - Remove the account itself. 171 * @param {boolean} removeData - Remove the message data of the account. 172 */ 173function remove_account( 174 account, 175 tab, 176 removeAccount = true, 177 removeData = false 178) { 179 let accountRow = get_account_tree_row(account.key, "am-server.xhtml", tab); 180 click_account_tree_row(tab, accountRow); 181 182 account = null; 183 // Use the Remove item in the Account actions menu. 184 mc.click(content_tab_e(tab, "accountActionsButton")); 185 mc.click(content_tab_e(tab, "accountActionsDropdownRemove")); 186 187 let cdc = wh.wait_for_frame_load( 188 tab.browser.contentWindow.gSubDialog._topDialog._frame, 189 "chrome://messenger/content/removeAccount.xhtml" 190 ); 191 192 // Account removal confirmation dialog. Select what to remove. 193 if (removeAccount) { 194 cdc.click(cdc.window.document.getElementById("removeAccount")); 195 } 196 if (removeData) { 197 cdc.click(cdc.window.document.getElementById("removeData")); 198 } 199 200 cdc.window.document.documentElement.querySelector("dialog").acceptDialog(); 201 cdc.waitFor( 202 () => 203 !cdc.window.document.querySelector("dialog").getButton("accept").disabled, 204 "Timeout waiting for finish of account removal", 205 5000, 206 100 207 ); 208 cdc.window.document.documentElement.querySelector("dialog").acceptDialog(); 209} 210