Bug 1759590 - Add tests for repeating and non-repeating events. r=aleca
Differential Revision: https://phabricator.services.mozilla.com/D142085 --HG-- extra : amend_source : 90b8abd539e1bda8ff4e04fc97fecb11de9e1ffd
This commit is contained in:
Родитель
872ecc309d
Коммит
5fd7226493
|
@ -255,7 +255,7 @@
|
|||
<toolbarbutton is="toolbarbutton-menu-button" id="imipDeclineRecurrencesButton"
|
||||
tooltiptext="&lightning.imipbar.btnDeclineRecurrences2.tooltiptext;"
|
||||
label="&lightning.imipbar.btnDeclineRecurrences.label;"
|
||||
oncommand="calImipBar.executeAction('DECLINED');"
|
||||
oncommand="calImipBar.executeAction('DECLINED', 'AUTO');"
|
||||
type="menu-button"
|
||||
class="toolbarbutton-1 message-header-view-button imipDeclineRecurrencesButton"
|
||||
hidden="true">
|
||||
|
@ -264,7 +264,7 @@
|
|||
tooltiptext="&lightning.imipbar.btnSendSeries.tooltiptext;"
|
||||
label="&lightning.imipbar.btnSend.label;"
|
||||
oncommand="calImipBar.executeAction('DECLINED'); event.stopPropagation();"/>
|
||||
<menuitem id="imipDeclineRecurrencesButton_DeclineAllDontSend"
|
||||
<menuitem id="imipDeclineRecurrencesButton_DeclineDontSend"
|
||||
tooltiptext="&lightning.imipbar.btnDontSendSeries.tooltiptext;"
|
||||
label="&lightning.imipbar.btnDontSend.label;"
|
||||
oncommand="calImipBar.executeAction('DECLINED', 'NONE'); event.stopPropagation();"/>
|
||||
|
|
|
@ -256,8 +256,7 @@ class CalItipEmailTransport {
|
|||
// "@mozilla.org/messengercompose/composesendlistener;1"
|
||||
// and/or "chrome://messenger/content/messengercompose/sendProgress.xhtml"
|
||||
// i.e. bug 432662
|
||||
let msgSend = Cc["@mozilla.org/messengercompose/send;1"].createInstance(Ci.nsIMsgSend);
|
||||
msgSend.sendMessageFile(
|
||||
this.getMsgSend().sendMessageFile(
|
||||
identity,
|
||||
account.key,
|
||||
composeFields,
|
||||
|
@ -366,6 +365,14 @@ class CalItipEmailTransport {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a new nsIMsgSend instance to use when sending the message. This
|
||||
* method can be overridden in child classes for testing or other purposes.
|
||||
*/
|
||||
getMsgSend() {
|
||||
return Cc["@mozilla.org/messengercompose/send;1"].createInstance(Ci.nsIMsgSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the identity and account to use when sending iTIP emails. By
|
||||
* default prefers whatever the item's calendar is configured to use or the
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[default]
|
||||
head = ../head.js
|
||||
head = ../head.js head.js
|
||||
prefs =
|
||||
calendar.item.promptDelete=false
|
||||
calendar.timezone.local=UTC
|
||||
|
@ -16,4 +16,6 @@ support-files = data/**
|
|||
[browser_icsAttachment.js]
|
||||
skip-if = os == 'win'
|
||||
[browser_identityPrompt.js]
|
||||
[browser_imipBar.js]
|
||||
[browser_imipBarEmail.js]
|
||||
[browser_imipBarRepeat.js]
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
/* 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 for receiving event invitations via the imip-bar.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
|
||||
var { CalItipDefaultEmailTransport } = ChromeUtils.import(
|
||||
"resource:///modules/CalItipEmailTransport.jsm"
|
||||
);
|
||||
var { FileUtils } = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
||||
var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
|
||||
|
||||
var { open_message_from_file } = ChromeUtils.import(
|
||||
"resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
|
||||
);
|
||||
var { CalendarTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/calendar/CalendarTestUtils.jsm"
|
||||
);
|
||||
|
||||
let deleteMgr = Cc["@mozilla.org/calendar/deleted-items-manager;1"].getService(Ci.calIDeletedItems)
|
||||
.wrappedJSObject;
|
||||
|
||||
let account;
|
||||
let identity;
|
||||
let calendar;
|
||||
let transport;
|
||||
let getImipTransport;
|
||||
let markDeleted;
|
||||
|
||||
/**
|
||||
* Initialize account, identity and calendar.
|
||||
*/
|
||||
add_setup(async function() {
|
||||
account = MailServices.accounts.createAccount();
|
||||
account.incomingServer = MailServices.accounts.createIncomingServer(
|
||||
"receiver",
|
||||
"example.com",
|
||||
"imap"
|
||||
);
|
||||
identity = MailServices.accounts.createIdentity();
|
||||
identity.email = "receiver@example.com";
|
||||
account.addIdentity(identity);
|
||||
|
||||
await CalendarTestUtils.setCalendarView(window, "month");
|
||||
window.goToDate(cal.createDateTime("20220316T191602Z"));
|
||||
|
||||
calendar = CalendarTestUtils.createCalendar("Test");
|
||||
transport = new EmailTransport(account, identity);
|
||||
getImipTransport = cal.itip.getImipTransport;
|
||||
cal.itip.getImipTransport = () => transport;
|
||||
markDeleted = deleteMgr.markDeleted;
|
||||
deleteMgr.markDeleted = () => {};
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
MailServices.accounts.removeAccount(account, true);
|
||||
cal.itip.getImipTransport = getImipTransport;
|
||||
deleteMgr.markDeleted = markDeleted;
|
||||
CalendarTestUtils.removeCalendar(calendar);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests accepting an invitation and sending a response.
|
||||
*/
|
||||
add_task(async function testAcceptWithResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/single-event.eml")));
|
||||
clickAction(win, "imipAcceptButton");
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
partStat: "ACCEPTED",
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests tentatively accepting an invitation and sending a response.
|
||||
*/
|
||||
add_task(async function testTentativeWithResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/single-event.eml")));
|
||||
clickAction(win, "imipTentativeButton");
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
partStat: "TENTATIVE",
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests declining an invitation and sending a response.
|
||||
*/
|
||||
add_task(async function testDeclineWithResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/single-event.eml")));
|
||||
clickAction(win, "imipDeclineButton");
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
partStat: "DECLINED",
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests accepting an invitation without sending a response.
|
||||
*/
|
||||
add_task(async function testAcceptWithoutResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/single-event.eml")));
|
||||
await clickMenuAction(win, "imipAcceptButton", "imipAcceptButton_AcceptDontSend");
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
partStat: "ACCEPTED",
|
||||
noReply: true,
|
||||
},
|
||||
event
|
||||
);
|
||||
await calendar.deleteItem(event);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests tentatively accepting an invitation without sending a response.
|
||||
*/
|
||||
add_task(async function testTentativeWithoutResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/single-event.eml")));
|
||||
await clickMenuAction(win, "imipTentativeButton", "imipTentativeButton_TentativeDontSend");
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
partStat: "TENTATIVE",
|
||||
noReply: true,
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests declining an invitation without sending a response.
|
||||
*/
|
||||
add_task(async function testDeclineWithoutResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/single-event.eml")));
|
||||
await clickMenuAction(win, "imipDeclineButton", "imipDeclineButton_DeclineDontSend");
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
partStat: "DECLINED",
|
||||
noReply: true,
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
|
@ -0,0 +1,229 @@
|
|||
/* 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 for receiving recurring event invitations via the imip-bar.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
|
||||
var { CalItipDefaultEmailTransport } = ChromeUtils.import(
|
||||
"resource:///modules/CalItipEmailTransport.jsm"
|
||||
);
|
||||
var { FileUtils } = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
||||
var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
|
||||
|
||||
var { open_message_from_file } = ChromeUtils.import(
|
||||
"resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
|
||||
);
|
||||
var { CalendarTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/calendar/CalendarTestUtils.jsm"
|
||||
);
|
||||
|
||||
let deleteMgr = Cc["@mozilla.org/calendar/deleted-items-manager;1"].getService(Ci.calIDeletedItems)
|
||||
.wrappedJSObject;
|
||||
|
||||
let account;
|
||||
let identity;
|
||||
let calendar;
|
||||
let transport;
|
||||
let getImipTransport = cal.itip.getImipTransport;
|
||||
let markDeleted = deleteMgr.markDeleted;
|
||||
|
||||
let startRange = cal.createDateTime("19990101");
|
||||
let endRange = cal.createDateTime("20400101");
|
||||
|
||||
/**
|
||||
* Initialize account, identity and calendar.
|
||||
*/
|
||||
add_setup(async function() {
|
||||
account = MailServices.accounts.createAccount();
|
||||
account.incomingServer = MailServices.accounts.createIncomingServer(
|
||||
"receiver",
|
||||
"example.com",
|
||||
"imap"
|
||||
);
|
||||
identity = MailServices.accounts.createIdentity();
|
||||
identity.email = "receiver@example.com";
|
||||
account.addIdentity(identity);
|
||||
|
||||
await CalendarTestUtils.setCalendarView(window, "month");
|
||||
window.goToDate(cal.createDateTime("20220316T191602Z"));
|
||||
|
||||
calendar = CalendarTestUtils.createCalendar("Test");
|
||||
transport = new EmailTransport(account, identity);
|
||||
getImipTransport = cal.itip.getImipTransport;
|
||||
cal.itip.getImipTransport = () => transport;
|
||||
markDeleted = deleteMgr.markDeleted;
|
||||
deleteMgr.markDeleted = () => {};
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
MailServices.accounts.removeAccount(account, true);
|
||||
cal.itip.getImipTransport = getImipTransport;
|
||||
deleteMgr.markDeleted = markDeleted;
|
||||
CalendarTestUtils.removeCalendar(calendar);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests accepting an invitation to a recurring event and sending a response.
|
||||
*/
|
||||
add_task(async function testAcceptRecurringWithResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/repeat-event.eml")));
|
||||
clickAction(win, "imipAcceptRecurrencesButton");
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
isRecurring: true,
|
||||
partStat: "ACCEPTED",
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event.parentItem);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests tentatively accepting an invitation to a recurring event and sending a
|
||||
* response.
|
||||
*/
|
||||
add_task(async function testTentativeRecurringWithResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/repeat-event.eml")));
|
||||
clickAction(win, "imipTentativeRecurrencesButton");
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
isRecurring: true,
|
||||
partStat: "TENTATIVE",
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event.parentItem);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests declining an invitation to a recurring event and sending a response.
|
||||
*/
|
||||
add_task(async function testDeclineRecurringWithResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/repeat-event.eml")));
|
||||
clickAction(win, "imipDeclineRecurrencesButton");
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
isRecurring: true,
|
||||
partStat: "DECLINED",
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event.parentItem);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests accepting an invitation to a recurring event without sending a response.
|
||||
*/
|
||||
add_task(async function testAcceptRecurringWithoutResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/repeat-event.eml")));
|
||||
await clickMenuAction(
|
||||
win,
|
||||
"imipAcceptRecurrencesButton",
|
||||
"imipAcceptRecurrencesButton_AcceptDontSend"
|
||||
);
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
isRecurring: true,
|
||||
partStat: "ACCEPTED",
|
||||
noReply: true,
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event.parentItem);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests tentatively accepting an invitation to a recurring event without sending
|
||||
* a response.
|
||||
*/
|
||||
add_task(async function testTentativeRecurringWithoutResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/repeat-event.eml")));
|
||||
await clickMenuAction(
|
||||
win,
|
||||
"imipTentativeRecurrencesButton",
|
||||
"imipTentativeRecurrencesButton_TentativeDontSend"
|
||||
);
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
isRecurring: true,
|
||||
partStat: "TENTATIVE",
|
||||
noReply: true,
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event.parentItem);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests declining an invitation to a recurring event without sending a response.
|
||||
*/
|
||||
add_task(async function testDeclineRecurrencesWithoutResponse() {
|
||||
transport.reset();
|
||||
let win = await openImipMessage(new FileUtils.File(getTestFilePath("data/repeat-event.eml")));
|
||||
await clickMenuAction(
|
||||
win,
|
||||
"imipDeclineRecurrencesButton",
|
||||
"imipDeclineRecurrencesButton_DeclineDontSend"
|
||||
);
|
||||
|
||||
let event = (await CalendarTestUtils.monthView.waitForItemAt(window, 3, 4, 1)).item;
|
||||
await doImipBarActionTest(
|
||||
{
|
||||
calendar,
|
||||
transport,
|
||||
identity,
|
||||
isRecurring: true,
|
||||
partStat: "DECLINED",
|
||||
noReply: true,
|
||||
},
|
||||
event
|
||||
);
|
||||
|
||||
await calendar.deleteItem(event.parentItem);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
|
@ -0,0 +1,49 @@
|
|||
MIME-Version: 1.0
|
||||
Date: Mon, 28 Mar 2022 17:49:35 +0000
|
||||
Subject: Invitation: Repeat Event @ Daily from 2pm to 3pm 3 times (AST) (receiver@example.com)
|
||||
From: sender@example.com
|
||||
To: receiver@example.com
|
||||
Content-Type: multipart/mixed; boundary="00000000000080f3db05db4aef5b"
|
||||
|
||||
--00000000000080f3db05db4aef5b
|
||||
Content-Type: multipart/alternative; boundary="00000000000080f3da05db4aef59"
|
||||
|
||||
--00000000000080f3da05db4aef59
|
||||
Content-Type: text/calendar; charset="UTF-8"; method=REQUEST
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
BEGIN:VCALENDAR
|
||||
METHOD:REQUEST
|
||||
BEGIN:VEVENT
|
||||
DTSTART:20220316T110000Z
|
||||
DTEND:20220316T113000Z
|
||||
RRULE:FREQ=DAILY;WKST=SU;COUNT=3;INTERVAL=1
|
||||
DTSTAMP:20220316T191602Z
|
||||
UID:02e79b96
|
||||
ORGANIZER;CN=Sender;
|
||||
EMAIL=sender@example.com:mailto:sender@example.com
|
||||
ATTENDEE;CN=Sender;
|
||||
EMAIL=sender@example.com;CUTYPE=INDIVIDUAL;
|
||||
PARTSTAT=ACCEPTED;RSVP=FALSE:mailto:sender@example.com
|
||||
ATTENDEE;CN=Receiver;EMAIL=receiver@example.com;CUTYPE=INDIVIDUAL;
|
||||
PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:receiver@example.com
|
||||
ATTENDEE;CN=Other;EMAIL=other@example.com;CUTYPE=INDIVIDUAL;
|
||||
PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:other@example.com
|
||||
CREATED:20220328T174934Z
|
||||
LAST-MODIFIED:20220328T174934Z
|
||||
LOCATION:Somewhere
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
SUMMARY:Repeat Event
|
||||
DESCRIPTION:An event invitation.
|
||||
TRANSP:OPAQUE
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER:-P1D
|
||||
DESCRIPTION:This is an event reminder
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
|
||||
--00000000000080f3da05db4aef59--
|
||||
--00000000000080f3db05db4aef5b--
|
|
@ -0,0 +1,78 @@
|
|||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: binary
|
||||
Content-Type: multipart/mixed; boundary="_----------=_1647458162153312762582"
|
||||
Date: Wed, 16 Mar 2022 15:16:02 -0400
|
||||
To: receiver@example.com
|
||||
Subject: Invitation: Single Event @ Wed, Mar 16 2022 11:00 AST
|
||||
From: Sender <sender@example.com>
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
|
||||
--_----------=_1647458162153312762582
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: binary
|
||||
Content-Type: multipart/alternative; boundary="_----------=_1647458162153312762583"
|
||||
Date: Wed, 16 Mar 2022 15:16:02 -0400
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
|
||||
--_----------=_1647458162153312762583
|
||||
MIME-Version: 1.0
|
||||
Content-Disposition: inline
|
||||
Content-Length: 227
|
||||
Content-Transfer-Encoding: binary
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
Date: Wed, 16 Mar 2022 15:16:02 -0400
|
||||
|
||||
Single Event
|
||||
|
||||
When:
|
||||
Wed, Mar 16 2022
|
||||
11:00 - 12:00 AST
|
||||
Where:
|
||||
Somewhere
|
||||
|
||||
--_----------=_1647458162153312762583
|
||||
MIME-Version: 1.0
|
||||
Content-Disposition: inline
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/calendar; charset="utf-8"; method="REQUEST"
|
||||
Date: Wed, 16 Mar 2022 15:16:02 -0400
|
||||
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
METHOD:REQUEST
|
||||
CALSCALE:GREGORIAN
|
||||
BEGIN:VEVENT
|
||||
UID:b0c0b197
|
||||
SEQUENCE:0
|
||||
DTSTAMP:20220316T191602Z
|
||||
CREATED:20220316T191532Z
|
||||
DTSTART:20220316T110000Z
|
||||
DTEND:20220316T113000Z
|
||||
DURATION:PT1H
|
||||
PRIORITY:0
|
||||
SUMMARY:Single Event
|
||||
DESCRIPTION:An event invitation.
|
||||
LOCATION:Somewhere
|
||||
STATUS:CONFIRMED
|
||||
TRANSP:OPAQUE
|
||||
CLASS:PUBLIC
|
||||
ORGANIZER;CN=3DSender;
|
||||
EMAIL=3Dsender@example.com:mailto:sender@example.com
|
||||
ATTENDEE;CN=3DSender;
|
||||
EMAIL=3Dsender@example.com;CUTYPE=3DINDIVIDUAL;
|
||||
PARTSTAT=3DACCEPTED;RSVP=3DFALSE:mailto:sender@example.com
|
||||
ATTENDEE;CN=Receiver;EMAIL=3Dreceiver@example.com;CUTYPE=3DINDIVIDUAL;
|
||||
PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailto:receiver@example.com
|
||||
ATTENDEE;CN=Other;EMAIL=other@example.com;CUTYPE=3DINDIVIDUAL;
|
||||
PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailto:other@example.com
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER:-P1D
|
||||
DESCRIPTION:This is an event reminder
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
|
||||
--_----------=_1647458162153312762583--
|
|
@ -0,0 +1,260 @@
|
|||
/* 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/. */
|
||||
|
||||
/**
|
||||
* Common functions for the imip-bar tests.
|
||||
*
|
||||
* Note that these tests are heavily tied to the properties of single-event.eml
|
||||
* and repeat-event.eml.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
|
||||
var { CalItipDefaultEmailTransport } = ChromeUtils.import(
|
||||
"resource:///modules/CalItipEmailTransport.jsm"
|
||||
);
|
||||
var { FileUtils } = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
||||
var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
|
||||
|
||||
var { open_message_from_file } = ChromeUtils.import(
|
||||
"resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
|
||||
);
|
||||
var { CalendarTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/calendar/CalendarTestUtils.jsm"
|
||||
);
|
||||
|
||||
class EmailTransport extends CalItipDefaultEmailTransport {
|
||||
sentItems = [];
|
||||
|
||||
sentMsgs = [];
|
||||
|
||||
getMsgSend() {
|
||||
let { sentMsgs } = this;
|
||||
return {
|
||||
sendMessageFile(
|
||||
userIdentity,
|
||||
accountKey,
|
||||
composeFields,
|
||||
messageFile,
|
||||
deleteSendFileOnCompletion,
|
||||
digest,
|
||||
deliverMode,
|
||||
msgToReplace,
|
||||
listener,
|
||||
statusFeedback,
|
||||
smtpPassword
|
||||
) {
|
||||
sentMsgs.push({
|
||||
userIdentity,
|
||||
accountKey,
|
||||
composeFields,
|
||||
messageFile,
|
||||
deleteSendFileOnCompletion,
|
||||
digest,
|
||||
deliverMode,
|
||||
msgToReplace,
|
||||
listener,
|
||||
statusFeedback,
|
||||
smtpPassword,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
sendItems(recipients, itipItem, fromAttendee) {
|
||||
this.sentItems.push({ recipients, itipItem, fromAttendee });
|
||||
return super.sendItems(recipients, itipItem, fromAttendee);
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.sentItems = [];
|
||||
this.sentMsgs = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an iMIP message file and waits for the imip-bar to appear.
|
||||
*
|
||||
* @param {nsIFile} file
|
||||
* @return {Window}
|
||||
*/
|
||||
async function openImipMessage(file) {
|
||||
let { window: win } = await open_message_from_file(file);
|
||||
let imipBar = win.document.getElementById("imip-bar");
|
||||
await TestUtils.waitForCondition(() => !imipBar.collapsed, "imip-bar shown");
|
||||
return win;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on one of the imip-bar action buttons.
|
||||
*
|
||||
* @param {Window} win
|
||||
* @param {string} id
|
||||
*/
|
||||
function clickAction(win, id) {
|
||||
let action = win.document.getElementById(id);
|
||||
Assert.ok(!action.hidden, `"#${id}" shown"`);
|
||||
EventUtils.synthesizeMouseAtCenter(action, {}, win);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on one of the imip-bar actions from a dropdown menu.
|
||||
*
|
||||
* @param {Window} win The window the imip message is opened in.
|
||||
* @param {string} buttonId The id of the <toolbarbutton> containing the menu.
|
||||
* @param {string} actionId The id of the menu item to click.
|
||||
*/
|
||||
async function clickMenuAction(win, buttonId, actionId) {
|
||||
let actionButton = win.document.getElementById(buttonId);
|
||||
Assert.ok(!actionButton.hidden, `"${buttonId}" shown`);
|
||||
|
||||
let actionMenu = actionButton.querySelector("menupopup");
|
||||
let menuShown = BrowserTestUtils.waitForEvent(actionMenu, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(actionButton.querySelector("dropmarker"), {}, win);
|
||||
await menuShown;
|
||||
EventUtils.synthesizeMouseAtCenter(win.document.getElementById(actionId), {}, win);
|
||||
}
|
||||
|
||||
const unpromotedProps = ["location", "description", "sequence", "x-moz-received-dtstamp"];
|
||||
|
||||
/**
|
||||
* An object where the keys are paths and the values the values they lead to
|
||||
* in an object we want to test for correctness.
|
||||
* @typedef {Object} Comparable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compares the paths specified in the expected object against the provided
|
||||
* actual object.
|
||||
*
|
||||
* @param {object} actual This is expected to be a calIEvent or calIAttendee but
|
||||
* can also be an array of both etc.
|
||||
* @param {Comparable} expected
|
||||
*/
|
||||
function compareProperties(actual, expected, prefix = "") {
|
||||
Assert.equal(typeof actual, "object", `${prefix || "provided value"} is an object`);
|
||||
for (let [key, value] of Object.entries(expected)) {
|
||||
if (key.includes(".")) {
|
||||
let keys = key.split(".");
|
||||
let head = keys[0];
|
||||
let tail = keys.slice(1).join(".");
|
||||
compareProperties(actual[head], { [tail]: value }, [prefix, head].filter(k => k).join("."));
|
||||
continue;
|
||||
}
|
||||
|
||||
let path = [prefix, key].filter(k => k).join(".");
|
||||
let actualValue = unpromotedProps.includes(key) ? actual.getProperty(key) : actual[key];
|
||||
Assert.equal(actualValue, value, `property "${path}" is "${value}"`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ImipBarActionTestConf
|
||||
*
|
||||
* @property {calICalendar} calendar The calendar used for the test.
|
||||
* @property {calIItipTranport} transport The transport used for the test.
|
||||
* @property {nsIIdentity} identity The identity expected to be used to
|
||||
* send the reply.
|
||||
* @property {string} partStat The participationStatus of the receiving user to
|
||||
* expect.
|
||||
* @property {boolean} noReply If true, do not expect an attempt to send a reply.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test the properties of an event created from the imip-bar and optionally, the
|
||||
* attempt to send a reply.
|
||||
*
|
||||
* @param {ImipBarActionTestConf} conf
|
||||
* @param {calIEvent|calIEvent[]} item
|
||||
*/
|
||||
async function doImipBarActionTest(conf, event) {
|
||||
let { calendar, transport, identity, partStat, isRecurring, noReply } = conf;
|
||||
let title = isRecurring ? "Repeat Event" : "Single Event";
|
||||
let events = [event];
|
||||
let startDates = ["20220316T110000Z"];
|
||||
let endDates = ["20220316T113000Z"];
|
||||
|
||||
if (isRecurring) {
|
||||
startDates = [...startDates, "20220317T110000Z", "20220318T110000Z"];
|
||||
endDates = [...endDates, "20220317T113000Z", "20220318T113000Z"];
|
||||
events = event.parentItem.recurrenceInfo.getOccurrences(
|
||||
cal.createDateTime("19700101"),
|
||||
cal.createDateTime("30000101"),
|
||||
Infinity
|
||||
);
|
||||
Assert.equal(events.length, 3, "reccurring event has 3 occurrences");
|
||||
}
|
||||
|
||||
info("Verifying relevant properties of each event occurrence");
|
||||
for (let [index, occurrence] of events.entries()) {
|
||||
compareProperties(occurrence, {
|
||||
title,
|
||||
"calendar.name": calendar.name,
|
||||
"startDate.icalString": startDates[index],
|
||||
"endDate.icalString": endDates[index],
|
||||
description: "An event invitation.",
|
||||
location: "Somewhere",
|
||||
sequence: "0",
|
||||
"x-moz-received-dtstamp": "20220316T191602Z",
|
||||
"organizer.id": "mailto:sender@example.com",
|
||||
status: "CONFIRMED",
|
||||
});
|
||||
|
||||
// Alarms should be ignored.
|
||||
Assert.equal(
|
||||
occurrence.getAlarms().length,
|
||||
0,
|
||||
`${isRecurring ? "occurrence" : "event"} has no reminders`
|
||||
);
|
||||
|
||||
info("Verifying attendee list and participation status");
|
||||
let attendees = occurrence.getAttendees();
|
||||
compareProperties(attendees, {
|
||||
"0.id": "mailto:sender@example.com",
|
||||
"0.participationStatus": "ACCEPTED",
|
||||
"1.participationStatus": partStat,
|
||||
"1.id": "mailto:receiver@example.com",
|
||||
"2.id": "mailto:other@example.com",
|
||||
"2.participationStatus": "NEEDS-ACTION",
|
||||
});
|
||||
}
|
||||
|
||||
if (noReply) {
|
||||
Assert.equal(
|
||||
transport.sentItems.length,
|
||||
0,
|
||||
"itip subsystem did not attempt to send a response"
|
||||
);
|
||||
Assert.equal(transport.sentMsgs.length, 0, "no call was made into the mail subsystem");
|
||||
} else {
|
||||
info("Verifying the attempt to send a response uses the correct data");
|
||||
Assert.equal(transport.sentItems.length, 1, "itip subsystem attempted to send a response");
|
||||
compareProperties(transport.sentItems[0], {
|
||||
"recipients.0.id": "mailto:sender@example.com",
|
||||
"itipItem.responseMethod": "REPLY",
|
||||
"fromAttendee.id": "mailto:receiver@example.com",
|
||||
"fromAttendee.participationStatus": partStat,
|
||||
});
|
||||
|
||||
// The itipItem is used to generate the iTIP data in the message body.
|
||||
info("Verifying the reply calItipItem attendee list");
|
||||
let replyItem = transport.sentItems[0].itipItem.getItemList()[0];
|
||||
let replyAttendees = replyItem.getAttendees();
|
||||
Assert.equal(replyAttendees.length, 1, "reply has one attendee");
|
||||
compareProperties(replyAttendees[0], {
|
||||
id: "mailto:receiver@example.com",
|
||||
participationStatus: partStat,
|
||||
});
|
||||
|
||||
info("Verifying the call to the message subsystem");
|
||||
Assert.equal(transport.sentMsgs.length, 1, "transport sent 1 message");
|
||||
compareProperties(transport.sentMsgs[0], {
|
||||
userIdentity: identity,
|
||||
"composeFields.from": "receiver@example.com",
|
||||
"composeFields.to": "Sender <sender@example.com>",
|
||||
});
|
||||
Assert.ok(transport.sentMsgs[0].messageFile.exists(), "message file was created");
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче