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
"use strict";
const { sinon } = ChromeUtils.importESModule(
);
const tabmail = document.getElementById("tabmail");
let browser;
let abView;
let testAccount;
add_setup(async function () {
const tab = tabmail.openTab("contentTab", {
});
await BrowserTestUtils.browserLoaded(tab.browser);
tab.browser.focus();
browser = tab.browser;
abView = tab.browser.contentWindow.document.querySelector(
"account-hub-address-book"
);
testAccount = {
account: { incomingServer: {}, defaultIdentity: {} },
addressBooks: [
{
name: "Book A",
existing: false,
url: { href: "test@test.com/BookA" },
},
{
name: "Book B",
existing: false,
url: { href: "test@test.com/BookB" },
},
],
existingAddressBookCount: 0,
};
testAccount.account.incomingServer.username = "test@test.com";
testAccount.account.defaultIdentity.fullName = "Test User";
registerCleanupFunction(async () => {
tabmail.closeOtherTabs(tabmail.tabInfo[0]);
});
});
add_task(async function test_initialization() {
const optionSelectSubview = abView.querySelector(
"#addressBookOptionSelectSubview"
);
// The first subview of the address book view should be visible.
Assert.ok(
BrowserTestUtils.isVisible(optionSelectSubview),
"The option select subview should be visible"
);
Assert.ok(
BrowserTestUtils.isHidden(
abView.querySelector("#addressBookAccountSelectSubview")
),
"The account select subview should be hidden"
);
// Making the address book view visible, the init function should run.
const spy = sinon.spy(abView, "init");
abView.hidden = true;
// Check that init() isn't called when the view is hidden.
Assert.equal(
spy.callCount,
0,
"Address book view should not have called init() once"
);
abView.hidden = false;
// Check that init has been called when the view is visible.
Assert.equal(spy.callCount, 1, "Address book view should have called init()");
});
add_task(async function test_reset() {
// Change the subview and footer buttons manually.
abView.querySelector("#addressBookOptionSelectSubview").hidden = true;
abView.querySelector("#addressBookAccountSelectSubview").hidden = false;
const footer = abView.querySelector("#addressBookFooter");
footer.canBack(true);
footer.canForward(true);
// Create a test state and add a resetState stub to a subview object.
const testState = {
subview: { resetState: sinon.stub() },
};
testState.subview.resetState.returns(true);
// Insert the state into the address book state.
abView.insertTestState("resetState", testState);
// Call reset on the address book view, making the address book option select
// subview visible, and reseting the footer buttons (this subview has both
// hidden).
await abView.reset();
Assert.ok(
BrowserTestUtils.isVisible(
abView.querySelector("#addressBookOptionSelectSubview")
),
"The option select subview should be visible"
);
Assert.ok(
BrowserTestUtils.isHidden(
abView.querySelector("#addressBookAccountSelectSubview")
),
"The account select subview should be hidden"
);
Assert.ok(
BrowserTestUtils.isHidden(footer.querySelector("#forward")),
"The footer forward button should be hidden"
);
Assert.ok(
BrowserTestUtils.isHidden(footer.querySelector("#back")),
"The footer back button should be hidden"
);
// Check if resetState has been called on the test state subview object.
Assert.equal(
testState.subview.resetState.callCount,
1,
"Test state subview should have called resetState"
);
});
add_task(async function test_optionAndAccountSelectFormSubmission() {
abView.insertTestAccount(testAccount);
const optionSelectSubview = abView.querySelector(
"address-book-option-select"
);
// To spy on the setState function of account select, we need to first load
// it by viewing it, and then go back to option select to see if setState is
// called when the form is submitted again.
const accountSelectSubview = await subtest_viewAccountOptions();
let setStateSpy = sinon.spy(accountSelectSubview, "setState");
const backButton = abView.querySelector("account-hub-footer #back");
let subviewHiddenPromise = BrowserTestUtils.waitForAttribute(
"hidden",
accountSelectSubview
);
EventUtils.synthesizeMouseAtCenter(backButton, {}, abView.ownerGlobal);
await subviewHiddenPromise;
await BrowserTestUtils.waitForAttributeRemoval("hidden", optionSelectSubview);
Assert.ok(
BrowserTestUtils.isHidden(accountSelectSubview),
"The account select subview should be hidden"
);
Assert.ok(
BrowserTestUtils.isVisible(optionSelectSubview),
"The option select subview should be visible"
);
EventUtils.synthesizeMouseAtCenter(
optionSelectSubview.querySelector("#syncExistingAccounts"),
{},
abView.ownerGlobal
);
await TestUtils.waitForCondition(
() => accountSelectSubview.querySelector('button[value="test@test.com"]'),
"The account-select subview should show an account button"
);
Assert.equal(
setStateSpy.callCount,
1,
"Account select subview should have called setState"
);
// To spy on the setState function of the syncSubview, we need to first load
// it by viewing it, and then go back to account select to see if setState is
// called when the form is submitted again.
const syncSubview = await subtest_viewSyncAddressBooks(accountSelectSubview);
setStateSpy = sinon.spy(syncSubview, "setState");
subviewHiddenPromise = BrowserTestUtils.waitForAttribute(
"hidden",
syncSubview
);
EventUtils.synthesizeMouseAtCenter(backButton, {}, abView.ownerGlobal);
await subviewHiddenPromise;
await BrowserTestUtils.waitForAttributeRemoval(
"hidden",
accountSelectSubview
);
Assert.ok(
BrowserTestUtils.isHidden(syncSubview),
"The sync subview should be hidden"
);
Assert.ok(
BrowserTestUtils.isVisible(accountSelectSubview),
"The account select subview should be visible"
);
subviewHiddenPromise = BrowserTestUtils.waitForAttribute(
"hidden",
accountSelectSubview
);
const accountButton = accountSelectSubview.querySelector(
'button[value="test@test.com"]'
);
EventUtils.synthesizeMouseAtCenter(accountButton, {}, abView.ownerGlobal);
await subviewHiddenPromise;
await BrowserTestUtils.waitForAttributeRemoval("hidden", syncSubview);
Assert.ok(
BrowserTestUtils.isHidden(accountSelectSubview),
"The account select subview should be hidden"
);
Assert.ok(
BrowserTestUtils.isVisible(syncSubview),
"The sync subview should be visible"
);
Assert.equal(
setStateSpy.callCount,
1,
"Address book sync subview should have called setState"
);
abView.removeTestAccount(testAccount);
abView.reset();
});
add_task(async function test_configUpdatedEvent() {
await TestUtils.waitForCondition(
() => abView.hasConnected,
"The address book subview should be connected"
);
const viewSubmit = BrowserTestUtils.waitForEvent(abView, "submit");
EventUtils.synthesizeMouseAtCenter(
abView.querySelector("#addRemoteAddressBook"),
{},
abView.ownerGlobal
);
await viewSubmit;
const forwardButton = abView.querySelector("#forward");
const incompleteEvent = new CustomEvent("config-updated", {
bubbles: true,
detail: { completed: false },
});
abView.dispatchEvent(incompleteEvent);
Assert.ok(
forwardButton.disabled,
"Forward should be disabled with incomplete config"
);
const completeEvent = new CustomEvent("config-updated", {
bubbles: true,
detail: { completed: true },
});
abView.dispatchEvent(completeEvent);
Assert.ok(
!forwardButton.disabled,
"Should enable forward button with complete config"
);
await abView.reset();
});
add_task(async function test_syncAllAddressBooks() {
setTestAccountWithAddressBookStubs();
const accountSelectSubview = await subtest_viewAccountOptions();
await subtest_viewSyncAddressBooks(accountSelectSubview);
await subtest_clickContinue();
// Check if create() was called for each address book.
Assert.equal(
testAccount.addressBooks[0].create.callCount,
1,
"First address book should have called create"
);
Assert.equal(
testAccount.addressBooks[1].create.callCount,
1,
"Second address booko should have called create"
);
abView.removeTestAccount(testAccount);
await abView.reset();
});
add_task(async function test_syncOneAddressBook() {
setTestAccountWithAddressBookStubs();
const accountSelectSubview = await subtest_viewAccountOptions();
const syncSubview = await subtest_viewSyncAddressBooks(accountSelectSubview);
// Uncheck the first address book.
EventUtils.synthesizeMouseAtCenter(
syncSubview.querySelector("input"),
{},
abView.ownerGlobal
);
await subtest_clickContinue();
// Check if create() was called for the second address book.
Assert.equal(
testAccount.addressBooks[0].create.callCount,
0,
"First address book should have called create"
);
Assert.equal(
testAccount.addressBooks[1].create.callCount,
1,
"Second address booko should have called create"
);
abView.removeTestAccount(testAccount);
await abView.reset();
});
add_task(async function test_syncNoAddressBooks() {
setTestAccountWithAddressBookStubs();
const accountSelectSubview = await subtest_viewAccountOptions();
const syncSubview = await subtest_viewSyncAddressBooks(accountSelectSubview);
// Uncheck the first address book.
EventUtils.synthesizeMouseAtCenter(
syncSubview.querySelector("#selectAllAddressBooks"),
{},
abView.ownerGlobal
);
await subtest_clickContinue();
// Check if create() wasn't called for either address book.
Assert.equal(
testAccount.addressBooks[0].create.callCount,
0,
"First address book should have called create"
);
Assert.equal(
testAccount.addressBooks[1].create.callCount,
0,
"Second address booko should have called create"
);
abView.removeTestAccount(testAccount);
await abView.reset();
});
/**
* Subtest to view the account select books subview.
*
* @returns {HTMLElement}
*/
async function subtest_viewAccountOptions() {
// Add a test account to the address-book #accounts variable
const optionSelectSubview = abView.querySelector(
"address-book-option-select"
);
// Enable the sync accounts option and select it.
const syncAccountsButton = optionSelectSubview.querySelector(
"#syncExistingAccounts"
);
syncAccountsButton.disabled = false;
const formSubmissionPromise = BrowserTestUtils.waitForEvent(
optionSelectSubview,
"submit"
);
EventUtils.synthesizeMouseAtCenter(
syncAccountsButton,
{},
abView.ownerGlobal
);
await formSubmissionPromise;
const accountSelectSubview = abView.querySelector(
"address-book-account-select"
);
await TestUtils.waitForCondition(
() => accountSelectSubview.hasConnected,
"The account-select subview should be connected"
);
return accountSelectSubview;
}
/**
* Subtest to view the sync address books subview from the account select
* subview.
*
* @param {HTMLElement} accountSelectSubview - The account select step.
* @returns {HTMLElement}
*/
async function subtest_viewSyncAddressBooks(accountSelectSubview) {
const accountButton = accountSelectSubview.querySelector(
'button[value="test@test.com"]'
);
const formSubmissionPromise = BrowserTestUtils.waitForEvent(
accountSelectSubview,
"submit"
);
EventUtils.synthesizeMouseAtCenter(accountButton, {}, abView.ownerGlobal);
await formSubmissionPromise;
const syncSubview = abView.querySelector("address-book-sync");
await TestUtils.waitForCondition(
() => syncSubview.hasConnected,
"The sync subview should be connected"
);
return syncSubview;
}
/**
* Adds function stubs to the create property of each address book in the test
* account.
*/
function setTestAccountWithAddressBookStubs() {
testAccount.addressBooks[0].create = sinon.stub();
testAccount.addressBooks[1].create = sinon.stub();
testAccount.addressBooks[0].create.returns(true);
testAccount.addressBooks[1].create.returns(true);
abView.insertTestAccount(testAccount);
}
/**
* Subtest to click the continue button in the account hub footer.
*/
async function subtest_clickContinue() {
const forwardButton = abView.querySelector("account-hub-footer #forward");
const formSubmissionPromise = BrowserTestUtils.waitForEvent(
abView.querySelector("account-hub-footer"),
"forward"
);
EventUtils.synthesizeMouseAtCenter(forwardButton, {}, abView.ownerGlobal);
await formSubmissionPromise;
}