Revision control

Copy as Markdown

Other Tools

/* 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/. */
/**
* Tests the UI for selection of folders with offline storage.
*/
const { click_account_tree_row, get_account_tree_row, openAccountSettings } =
ChromeUtils.importESModule(
);
const { RemoteFolder } = ChromeUtils.importESModule(
);
const { ServerTestUtils } = ChromeUtils.importESModule(
);
const tabmail = document.getElementById("tabmail");
let nntpAccount, nntpRootFolder;
let imapAccount, imapRootFolder;
let ewsAccount, ewsRootFolder;
add_setup(async () => {
// Set up servers.
const imapServer = await ServerTestUtils.createServer({ type: "imap" });
imapServer.daemon.getMailbox("INBOX").specialUseFlag = "\\Inbox";
imapServer.daemon.getMailbox("INBOX").subscribed = true;
imapServer.daemon.createMailbox("Trash", {
flags: ["\\Trash"],
subscribed: true,
});
imapServer.daemon.createMailbox("first", { subscribed: true });
imapServer.daemon.createMailbox("second", { subscribed: true });
imapServer.daemon.createMailbox("third", { subscribed: true });
imapServer.daemon.createMailbox("third/fourth", { subscribed: true });
const ewsServer = await ServerTestUtils.createServer({ type: "ews" });
ewsServer.setRemoteFolders([
new RemoteFolder("root", null, "Root", "msgfolderroot"),
new RemoteFolder("inbox", "root", "Inbox", "inbox"),
new RemoteFolder("first", "root"),
new RemoteFolder("second", "root"),
new RemoteFolder("third", "root"),
new RemoteFolder("fourth", "third"),
]);
// Set up NNTP account.
nntpAccount = MailServices.accounts.createAccount();
nntpAccount.addIdentity(MailServices.accounts.createIdentity());
nntpAccount.incomingServer = MailServices.accounts.createIncomingServer(
null,
"example.nntp.invalid",
"nntp"
);
nntpRootFolder = nntpAccount.incomingServer.rootFolder;
nntpRootFolder.createSubfolder("offline.first", null);
nntpRootFolder
.getChildNamed("offline.first")
.setFlag(Ci.nsMsgFolderFlags.Offline);
nntpRootFolder.createSubfolder("offline.second", null);
nntpRootFolder
.getChildNamed("offline.second")
.setFlag(Ci.nsMsgFolderFlags.Offline);
nntpRootFolder.createSubfolder("offline.third", null);
nntpRootFolder.createSubfolder("offline.third.fourth", null);
// Set up IMAP account.
imapAccount = MailServices.accounts.createAccount();
imapAccount.addIdentity(MailServices.accounts.createIdentity());
imapAccount.incomingServer = MailServices.accounts.createIncomingServer(
"user",
"localhost",
"imap"
);
imapAccount.incomingServer.port = imapServer.port;
imapAccount.incomingServer.password = "password";
imapAccount.incomingServer.prettyName = "IMAP Account";
imapRootFolder = imapAccount.incomingServer.rootFolder;
imapAccount.incomingServer.performExpand(null);
await TestUtils.waitForCondition(
() => imapRootFolder.numSubFolders == 5,
"waiting for IMAP folders to sync"
);
imapRootFolder.getChildNamed("third").clearFlag(Ci.nsMsgFolderFlags.Offline);
imapRootFolder
.getChildNamed("third")
.getChildNamed("fourth")
.clearFlag(Ci.nsMsgFolderFlags.Offline);
// Set up EWS account.
ewsAccount = MailServices.accounts.createAccount();
ewsAccount.addIdentity(MailServices.accounts.createIdentity());
ewsAccount.incomingServer = MailServices.accounts.createIncomingServer(
"user",
"localhost",
"ews"
);
ewsAccount.incomingServer.setStringValue(
"ews_url",
`http://localhost:${ewsServer.port}/EWS/Exchange.asmx`
);
ewsAccount.incomingServer.prettyName = "EWS Account";
ewsAccount.incomingServer.username = "user";
ewsAccount.incomingServer.password = "password";
ewsRootFolder = ewsAccount.incomingServer.rootFolder;
ewsAccount.incomingServer.performExpand(null);
await TestUtils.waitForCondition(
() => ewsRootFolder.numSubFolders == 4,
"waiting for EWS folders to sync"
);
ewsRootFolder.getChildNamed("Inbox").setFlag(Ci.nsMsgFolderFlags.Offline);
ewsRootFolder.getChildNamed("first").setFlag(Ci.nsMsgFolderFlags.Offline);
ewsRootFolder.getChildNamed("second").setFlag(Ci.nsMsgFolderFlags.Offline);
registerCleanupFunction(async () => {
MailServices.accounts.removeAccount(nntpAccount, false);
MailServices.accounts.removeAccount(imapAccount, false);
MailServices.accounts.removeAccount(ewsAccount, false);
tabmail.closeOtherTabs(0);
});
});
/**
* Test the account settings for a Local Folders account. The offline section
* should not be visible.
*/
add_task(async function testLocalFolders() {
const accountsTab = await openAccountSettings();
const accountRowIndex = get_account_tree_row(
"account1",
"am-offline.xhtml",
accountsTab
);
Assert.notEqual(accountRowIndex, -1);
const accountRow =
accountsTab.browser.contentDocument.getElementById("accounttree").rows[
accountRowIndex
];
Assert.equal(accountRow.textContent, "Disk Space");
await click_account_tree_row(accountsTab, accountRowIndex);
const { contentDocument } =
accountsTab.browser.contentDocument.getElementById("contentFrame");
const offlineSection = contentDocument.getElementById("offline.titlebox");
const diskSpaceSection = contentDocument.getElementById("diskspace.titlebox");
Assert.ok(
BrowserTestUtils.isHidden(offlineSection),
"offline section should be hidden for Local Folders"
);
Assert.ok(
BrowserTestUtils.isVisible(diskSpaceSection),
"diskSpace section should be visible for Local Folders"
);
tabmail.closeTab(accountsTab);
});
/**
* Test the account settings for a POP3 account. The offline section should
* not be visible.
*/
add_task(async function testPOP3() {
const accountsTab = await openAccountSettings();
const accountRowIndex = get_account_tree_row(
"account2",
"am-offline.xhtml",
accountsTab
);
Assert.notEqual(accountRowIndex, -1);
const accountRow =
accountsTab.browser.contentDocument.getElementById("accounttree").rows[
accountRowIndex
];
Assert.equal(accountRow.textContent, "Disk Space");
await click_account_tree_row(accountsTab, accountRowIndex);
const { contentDocument } =
accountsTab.browser.contentDocument.getElementById("contentFrame");
const offlineSection = contentDocument.getElementById("offline.titlebox");
const diskSpaceSection = contentDocument.getElementById("diskspace.titlebox");
Assert.ok(
BrowserTestUtils.isHidden(offlineSection),
"offline section should be hidden for POP3 accounts"
);
Assert.ok(
BrowserTestUtils.isVisible(diskSpaceSection),
"diskSpace section should be visible for POP3 accounts"
);
tabmail.closeTab(accountsTab);
});
/**
* Test the account settings for an NNTP account.
*/
add_task(async function testNNTP() {
const accountsTab = await openAccountSettings();
const accountRowIndex = get_account_tree_row(
nntpAccount.key,
"am-offline.xhtml",
accountsTab
);
Assert.notEqual(accountRowIndex, -1);
const accountRow =
accountsTab.browser.contentDocument.getElementById("accounttree").rows[
accountRowIndex
];
Assert.equal(accountRow.textContent, "Synchronization & Storage");
await click_account_tree_row(accountsTab, accountRowIndex);
const { contentWindow, contentDocument } =
accountsTab.browser.contentDocument.getElementById("contentFrame");
const offlineSection = contentDocument.getElementById("offline.titlebox");
const diskSpaceSection = contentDocument.getElementById("diskspace.titlebox");
const selectFoldersButton = contentDocument.getElementById(
"selectImapFoldersButton"
);
const selectNewsgroupsButton = contentDocument.getElementById(
"selectNewsgroupsButton"
);
Assert.ok(
BrowserTestUtils.isVisible(offlineSection),
"offline section should be visible for NNTP accounts"
);
Assert.ok(
BrowserTestUtils.isVisible(diskSpaceSection),
"diskSpace section should be visible for NNTP accounts"
);
Assert.ok(
BrowserTestUtils.isHidden(selectFoldersButton),
"select folders button should be hidden for NNTP accounts"
);
Assert.ok(
BrowserTestUtils.isVisible(selectNewsgroupsButton),
"select folders button should be visible for NNTP accounts"
);
Assert.deepEqual(
Array.from(
nntpRootFolder.getFoldersWithFlags(Ci.nsMsgFolderFlags.Offline),
folder => folder.localizedName
),
["offline.first", "offline.second"]
);
const dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(
undefined,
{
isSubDialog: true,
async callback(win) {
await SimpleTest.promiseFocus(win);
const doc = win.document;
const tree = doc.getElementById("synchronizeTree");
const { folderNameCol, syncCol } = tree.columns;
const treeChildren = tree.lastElementChild;
const acceptButton = doc.querySelector("dialog").getButton("accept");
// Check the initial state.
Assert.equal(tree.view.rowCount, 3);
Assert.ok(
!tree.view.isContainerOpen(0),
"root folder should not be open"
);
tree.view.toggleOpenState(0); // Open root folder.
Assert.equal(tree.view.rowCount, 7);
Assert.equal(
tree.view.getCellText(0, folderNameCol),
"example.nntp.invalid"
);
Assert.equal(tree.view.getCellText(1, folderNameCol), "o.first");
Assert.equal(tree.view.getCellText(2, folderNameCol), "o.second");
Assert.equal(tree.view.getCellText(3, folderNameCol), "o.third");
Assert.equal(tree.view.getCellText(4, folderNameCol), "o.t.fourth");
Assert.equal(tree.view.getCellText(5, folderNameCol), "IMAP Account");
Assert.equal(tree.view.getCellText(6, folderNameCol), "EWS Account");
// Check the initial selection.
const isSelected = index =>
tree.view
.getCellProperties(index, syncCol)
.includes("synchronize-true");
Assert.ok(isSelected(1));
Assert.ok(isSelected(2));
Assert.ok(!isSelected(3));
Assert.ok(!isSelected(4));
// Change the selection by clicking on a check box.
const coords = tree.getCoordsForCellItem(1, syncCol, "cell");
EventUtils.synthesizeMouse(
treeChildren,
coords.x + coords.width / 2,
coords.y + coords.height / 2,
{},
win
);
// Change the selection by selecting some rows and pressing space.
tree.view.selection.rangedSelect(3, 4, false);
tree.focus();
EventUtils.synthesizeKey(" ", {}, win);
// Check the changed selection.
Assert.ok(!isSelected(1));
Assert.ok(isSelected(2));
Assert.ok(isSelected(3));
Assert.ok(isSelected(4));
acceptButton.click();
},
}
);
EventUtils.synthesizeMouseAtCenter(selectNewsgroupsButton, {}, contentWindow);
await dialogPromise;
Assert.deepEqual(
Array.from(
nntpRootFolder.getFoldersWithFlags(Ci.nsMsgFolderFlags.Offline),
folder => folder.localizedName
),
["offline.second", "offline.third", "offline.third.fourth"]
);
tabmail.closeTab(accountsTab);
});
/**
* Test the account settings for an IMAP account.
*/
add_task(async function testIMAP() {
const accountsTab = await openAccountSettings();
const accountRowIndex = get_account_tree_row(
imapAccount.key,
"am-offline.xhtml",
accountsTab
);
Assert.notEqual(accountRowIndex, -1);
const accountRow =
accountsTab.browser.contentDocument.getElementById("accounttree").rows[
accountRowIndex
];
Assert.equal(accountRow.textContent, "Synchronization & Storage");
await click_account_tree_row(accountsTab, accountRowIndex);
const { contentWindow, contentDocument } =
accountsTab.browser.contentDocument.getElementById("contentFrame");
const offlineSection = contentDocument.getElementById("offline.titlebox");
const diskSpaceSection = contentDocument.getElementById("diskspace.titlebox");
const selectFoldersButton = contentDocument.getElementById(
"selectImapFoldersButton"
);
const selectNewsgroupsButton = contentDocument.getElementById(
"selectNewsgroupsButton"
);
Assert.ok(
BrowserTestUtils.isVisible(offlineSection),
"offline section should be visible for IMAP accounts"
);
Assert.ok(
BrowserTestUtils.isVisible(diskSpaceSection),
"diskSpace section should be visible for IMAP accounts"
);
Assert.ok(
BrowserTestUtils.isVisible(selectFoldersButton),
"select folders button should be visible for IMAP accounts"
);
Assert.ok(
BrowserTestUtils.isHidden(selectNewsgroupsButton),
"select folders button should be hidden for IMAP accounts"
);
Assert.deepEqual(
Array.from(
imapRootFolder.getFoldersWithFlags(Ci.nsMsgFolderFlags.Offline),
folder => folder.localizedName
),
["Inbox", "first", "second"]
);
const dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(
undefined,
{
isSubDialog: true,
async callback(win) {
await SimpleTest.promiseFocus(win);
const doc = win.document;
const tree = doc.getElementById("synchronizeTree");
const { folderNameCol, syncCol } = tree.columns;
const treeChildren = tree.lastElementChild;
const acceptButton = doc.querySelector("dialog").getButton("accept");
// Check the initial state.
Assert.equal(tree.view.rowCount, 3);
Assert.ok(
!tree.view.isContainerOpen(1),
"root folder should not be open"
);
tree.view.toggleOpenState(1); // Open root folder.
Assert.equal(tree.view.rowCount, 8);
Assert.ok(
!tree.view.isContainerOpen(6),
"unselected folder should not be open"
);
tree.view.toggleOpenState(6); // Open "third" folder.
Assert.equal(tree.view.rowCount, 9);
Assert.equal(
tree.view.getCellText(0, folderNameCol),
"example.nntp.invalid"
);
Assert.equal(tree.view.getCellText(1, folderNameCol), "IMAP Account");
Assert.equal(tree.view.getCellText(2, folderNameCol), "Inbox");
Assert.equal(tree.view.getCellText(3, folderNameCol), "Trash");
Assert.equal(tree.view.getCellText(4, folderNameCol), "first");
Assert.equal(tree.view.getCellText(5, folderNameCol), "second");
Assert.equal(tree.view.getCellText(6, folderNameCol), "third");
Assert.equal(tree.view.getCellText(7, folderNameCol), "fourth");
Assert.equal(tree.view.getCellText(8, folderNameCol), "EWS Account");
// Check the initial selection.
const isSelected = index =>
tree.view
.getCellProperties(index, syncCol)
.includes("synchronize-true");
Assert.ok(!isSelected(1));
Assert.ok(isSelected(2));
Assert.ok(!isSelected(3));
Assert.ok(isSelected(4));
Assert.ok(isSelected(5));
Assert.ok(!isSelected(6));
Assert.ok(!isSelected(7));
// Change the selection by clicking on a check box.
const coords = tree.getCoordsForCellItem(4, syncCol, "cell");
EventUtils.synthesizeMouse(
treeChildren,
coords.x + coords.width / 2,
coords.y + coords.height / 2,
{},
win
);
// Change the selection by selecting some rows and pressing space.
tree.view.selection.rangedSelect(6, 7, false);
tree.focus();
EventUtils.synthesizeKey(" ", {}, win);
// Check the changed selection.
Assert.ok(!isSelected(1));
Assert.ok(isSelected(2));
Assert.ok(!isSelected(3));
Assert.ok(!isSelected(4));
Assert.ok(isSelected(5));
Assert.ok(isSelected(6));
Assert.ok(isSelected(7));
acceptButton.click();
},
}
);
EventUtils.synthesizeMouseAtCenter(selectFoldersButton, {}, contentWindow);
await dialogPromise;
Assert.deepEqual(
Array.from(
imapRootFolder.getFoldersWithFlags(Ci.nsMsgFolderFlags.Offline),
folder => folder.localizedName
),
["Inbox", "second", "third", "fourth"]
);
tabmail.closeTab(accountsTab);
});
/**
* Test the account settings for an EWS account.
*/
add_task(async function testEWS() {
const accountsTab = await openAccountSettings();
const accountRowIndex = get_account_tree_row(
ewsAccount.key,
"am-offline.xhtml",
accountsTab
);
Assert.notEqual(accountRowIndex, -1);
const accountRow =
accountsTab.browser.contentDocument.getElementById("accounttree").rows[
accountRowIndex
];
Assert.equal(accountRow.textContent, "Synchronization & Storage");
await click_account_tree_row(accountsTab, accountRowIndex);
const { contentWindow, contentDocument } =
accountsTab.browser.contentDocument.getElementById("contentFrame");
const offlineSection = contentDocument.getElementById("offline.titlebox");
const diskSpaceSection = contentDocument.getElementById("diskspace.titlebox");
const selectFoldersButton = contentDocument.getElementById(
"selectImapFoldersButton"
);
const selectNewsgroupsButton = contentDocument.getElementById(
"selectNewsgroupsButton"
);
Assert.ok(
BrowserTestUtils.isVisible(offlineSection),
"offline section should be visible for EWS accounts"
);
Assert.ok(
BrowserTestUtils.isVisible(diskSpaceSection),
"diskSpace section should be visible for EWS accounts"
);
Assert.ok(
BrowserTestUtils.isVisible(selectFoldersButton),
"select folders button should be visible for EWS accounts"
);
Assert.ok(
BrowserTestUtils.isHidden(selectNewsgroupsButton),
"select folders button should be hidden for EWS accounts"
);
Assert.deepEqual(
Array.from(
ewsRootFolder.getFoldersWithFlags(Ci.nsMsgFolderFlags.Offline),
folder => folder.localizedName
),
["Inbox", "first", "second"]
);
const dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(
undefined,
{
isSubDialog: true,
async callback(win) {
await SimpleTest.promiseFocus(win);
const doc = win.document;
const tree = doc.getElementById("synchronizeTree");
const { folderNameCol, syncCol } = tree.columns;
const treeChildren = tree.lastElementChild;
const acceptButton = doc.querySelector("dialog").getButton("accept");
// Check the initial state.
Assert.equal(tree.view.rowCount, 3);
Assert.ok(
!tree.view.isContainerOpen(2),
"root folder should not be open"
);
tree.view.toggleOpenState(2); // Open root folder.
Assert.equal(tree.view.rowCount, 7);
Assert.ok(
!tree.view.isContainerOpen(6),
"unselected folder should not be open"
);
tree.view.toggleOpenState(6); // Open "third" folder.
Assert.equal(tree.view.rowCount, 8);
Assert.equal(
tree.view.getCellText(0, folderNameCol),
"example.nntp.invalid"
);
Assert.equal(tree.view.getCellText(1, folderNameCol), "IMAP Account");
Assert.equal(tree.view.getCellText(2, folderNameCol), "EWS Account");
Assert.equal(tree.view.getCellText(3, folderNameCol), "Inbox");
Assert.equal(tree.view.getCellText(4, folderNameCol), "first");
Assert.equal(tree.view.getCellText(5, folderNameCol), "second");
Assert.equal(tree.view.getCellText(6, folderNameCol), "third");
Assert.equal(tree.view.getCellText(7, folderNameCol), "fourth");
// Check the initial selection.
const isSelected = index =>
tree.view
.getCellProperties(index, syncCol)
.includes("synchronize-true");
Assert.ok(isSelected(3));
Assert.ok(isSelected(4));
Assert.ok(isSelected(5));
Assert.ok(!isSelected(6));
Assert.ok(!isSelected(7));
// Change the selection by clicking on a check box.
const coords = tree.getCoordsForCellItem(4, syncCol, "cell");
EventUtils.synthesizeMouse(
treeChildren,
coords.x + coords.width / 2,
coords.y + coords.height / 2,
{},
win
);
// Change the selection by selecting some rows and pressing space.
tree.view.selection.rangedSelect(6, 7, false);
tree.focus();
EventUtils.synthesizeKey(" ", {}, win);
// Check the changed selection.
Assert.ok(isSelected(3));
Assert.ok(!isSelected(4));
Assert.ok(isSelected(5));
Assert.ok(isSelected(6));
Assert.ok(isSelected(7));
acceptButton.click();
},
}
);
EventUtils.synthesizeMouseAtCenter(selectFoldersButton, {}, contentWindow);
await dialogPromise;
Assert.deepEqual(
Array.from(
ewsRootFolder.getFoldersWithFlags(Ci.nsMsgFolderFlags.Offline),
folder => folder.localizedName
),
["Inbox", "second", "third", "fourth"]
);
tabmail.closeTab(accountsTab);
});