From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../addrbook/test/browser/browser_display_card.js | 1020 ++++++++++++++++++++ 1 file changed, 1020 insertions(+) create mode 100644 comm/mail/components/addrbook/test/browser/browser_display_card.js (limited to 'comm/mail/components/addrbook/test/browser/browser_display_card.js') diff --git a/comm/mail/components/addrbook/test/browser/browser_display_card.js b/comm/mail/components/addrbook/test/browser/browser_display_card.js new file mode 100644 index 0000000000..4d468ed646 --- /dev/null +++ b/comm/mail/components/addrbook/test/browser/browser_display_card.js @@ -0,0 +1,1020 @@ +/* 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/. */ + +requestLongerTimeout(2); + +var { CalendarTestUtils } = ChromeUtils.import( + "resource://testing-common/calendar/CalendarTestUtils.jsm" +); +var { MockRegistrar } = ChromeUtils.importESModule( + "resource://testing-common/MockRegistrar.sys.mjs" +); + +var { VCardUtils } = ChromeUtils.import("resource:///modules/VCardUtils.jsm"); +var { AddrBookCard } = ChromeUtils.import( + "resource:///modules/AddrBookCard.jsm" +); + +/** @implements {nsIExternalProtocolService} */ +let mockExternalProtocolService = { + _loadedURLs: [], + externalProtocolHandlerExists(aProtocolScheme) {}, + getApplicationDescription(aScheme) {}, + getProtocolHandlerInfo(aProtocolScheme) {}, + getProtocolHandlerInfoFromOS(aProtocolScheme, aFound) {}, + isExposedProtocol(aProtocolScheme) {}, + loadURI(aURI, aWindowContext) { + this._loadedURLs.push(aURI.spec); + }, + setProtocolHandlerDefaults(aHandlerInfo, aOSHandlerExists) {}, + urlLoaded(aURL) { + return this._loadedURLs.includes(aURL); + }, + QueryInterface: ChromeUtils.generateQI(["nsIExternalProtocolService"]), +}; + +add_setup(async function () { + // Card 0. + personalBook.addCard( + VCardUtils.vCardToAbCard("BEGIN:VCARD\r\nEND:VCARD\r\n") + ); + // Card 1. + personalBook.addCard( + VCardUtils.vCardToAbCard(formatVCard` + BEGIN:VCARD + FN:basic person + EMAIL:basic@invalid + END:VCARD + `) + ); + // Card 2. + personalBook.addCard( + VCardUtils.vCardToAbCard(formatVCard` + BEGIN:VCARD + FN:complex person + EMAIL:secondary@invalid + EMAIL;PREF=1:primary@invalid + EMAIL;TYPE=WORK:tertiary@invalid + TEL;VALUE=URI:tel:000-0000 + TEL;TYPE=WORK,VOICE:callto:111-1111 + TEL;TYPE=VOICE,WORK:222-2222 + TEL;TYPE=HOME;TYPE=VIDEO:tel:333-3333 + ADR:;;street,suburb;city;state;zip;country + ANNIVERSARY:2018-06-11 + BDAY;VALUE=DATE:--0229 + NOTE:mary had a little lamb\\nits fleece was white as snow\\nand everywhere t + hat mary went\\nthe lamb was sure to go + ORG:thunderbird;engineering + ROLE:sheriff + TITLE:senior engineering lead + TZ;VALUE=TEXT:Pacific/Auckland + URL;TYPE=work:https://www.thunderbird.net/ + IMPP:xmpp:cowboy@example.org + END:VCARD + `) + ); + + MailServices.accounts.createLocalMailAccount(); + let account = MailServices.accounts.accounts[0]; + account.addIdentity(MailServices.accounts.createIdentity()); + + let calendar = CalendarTestUtils.createCalendar(); + + let mockExternalProtocolServiceCID = MockRegistrar.register( + "@mozilla.org/uriloader/external-protocol-service;1", + mockExternalProtocolService + ); + + registerCleanupFunction(async () => { + personalBook.deleteCards(personalBook.childCards); + MailServices.accounts.removeAccount(account, true); + CalendarTestUtils.removeCalendar(calendar); + MockRegistrar.unregister(mockExternalProtocolServiceCID); + }); +}); + +/** + * Checks basic display. + */ +add_task(async function testDisplay() { + let abWindow = await openAddressBookWindow(); + openDirectory(personalBook); + + let abDocument = abWindow.document; + let cardsList = abDocument.getElementById("cards"); + let detailsPane = abDocument.getElementById("detailsPane"); + + let viewContactName = abDocument.getElementById("viewContactName"); + let viewPrimaryEmail = abDocument.getElementById("viewPrimaryEmail"); + let editButton = abDocument.getElementById("editButton"); + + let emailAddressesSection = abDocument.getElementById("emailAddresses"); + let phoneNumbersSection = abDocument.getElementById("phoneNumbers"); + let addressesSection = abDocument.getElementById("addresses"); + let notesSection = abDocument.getElementById("notes"); + let websitesSection = abDocument.getElementById("websites"); + let imppSection = abDocument.getElementById("instantMessaging"); + let otherInfoSection = abDocument.getElementById("otherInfo"); + let selectedCardsSection = abDocument.getElementById("selectedCards"); + + Assert.equal(cardsList.view.rowCount, personalBook.childCardCount); + Assert.ok(detailsPane.hidden); + + // Card 0: an empty card. + + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(0), {}, abWindow); + await TestUtils.waitForCondition(() => + BrowserTestUtils.is_visible(detailsPane) + ); + + // Header. + Assert.equal(viewContactName.textContent, ""); + Assert.equal(viewPrimaryEmail.textContent, ""); + + // Action buttons. + await checkActionButtons(); + Assert.ok(BrowserTestUtils.is_visible(editButton)); + + Assert.ok(BrowserTestUtils.is_hidden(emailAddressesSection)); + Assert.ok(BrowserTestUtils.is_hidden(phoneNumbersSection)); + Assert.ok(BrowserTestUtils.is_hidden(addressesSection)); + Assert.ok(BrowserTestUtils.is_hidden(notesSection)); + Assert.ok(BrowserTestUtils.is_hidden(otherInfoSection)); + Assert.ok(BrowserTestUtils.is_hidden(selectedCardsSection)); + + // Card 1: an basic card. + + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(1), {}, abWindow); + await TestUtils.waitForCondition(() => + BrowserTestUtils.is_visible(detailsPane) + ); + + // Header. + Assert.equal(viewContactName.textContent, "basic person"); + Assert.equal(viewPrimaryEmail.textContent, "basic@invalid"); + + // Action buttons. + await checkActionButtons("basic@invalid", "basic person"); + Assert.ok(BrowserTestUtils.is_visible(editButton)); + + // Email section. + Assert.ok(BrowserTestUtils.is_visible(emailAddressesSection)); + let items = emailAddressesSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal(items[0].querySelector(".entry-type").textContent, ""); + Assert.equal( + items[0].querySelector("a").href, + `mailto:basic%20person%20%3Cbasic%40invalid%3E` + ); + Assert.equal(items[0].querySelector("a").textContent, "basic@invalid"); + + let composeWindowPromise = BrowserTestUtils.domWindowOpened(); + EventUtils.synthesizeMouseAtCenter(items[0].querySelector("a"), {}, abWindow); + await checkComposeWindow( + await composeWindowPromise, + "basic person " + ); + + // Other sections. + Assert.ok(BrowserTestUtils.is_hidden(phoneNumbersSection)); + Assert.ok(BrowserTestUtils.is_hidden(addressesSection)); + Assert.ok(BrowserTestUtils.is_hidden(notesSection)); + Assert.ok(BrowserTestUtils.is_hidden(otherInfoSection)); + Assert.ok(BrowserTestUtils.is_hidden(selectedCardsSection)); + + // Card 2: an complex card. + + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(2), {}, abWindow); + await TestUtils.waitForCondition(() => + BrowserTestUtils.is_visible(detailsPane) + ); + + // Header. + Assert.equal(viewContactName.textContent, "complex person"); + Assert.equal(viewPrimaryEmail.textContent, "primary@invalid"); + + // Action buttons. + await checkActionButtons( + "primary@invalid", + "complex person", + "primary@invalid secondary@invalid tertiary@invalid" + ); + Assert.ok(BrowserTestUtils.is_visible(editButton)); + + // Email section. + Assert.ok(BrowserTestUtils.is_visible(emailAddressesSection)); + items = emailAddressesSection.querySelectorAll("li"); + Assert.equal(items.length, 3); + + Assert.equal(items[0].querySelector(".entry-type").textContent, ""); + Assert.equal( + items[0].querySelector("a").href, + `mailto:complex%20person%20%3Csecondary%40invalid%3E` + ); + Assert.equal(items[0].querySelector("a").textContent, "secondary@invalid"); + + Assert.equal(items[1].querySelector(".entry-type").textContent, ""); + Assert.equal( + items[1].querySelector("a").href, + `mailto:complex%20person%20%3Cprimary%40invalid%3E` + ); + Assert.equal(items[1].querySelector("a").textContent, "primary@invalid"); + + Assert.equal( + items[2].querySelector(".entry-type").dataset.l10nId, + "about-addressbook-entry-type-work" + ); + Assert.equal( + items[2].querySelector("a").href, + `mailto:complex%20person%20%3Ctertiary%40invalid%3E` + ); + Assert.equal(items[2].querySelector("a").textContent, "tertiary@invalid"); + + composeWindowPromise = BrowserTestUtils.domWindowOpened(); + EventUtils.synthesizeMouseAtCenter(items[2].querySelector("a"), {}, abWindow); + await checkComposeWindow( + await composeWindowPromise, + "complex person " + ); + + // Phone numbers section. + Assert.ok(BrowserTestUtils.is_visible(phoneNumbersSection)); + items = phoneNumbersSection.querySelectorAll("li"); + Assert.equal(items.length, 4); + + Assert.equal(items[0].querySelector(".entry-type").textContent, ""); + Assert.equal(items[0].querySelector(".entry-value a").href, `tel:0000000`); + + Assert.equal( + items[1].querySelector(".entry-type").dataset.l10nId, + "about-addressbook-entry-type-work" + ); + Assert.equal(items[1].querySelector(".entry-value").textContent, "111-1111"); + Assert.equal(items[1].querySelector(".entry-value a").href, `callto:1111111`); + + Assert.equal( + items[2].querySelector(".entry-type").dataset.l10nId, + "about-addressbook-entry-type-work" + ); + Assert.equal(items[2].querySelector(".entry-value").textContent, "222-2222"); + + Assert.equal( + items[3].querySelector(".entry-type").dataset.l10nId, + "about-addressbook-entry-type-home" + ); + Assert.equal(items[3].querySelector(".entry-value").textContent, "333-3333"); + Assert.equal(items[3].querySelector(".entry-value a").href, `tel:3333333`); + + // Addresses section. + Assert.ok(BrowserTestUtils.is_visible(addressesSection)); + items = addressesSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + + Assert.equal(items[0].querySelector(".entry-type").textContent, ""); + Assert.equal(items[0].querySelector(".entry-value").childNodes.length, 11); + Assert.deepEqual( + Array.from( + items[0].querySelector(".entry-value").childNodes, + n => n.textContent + ), + ["street", "", "suburb", "", "city", "", "state", "", "zip", "", "country"] + ); + + // Notes section. + Assert.ok(BrowserTestUtils.is_visible(notesSection)); + Assert.equal( + notesSection.querySelector("div").textContent, + "mary had a little lamb\nits fleece was white as snow\nand everywhere that mary went\nthe lamb was sure to go" + ); + + // Websites section + Assert.ok(BrowserTestUtils.is_visible(websitesSection)); + items = websitesSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal( + items[0].children[0].dataset.l10nId, + "about-addressbook-entry-type-work" + ); + Assert.equal( + items[0].children[1].querySelector("a").href, + "https://www.thunderbird.net/" + ); + Assert.equal( + items[0].children[1].querySelector("a").textContent, + "www.thunderbird.net" + ); + items[0].children[1].querySelector("a").scrollIntoView(); + EventUtils.synthesizeMouseAtCenter( + items[0].children[1].querySelector("a"), + {}, + abWindow + ); + await TestUtils.waitForCondition( + () => mockExternalProtocolService.urlLoaded("https://www.thunderbird.net/"), + "attempted to load website in a browser" + ); + + // Instant messaging section + Assert.ok(BrowserTestUtils.is_visible(imppSection)); + items = imppSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal( + items[0].children[1].querySelector("a").href, + "xmpp:cowboy@example.org" + ); + + // Other sections. + Assert.ok(BrowserTestUtils.is_visible(otherInfoSection)); + items = otherInfoSection.querySelectorAll("li"); + Assert.equal(items.length, 6, "number of
  • in section should be correct"); + Assert.equal( + items[0].children[0].dataset.l10nId, + "about-addressbook-entry-name-birthday" + ); + Assert.equal(items[0].children[1].textContent, "February 29"); + Assert.equal( + items[1].children[0].dataset.l10nId, + "about-addressbook-entry-name-anniversary" + ); + Assert.equal(items[1].children[1].textContent, "June 11, 2018"); + + Assert.equal( + items[2].children[0].dataset.l10nId, + "about-addressbook-entry-name-title" + ); + Assert.equal(items[2].children[1].textContent, "senior engineering lead"); + Assert.equal( + items[3].children[0].dataset.l10nId, + "about-addressbook-entry-name-role" + ); + Assert.equal(items[3].children[1].textContent, "sheriff"); + Assert.equal( + items[4].children[0].dataset.l10nId, + "about-addressbook-entry-name-organization" + ); + Assert.deepEqual( + Array.from( + items[4].querySelector(".entry-value").childNodes, + n => n.textContent + ), + ["engineering", " • ", "thunderbird"] + ); + Assert.equal( + items[5].children[0].dataset.l10nId, + "about-addressbook-entry-name-time-zone" + ); + Assert.equal(items[5].children[1].firstChild.nodeValue, "Pacific/Auckland"); + Assert.equal( + items[5].children[1].lastChild.getAttribute("is"), + "active-time" + ); + Assert.equal( + items[5].children[1].lastChild.getAttribute("tz"), + "Pacific/Auckland" + ); + Assert.ok(BrowserTestUtils.is_hidden(selectedCardsSection)); + + // Card 0, again, just to prove that everything was cleared properly. + + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(0), {}, abWindow); + await TestUtils.waitForCondition(() => + BrowserTestUtils.is_visible(detailsPane) + ); + + // Header. + Assert.equal(viewContactName.textContent, ""); + Assert.equal(viewPrimaryEmail.textContent, ""); + + // Action buttons. + await checkActionButtons(); + Assert.ok(BrowserTestUtils.is_visible(editButton)); + + Assert.ok(BrowserTestUtils.is_hidden(emailAddressesSection)); + Assert.ok(BrowserTestUtils.is_hidden(phoneNumbersSection)); + Assert.ok(BrowserTestUtils.is_hidden(addressesSection)); + Assert.ok(BrowserTestUtils.is_hidden(notesSection)); + Assert.ok(BrowserTestUtils.is_hidden(otherInfoSection)); + Assert.ok(BrowserTestUtils.is_hidden(selectedCardsSection)); + + await closeAddressBookWindow(); +}); + +/** + * Test the display of dates with various components missing. + */ +add_task(async function testDates() { + let abWindow = await openAddressBookWindow(); + let otherInfoSection = abWindow.document.getElementById("otherInfo"); + + // Year only. + + let yearCard = await addAndDisplayCard(formatVCard` + BEGIN:VCARD + EMAIL:xbasic3@invalid + ANNIVERSARY:2005 + END:VCARD + `); + Assert.ok(BrowserTestUtils.is_visible(otherInfoSection)); + let items = otherInfoSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal( + items[0].children[0].dataset.l10nId, + "about-addressbook-entry-name-anniversary" + ); + Assert.equal(items[0].children[1].textContent, "2005"); + + // Year and month. + + let yearMonthCard = await addAndDisplayCard(formatVCard` + BEGIN:VCARD + EMAIL:xbasic4@invalid + ANNIVERSARY:2006-06 + END:VCARD + `); + Assert.ok(BrowserTestUtils.is_visible(otherInfoSection)); + items = otherInfoSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal( + items[0].children[0].dataset.l10nId, + "about-addressbook-entry-name-anniversary" + ); + Assert.equal(items[0].children[1].textContent, "June 2006"); + + // Month only. + let monthCard = await addAndDisplayCard(formatVCard` + BEGIN:VCARD + EMAIL:xbasic5@invalid + ANNIVERSARY:--12 + END:VCARD + `); + Assert.ok(BrowserTestUtils.is_visible(otherInfoSection)); + items = otherInfoSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal( + items[0].children[0].dataset.l10nId, + "about-addressbook-entry-name-anniversary" + ); + Assert.equal(items[0].children[1].textContent, "December"); + + // Month and day. + let monthDayCard = await addAndDisplayCard(formatVCard` + BEGIN:VCARD + EMAIL:xbasic6@invalid + ANNIVERSARY;VALUE=DATE:--0704 + END:VCARD + `); + Assert.ok(BrowserTestUtils.is_visible(otherInfoSection)); + items = otherInfoSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal( + items[0].children[0].dataset.l10nId, + "about-addressbook-entry-name-anniversary" + ); + Assert.equal(items[0].children[1].textContent, "July 4"); + + // Day only. + let dayCard = await addAndDisplayCard(formatVCard` + BEGIN:VCARD + EMAIL:xbasic7@invalid + ANNIVERSARY:---30 + END:VCARD + `); + Assert.ok(BrowserTestUtils.is_visible(otherInfoSection)); + items = otherInfoSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal( + items[0].children[0].dataset.l10nId, + "about-addressbook-entry-name-anniversary" + ); + Assert.equal(items[0].children[1].textContent, "30"); + + await closeAddressBookWindow(); + personalBook.deleteCards([ + yearCard, + yearMonthCard, + monthCard, + monthDayCard, + dayCard, + ]); +}); + +/** + * Only an organisation name. + */ +add_task(async function testOrganisationNameOnly() { + let card = await addAndDisplayCard( + VCardUtils.vCardToAbCard(formatVCard` + BEGIN:VCARD + ORG:organisation + END:VCARD + `) + ); + + let abWindow = await getAddressBookWindow(); + let viewContactName = abWindow.document.getElementById("viewContactName"); + Assert.equal(viewContactName.textContent, "organisation"); + + await closeAddressBookWindow(); + personalBook.deleteCards([card]); +}); + +/** + * Tests that custom properties (Custom1 etc.) are displayed. + */ +add_task(async function testCustomProperties() { + let card = new AddrBookCard(); + card._properties = new Map([ + ["PopularityIndex", 0], + ["Custom2", "custom two"], + ["Custom4", "custom four"], + [ + "_vCard", + formatVCard` + BEGIN:VCARD + FN:custom person + X-CUSTOM3:x-custom three + X-CUSTOM4:x-custom four + END:VCARD + `, + ], + ]); + card = await addAndDisplayCard(card); + + let abWindow = await getAddressBookWindow(); + let otherInfoSection = abWindow.document.getElementById("otherInfo"); + + Assert.ok(BrowserTestUtils.is_visible(otherInfoSection)); + + let items = otherInfoSection.querySelectorAll("li"); + Assert.equal(items.length, 3); + // Custom 1 has no value, should not display. + // Custom 2 has an old property value, should display that. + + await TestUtils.waitForCondition(() => { + return items[0].children[0].textContent; + }, "text not created in time"); + + Assert.equal(items[0].children[0].textContent, "Custom 2"); + Assert.equal(items[0].children[1].textContent, "custom two"); + // Custom 3 has a vCard property value, should display that. + Assert.equal(items[1].children[0].textContent, "Custom 3"); + Assert.equal(items[1].children[1].textContent, "x-custom three"); + // Custom 4 has both types of value, the vCard value should be displayed. + Assert.equal(items[2].children[0].textContent, "Custom 4"); + Assert.equal(items[2].children[1].textContent, "x-custom four"); + + await closeAddressBookWindow(); + personalBook.deleteCards([card]); +}); + +/** + * Checks that the edit button is hidden for read-only contacts. + */ +add_task(async function testReadOnlyActions() { + let readOnlyBook = createAddressBook("Read-Only Book"); + let readOnlyList = readOnlyBook.addMailList( + createMailingList("Read-Only List") + ); + readOnlyBook.addCard( + VCardUtils.vCardToAbCard(formatVCard` + BEGIN:VCARD + FN:read-only person + END:VCARD + `) + ); + readOnlyList.addCard( + readOnlyBook.addCard( + VCardUtils.vCardToAbCard(formatVCard` + BEGIN:VCARD + FN:read-only person with email + EMAIL:read.only@invalid + END:VCARD + `) + ) + ); + readOnlyBook.setBoolValue("readOnly", true); + + let abWindow = await openAddressBookWindow(); + + let abDocument = abWindow.document; + let cardsList = abDocument.getElementById("cards"); + let detailsPane = abDocument.getElementById("detailsPane"); + let contactView = abDocument.getElementById("viewContact"); + + let actions = abDocument.getElementById("detailsActions"); + let editButton = abDocument.getElementById("editButton"); + let editForm = abDocument.getElementById("editContactForm"); + + let selectHandler = { + seenEvent: null, + selectedAtEvent: null, + + reset() { + this.seenEvent = null; + this.selectedAtEvent = null; + }, + handleEvent(event) { + this.seenEvent = event; + this.selectedAtEvent = cardsList.selectedIndex; + }, + }; + + // Check contacts with the book displayed. + + openDirectory(readOnlyBook); + Assert.equal(cardsList.view.rowCount, 3); + Assert.ok(BrowserTestUtils.is_hidden(detailsPane)); + + // Without email. + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(1), {}, abWindow); + Assert.ok( + BrowserTestUtils.is_visible(contactView), + "contact view should be shown" + ); + Assert.ok( + BrowserTestUtils.is_hidden(actions), + "actions section should be hidden" + ); + + // With email. + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(2), {}, abWindow); + Assert.ok(BrowserTestUtils.is_visible(actions), "actions section is shown"); + await checkActionButtons("read.only@invalid", "read-only person with email"); + Assert.ok(BrowserTestUtils.is_hidden(editButton), "editButton is hidden"); + + // Double clicking on the item will select but not edit it. + EventUtils.synthesizeMouseAtCenter( + cardsList.getRowAtIndex(1), + { clickCount: 1 }, + abWindow + ); + EventUtils.synthesizeMouseAtCenter( + cardsList.getRowAtIndex(1), + { clickCount: 2 }, + abWindow + ); + // Wait one loop to see if edit form was opened. + await TestUtils.waitForTick(); + Assert.ok( + BrowserTestUtils.is_visible(contactView), + "contact view should be shown" + ); + Assert.ok( + BrowserTestUtils.is_hidden(editForm), + "contact form should be hidden" + ); + Assert.ok( + BrowserTestUtils.is_hidden(actions), + "actions section should be hidden" + ); + Assert.equal( + cardsList.table.body, + abDocument.activeElement, + "Cards list should be the active element" + ); + + selectHandler.reset(); + cardsList.addEventListener("select", selectHandler, { once: true }); + // Same with Enter on the second item. + EventUtils.synthesizeKey("KEY_ArrowDown", {}, abWindow); + await TestUtils.waitForCondition( + () => selectHandler.seenEvent, + `'select' event should get fired` + ); + Assert.ok( + BrowserTestUtils.is_visible(contactView), + "contact view should be shown" + ); + Assert.ok( + BrowserTestUtils.is_hidden(editForm), + "contact form should be hidden" + ); + Assert.ok( + BrowserTestUtils.is_visible(actions), + "actions section should be shown" + ); + Assert.ok( + BrowserTestUtils.is_hidden(editButton), + "editButton should be hidden" + ); + + EventUtils.synthesizeKey("KEY_Enter", {}, abWindow); + await TestUtils.waitForTick(); + Assert.ok( + BrowserTestUtils.is_visible(contactView), + "contact view should be shown" + ); + Assert.ok( + BrowserTestUtils.is_hidden(editForm), + "contact form should be hidden" + ); + Assert.ok( + BrowserTestUtils.is_visible(actions), + "actions section should be shown" + ); + Assert.ok( + BrowserTestUtils.is_hidden(editForm), + "contact form should be hidden" + ); + + // Check contacts with the list displayed. + + openDirectory(readOnlyList); + Assert.equal(cardsList.view.rowCount, 1); + Assert.ok(BrowserTestUtils.is_hidden(detailsPane)); + + // With email. + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(0), {}, abWindow); + Assert.ok(BrowserTestUtils.is_visible(contactView)); + Assert.ok(BrowserTestUtils.is_visible(actions), "actions section is shown"); + await checkActionButtons("read.only@invalid", "read-only person with email"); + Assert.ok(BrowserTestUtils.is_hidden(editButton), "editButton is hidden"); + + // Check contacts with All Address Books displayed. + + openAllAddressBooks(); + Assert.equal(cardsList.view.rowCount, 6); + Assert.ok(BrowserTestUtils.is_hidden(detailsPane)); + + // Basic person from Personal Address Books. + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(1), {}, abWindow); + Assert.ok(BrowserTestUtils.is_visible(contactView)); + Assert.ok(BrowserTestUtils.is_visible(actions), "actions section is shown"); + await checkActionButtons("basic@invalid", "basic person"); + Assert.ok(BrowserTestUtils.is_visible(editButton), "edit button is shown"); + + // Without email. + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(4), {}, abWindow); + Assert.ok(BrowserTestUtils.is_visible(contactView)); + Assert.ok(BrowserTestUtils.is_hidden(actions), "actions section is hidden"); + + // With email. + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(5), {}, abWindow); + Assert.ok(BrowserTestUtils.is_visible(actions), "actions section is shown"); + await checkActionButtons("read.only@invalid", "read-only person with email"); + Assert.ok(BrowserTestUtils.is_hidden(editButton), "editButton is hidden"); + + // Basic person again, to prove the buttons aren't hidden forever. + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(1), {}, abWindow); + Assert.ok(BrowserTestUtils.is_visible(contactView)); + Assert.ok(BrowserTestUtils.is_visible(actions), "actions section is shown"); + await checkActionButtons("basic@invalid", "basic person"); + Assert.ok(BrowserTestUtils.is_visible(editButton), "edit button is shown"); + + await closeAddressBookWindow(); + await promiseDirectoryRemoved(readOnlyBook.URI); +}); + +/** + * Tests that we correctly fix Google's bad escaping of colons in values, and + * other characters in URI values. + */ +add_task(async function testGoogleEscaping() { + let googleBook = createAddressBook("Google Book"); + googleBook.wrappedJSObject._isGoogleCardDAV = true; + googleBook.addCard( + VCardUtils.vCardToAbCard(formatVCard` + BEGIN:VCARD + VERSION:3.0 + N:test;en\\\\c\\:oding;;; + FN:en\\\\c\\:oding test + TITLE:title\\:title\\;title\\,title\\\\title\\\\\\:title\\\\\\;title\\\\\\,title\\\\\\\\ + TEL:tel\\:0123\\\\4567 + NOTE:notes\\:\\nnotes\\;\\nnotes\\,\\nnotes\\\\ + URL:https\\://host/url\\:url\\;url\\,url\\\\url + END:VCARD + `) + ); + + let abWindow = await openAddressBookWindow(); + + let abDocument = abWindow.document; + let cardsList = abDocument.getElementById("cards"); + let detailsPane = abDocument.getElementById("detailsPane"); + + let viewContactName = abDocument.getElementById("viewContactName"); + let viewPrimaryEmail = abDocument.getElementById("viewPrimaryEmail"); + let editButton = abDocument.getElementById("editButton"); + + let emailAddressesSection = abDocument.getElementById("emailAddresses"); + let phoneNumbersSection = abDocument.getElementById("phoneNumbers"); + let addressesSection = abDocument.getElementById("addresses"); + let notesSection = abDocument.getElementById("notes"); + let websitesSection = abDocument.getElementById("websites"); + let imppSection = abDocument.getElementById("instantMessaging"); + let otherInfoSection = abDocument.getElementById("otherInfo"); + let selectedCardsSection = abDocument.getElementById("selectedCards"); + + openDirectory(googleBook); + Assert.equal(cardsList.view.rowCount, 1); + Assert.ok(BrowserTestUtils.is_hidden(detailsPane)); + + EventUtils.synthesizeMouseAtCenter(cardsList.getRowAtIndex(0), {}, abWindow); + await TestUtils.waitForCondition(() => + BrowserTestUtils.is_visible(detailsPane) + ); + + // Header. + Assert.equal(viewContactName.textContent, "en\\c:oding test"); + Assert.equal(viewPrimaryEmail.textContent, ""); + + // Action buttons. + await checkActionButtons(); + Assert.ok(BrowserTestUtils.is_visible(editButton)); + + // Email section. + Assert.ok(BrowserTestUtils.is_hidden(emailAddressesSection)); + + // Phone numbers section. + Assert.ok(BrowserTestUtils.is_visible(phoneNumbersSection)); + let items = phoneNumbersSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + + Assert.equal(items[0].querySelector(".entry-type").textContent, ""); + Assert.equal(items[0].querySelector(".entry-value").textContent, "01234567"); + + // Addresses section. + Assert.ok(BrowserTestUtils.is_hidden(addressesSection)); + + // Notes section. + Assert.ok(BrowserTestUtils.is_visible(notesSection)); + Assert.equal( + notesSection.querySelector("div").textContent, + "notes:\nnotes;\nnotes,\nnotes\\" + ); + + // Websites section + Assert.ok(BrowserTestUtils.is_visible(websitesSection)); + items = websitesSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal( + items[0].children[1].querySelector("a").href, + "https://host/url:url;url,url/url" + ); + Assert.equal( + items[0].children[1].querySelector("a").textContent, + "host/url:url;url,url/url" + ); + items[0].children[1].querySelector("a").scrollIntoView(); + EventUtils.synthesizeMouseAtCenter( + items[0].children[1].querySelector("a"), + {}, + abWindow + ); + await TestUtils.waitForCondition( + () => + mockExternalProtocolService.urlLoaded("https://host/url:url;url,url/url"), + "attempted to load website in a browser" + ); + + // Instant messaging section. + Assert.ok(BrowserTestUtils.is_hidden(imppSection)); + + // Other sections. + Assert.ok(BrowserTestUtils.is_visible(otherInfoSection)); + items = otherInfoSection.querySelectorAll("li"); + Assert.equal(items.length, 1); + Assert.equal( + items[0].children[0].dataset.l10nId, + "about-addressbook-entry-name-title" + ); + Assert.equal( + items[0].children[1].textContent, + "title:title;title,title\\title\\:title\\;title\\,title\\\\" + ); + + Assert.ok(BrowserTestUtils.is_hidden(selectedCardsSection)); + + await closeAddressBookWindow(); + await promiseDirectoryRemoved(googleBook.URI); +}); + +async function addAndDisplayCard(card) { + if (typeof card == "string") { + card = VCardUtils.vCardToAbCard(card); + } + card = personalBook.addCard(card); + + let abWindow = await openAddressBookWindow(); + let abDocument = abWindow.document; + let cardsList = abDocument.getElementById("cards"); + let detailsPane = abDocument.getElementById("detailsPane"); + + let index = cardsList.view.getIndexForUID(card.UID); + EventUtils.synthesizeMouseAtCenter( + cardsList.getRowAtIndex(index), + {}, + abWindow + ); + await TestUtils.waitForCondition(() => + BrowserTestUtils.is_visible(detailsPane) + ); + return card; +} + +async function checkActionButtons( + primaryEmail, + displayName, + searchString = primaryEmail +) { + let tabmail = document.getElementById("tabmail"); + let abWindow = getAddressBookWindow(); + let abDocument = abWindow.document; + + let writeButton = abDocument.getElementById("detailsWriteButton"); + let eventButton = abDocument.getElementById("detailsEventButton"); + let searchButton = abDocument.getElementById("detailsSearchButton"); + let newListButton = abDocument.getElementById("detailsNewListButton"); + + if (primaryEmail) { + // Write. + Assert.ok( + BrowserTestUtils.is_visible(writeButton), + "write button is visible" + ); + + let composeWindowPromise = BrowserTestUtils.domWindowOpened(); + EventUtils.synthesizeMouseAtCenter(writeButton, {}, abWindow); + await checkComposeWindow( + await composeWindowPromise, + `${displayName} <${primaryEmail}>` + ); + + // Search. Do this before the event test to stop a strange macOS failure. + Assert.ok( + BrowserTestUtils.is_visible(searchButton), + "search button is visible" + ); + + let searchTabPromise = BrowserTestUtils.waitForEvent(window, "TabOpen"); + EventUtils.synthesizeMouseAtCenter(searchButton, {}, abWindow); + let { + detail: { tabInfo: searchTab }, + } = await searchTabPromise; + + let searchBox = tabmail.selectedTab.panel.querySelector(".searchBox"); + Assert.equal(searchBox.value, searchString); + + searchTabPromise = BrowserTestUtils.waitForEvent(window, "TabClose"); + tabmail.closeTab(searchTab); + await searchTabPromise; + + // Event. + Assert.ok( + BrowserTestUtils.is_visible(eventButton), + "event button is visible" + ); + + let eventWindowPromise = CalendarTestUtils.waitForEventDialog("edit"); + EventUtils.synthesizeMouseAtCenter(eventButton, {}, abWindow); + let eventWindow = await eventWindowPromise; + + let iframe = eventWindow.document.getElementById( + "calendar-item-panel-iframe" + ); + let tabPanels = iframe.contentDocument.getElementById( + "event-grid-tabpanels" + ); + let attendeesTabPanel = iframe.contentDocument.getElementById( + "event-grid-tabpanel-attendees" + ); + Assert.equal( + tabPanels.selectedPanel, + attendeesTabPanel, + "attendees are displayed" + ); + let attendeeNames = attendeesTabPanel.querySelectorAll( + ".attendee-list .attendee-name" + ); + Assert.deepEqual( + Array.from(attendeeNames, a => a.textContent), + [`${displayName} <${primaryEmail}>`], + "attendees are correct" + ); + + eventWindowPromise = BrowserTestUtils.domWindowClosed(eventWindow); + BrowserTestUtils.promiseAlertDialog("extra1"); + EventUtils.synthesizeKey("VK_ESCAPE", {}, eventWindow); + await eventWindowPromise; + Assert.report(false, undefined, undefined, "Item dialog closed"); + } else { + Assert.ok( + BrowserTestUtils.is_hidden(writeButton), + "write button is hidden" + ); + Assert.ok( + BrowserTestUtils.is_hidden(eventButton), + "event button is hidden" + ); + Assert.ok( + BrowserTestUtils.is_hidden(searchButton), + "search button is hidden" + ); + } + + Assert.ok( + BrowserTestUtils.is_hidden(newListButton), + "new list button is hidden" + ); +} -- cgit v1.2.3