summaryrefslogtreecommitdiffstats
path: root/comm/calendar/test/browser/views
diff options
context:
space:
mode:
Diffstat (limited to 'comm/calendar/test/browser/views')
-rw-r--r--comm/calendar/test/browser/views/browser.ini32
-rw-r--r--comm/calendar/test/browser/views/browser_dayView.js185
-rw-r--r--comm/calendar/test/browser/views/browser_monthView.js86
-rw-r--r--comm/calendar/test/browser/views/browser_multiweekView.js88
-rw-r--r--comm/calendar/test/browser/views/browser_propertyChanges.js248
-rw-r--r--comm/calendar/test/browser/views/browser_taskView.js148
-rw-r--r--comm/calendar/test/browser/views/browser_viewSwitch.js138
-rw-r--r--comm/calendar/test/browser/views/browser_weekView.js81
-rw-r--r--comm/calendar/test/browser/views/head.js13
9 files changed, 1019 insertions, 0 deletions
diff --git a/comm/calendar/test/browser/views/browser.ini b/comm/calendar/test/browser/views/browser.ini
new file mode 100644
index 0000000000..0aae8af9d0
--- /dev/null
+++ b/comm/calendar/test/browser/views/browser.ini
@@ -0,0 +1,32 @@
+[default]
+head = head.js
+prefs =
+ calendar.item.promptDelete=false
+ calendar.timezone.local=UTC
+ calendar.timezone.useSystemTimezone=false
+ # Default start of the week Thursday to make sure calendar isn't relying on
+ # built-in assumptions of week start.
+ calendar.week.start=4
+ # Default Sunday to "not a weekend" and Wednesday to "weekend" to make sure
+ # calendar isn't relying on built-in assumptions of work days.
+ calendar.week.d0sundaysoff=false
+ calendar.week.d3wednesdaysoff=true
+ # Default work hours to be from 3:00 to 12:00 to make sure calendar isn't
+ # relying on built-in assumptions of work hours.
+ calendar.view.daystarthour=3
+ calendar.view.dayendhour=12
+ calendar.view.visiblehours=3
+ mail.provider.suppress_dialog_on_startup=true
+ mail.spotlight.firstRunDone=true
+ mail.winsearch.firstRunDone=true
+ mailnews.start_page.override_url=about:blank
+ mailnews.start_page.url=about:blank
+subsuite = thunderbird
+
+[browser_dayView.js]
+[browser_monthView.js]
+[browser_multiweekView.js]
+[browser_propertyChanges.js]
+[browser_taskView.js]
+[browser_viewSwitch.js]
+[browser_weekView.js]
diff --git a/comm/calendar/test/browser/views/browser_dayView.js b/comm/calendar/test/browser/views/browser_dayView.js
new file mode 100644
index 0000000000..ba68a85eea
--- /dev/null
+++ b/comm/calendar/test/browser/views/browser_dayView.js
@@ -0,0 +1,185 @@
+/* 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/. */
+
+var { formatDate, formatTime, saveAndCloseItemDialog, setData } = ChromeUtils.import(
+ "resource://testing-common/calendar/ItemEditingHelpers.jsm"
+);
+
+var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
+
+const TITLE1 = "Day View Event";
+const TITLE2 = "Day View Event Changed";
+const DESC = "Day View Event Description";
+
+add_setup(async function () {
+ let calendar = CalendarTestUtils.createCalendar();
+ registerCleanupFunction(() => {
+ CalendarTestUtils.removeCalendar(calendar);
+ });
+
+ await CalendarTestUtils.setCalendarView(window, "day");
+});
+
+add_task(async function testDayView() {
+ await CalendarTestUtils.goToDate(window, 2009, 1, 1);
+
+ let dayView = document.getElementById("day-view");
+ // Verify date in view.
+ await TestUtils.waitForCondition(
+ () => dayView.dayColumns[0]?.date.icalString == "20090101",
+ "Inspecting the date"
+ );
+
+ // Create event at 8 AM.
+ let eventBox = CalendarTestUtils.dayView.getHourBoxAt(window, 8);
+ let { dialogWindow, iframeWindow, iframeDocument } = await CalendarTestUtils.editNewEvent(
+ window,
+ eventBox
+ );
+
+ // Check that the start time is correct.
+ let someDate = cal.createDateTime();
+ someDate.resetTo(2009, 0, 1, 8, 0, 0, cal.dtz.UTC);
+
+ let startPicker = iframeDocument.getElementById("event-starttime");
+ Assert.equal(startPicker._datepicker._inputField.value, formatDate(someDate));
+ Assert.equal(startPicker._timepicker._inputField.value, formatTime(someDate));
+
+ // Fill in title, description and calendar.
+ await setData(dialogWindow, iframeWindow, {
+ title: TITLE1,
+ description: DESC,
+ calendar: "Test",
+ });
+
+ await saveAndCloseItemDialog(dialogWindow);
+
+ // If it was created successfully, it can be opened.
+ ({ dialogWindow, iframeWindow } = await CalendarTestUtils.dayView.editEventAt(window, 1));
+ await setData(dialogWindow, iframeWindow, { title: TITLE2 });
+ await saveAndCloseItemDialog(dialogWindow);
+
+ // Check if name was saved.
+ await TestUtils.waitForCondition(() => {
+ eventBox = CalendarTestUtils.dayView.getEventBoxAt(window, 1);
+ if (!eventBox) {
+ return false;
+ }
+
+ let eventName = eventBox.querySelector(".event-name-label");
+ return eventName.textContent == TITLE2;
+ }, "event was modified in the view");
+
+ // Delete event
+ EventUtils.synthesizeMouseAtCenter(eventBox, {}, window);
+ eventBox.focus();
+ EventUtils.synthesizeKey("VK_DELETE", {}, window);
+ await CalendarTestUtils.dayView.waitForNoEventBoxAt(window, 1);
+
+ Assert.ok(true, "Test ran to completion");
+});
+
+add_task(async function testDayViewDateLabel() {
+ await CalendarTestUtils.goToDate(window, 2022, 4, 13);
+
+ let heading = CalendarTestUtils.dayView.getColumnHeading(window);
+ let labelSpan = heading.querySelector("span:not([hidden])");
+
+ Assert.equal(
+ labelSpan.textContent,
+ "Wednesday Apr 13",
+ "the date label should contain the displayed date in a human-readable string"
+ );
+});
+
+add_task(async function testDayViewCurrentDayHighlight() {
+ // Sanity check that this date (which should be in the past) is not today's
+ // date.
+ let today = new Date();
+ Assert.ok(today.getUTCFullYear() != 2022 || today.getUTCMonth() != 3 || today.getUTCDate() != 13);
+
+ // When displaying days which are not the current day, there should be no
+ // highlight.
+ await CalendarTestUtils.goToDate(window, 2022, 4, 13);
+
+ let container = CalendarTestUtils.dayView.getColumnContainer(window);
+ Assert.ok(
+ !container.classList.contains("day-column-today"),
+ "the displayed date should not be highlighted if it is not the current day"
+ );
+
+ // When displaying the current day, it should be highlighted.
+ await CalendarTestUtils.goToToday(window);
+
+ container = CalendarTestUtils.dayView.getColumnContainer(window);
+ Assert.ok(
+ container.classList.contains("day-column-today"),
+ "the displayed date should be highlighted if it is the current day"
+ );
+});
+
+add_task(async function testDayViewWorkDayHighlight() {
+ // The test configuration sets Sunday to be a work day, so it should not have
+ // the weekend background.
+ await CalendarTestUtils.goToDate(window, 2022, 4, 10);
+
+ let container = CalendarTestUtils.dayView.getColumnContainer(window);
+ Assert.ok(
+ !container.classList.contains("day-column-weekend"),
+ "the displayed date should not be highlighted if it is a work day"
+ );
+
+ await CalendarTestUtils.goToDate(window, 2022, 4, 13);
+
+ container = CalendarTestUtils.dayView.getColumnContainer(window);
+ Assert.ok(
+ container.classList.contains("day-column-weekend"),
+ "the displayed date should be highlighted if it is not a work day"
+ );
+});
+
+add_task(async function testDayViewNavbar() {
+ await CalendarTestUtils.goToDate(window, 2022, 4, 13);
+
+ let intervalDescription = CalendarTestUtils.getNavBarIntervalDescription(window);
+ Assert.equal(
+ intervalDescription.textContent,
+ "Wednesday, April 13, 2022",
+ "interval description should contain a description of the displayed date"
+ );
+
+ // Note that the value 14 here tests calculation of the calendar week based on
+ // the starting day of the week; if the calculation built in an assumption of
+ // Sunday or Monday as the starting day of the week, we would get 15 here.
+ let calendarWeek = CalendarTestUtils.getNavBarCalendarWeekBox(window);
+ Assert.equal(
+ calendarWeek.textContent,
+ "CW: 14",
+ "calendar week label should contain an indicator of which week contains displayed date"
+ );
+});
+
+add_task(async function testDayViewTodayButton() {
+ // Though this code is cribbed from the CalendarTestUtils, it should be
+ // duplicated in case the utility implementation changes.
+ let todayButton = CalendarTestUtils.getNavBarTodayButton(window);
+
+ EventUtils.synthesizeMouseAtCenter(todayButton, {}, window);
+ await CalendarTestUtils.ensureViewLoaded(window);
+
+ let displayedDate = CalendarTestUtils.dayView.getEventColumn(window).date;
+
+ let today = new Date();
+ Assert.equal(
+ displayedDate.year,
+ today.getUTCFullYear(),
+ "year of displayed date should be this year"
+ );
+ Assert.equal(
+ displayedDate.month,
+ today.getUTCMonth(),
+ "month of displayed date should be this month"
+ );
+ Assert.equal(displayedDate.day, today.getUTCDate(), "day of displayed date should be today");
+});
diff --git a/comm/calendar/test/browser/views/browser_monthView.js b/comm/calendar/test/browser/views/browser_monthView.js
new file mode 100644
index 0000000000..f3a385a3f5
--- /dev/null
+++ b/comm/calendar/test/browser/views/browser_monthView.js
@@ -0,0 +1,86 @@
+/* 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/. */
+
+var { formatDate, formatTime, saveAndCloseItemDialog, setData } = ChromeUtils.import(
+ "resource://testing-common/calendar/ItemEditingHelpers.jsm"
+);
+
+var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
+
+const TITLE1 = "Month View Event";
+const TITLE2 = "Month View Event Changed";
+const DESC = "Month View Event Description";
+
+add_task(async function testMonthView() {
+ let calendar = CalendarTestUtils.createCalendar();
+ registerCleanupFunction(() => {
+ CalendarTestUtils.removeCalendar(calendar);
+ });
+
+ await CalendarTestUtils.setCalendarView(window, "month");
+ await CalendarTestUtils.goToDate(window, 2009, 1, 1);
+
+ // Verify date.
+ await TestUtils.waitForCondition(() => {
+ let dateLabel = document.querySelector(
+ '#month-view td[selected="true"] > calendar-month-day-box'
+ );
+ return dateLabel && dateLabel.mDate.icalString == "20090101";
+ }, "Inspecting the date");
+
+ // Create event.
+ // Thursday of 2009-01-05 should be the selected box in the first row with default settings.
+ let hour = new Date().getUTCHours(); // Remember time at click.
+ let eventBox = CalendarTestUtils.monthView.getDayBox(window, 1, 5);
+ let { dialogWindow, iframeWindow, iframeDocument } = await CalendarTestUtils.editNewEvent(
+ window,
+ eventBox
+ );
+
+ // Check that the start time is correct.
+ // Next full hour except last hour hour of the day.
+ let nextHour = hour == 23 ? hour : (hour + 1) % 24;
+ let someDate = cal.dtz.now();
+ someDate.resetTo(2009, 0, 5, nextHour, 0, 0, cal.dtz.UTC);
+
+ let startPicker = iframeDocument.getElementById("event-starttime");
+ Assert.equal(startPicker._datepicker._inputField.value, formatDate(someDate));
+ Assert.equal(startPicker._timepicker._inputField.value, formatTime(someDate));
+
+ // Fill in title, description and calendar.
+ await setData(dialogWindow, iframeWindow, {
+ title: TITLE1,
+ description: DESC,
+ calendar: "Test",
+ });
+
+ await saveAndCloseItemDialog(dialogWindow);
+
+ // If it was created successfully, it can be opened.
+ ({ dialogWindow, iframeWindow } = await CalendarTestUtils.monthView.editItemAt(window, 1, 5, 1));
+ // Change title and save changes.
+ await setData(dialogWindow, iframeWindow, { title: TITLE2 });
+ await saveAndCloseItemDialog(dialogWindow);
+
+ // Check if name was saved.
+ let eventName;
+ await TestUtils.waitForCondition(() => {
+ eventBox = CalendarTestUtils.monthView.getItemAt(window, 1, 5, 1);
+ if (!eventBox) {
+ return false;
+ }
+ eventName = eventBox.querySelector(".event-name-label").textContent;
+ return eventName == TITLE2;
+ }, "event name did not update in time");
+
+ Assert.equal(eventName, TITLE2);
+
+ // Delete event.
+ EventUtils.synthesizeMouseAtCenter(eventBox, {}, window);
+ eventBox.focus();
+ EventUtils.synthesizeKey("VK_DELETE", {}, window);
+ await CalendarTestUtils.monthView.waitForNoItemAt(window, 1, 5, 1);
+
+ Assert.ok(true, "Test ran to completion");
+});
diff --git a/comm/calendar/test/browser/views/browser_multiweekView.js b/comm/calendar/test/browser/views/browser_multiweekView.js
new file mode 100644
index 0000000000..feb8fcd3ec
--- /dev/null
+++ b/comm/calendar/test/browser/views/browser_multiweekView.js
@@ -0,0 +1,88 @@
+/* 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/. */
+
+var { formatDate, formatTime, saveAndCloseItemDialog, setData } = ChromeUtils.import(
+ "resource://testing-common/calendar/ItemEditingHelpers.jsm"
+);
+
+var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
+
+const TITLE1 = "Multiweek View Event";
+const TITLE2 = "Multiweek View Event Changed";
+const DESC = "Multiweek View Event Description";
+
+add_task(async function () {
+ let calendar = CalendarTestUtils.createCalendar();
+ registerCleanupFunction(() => {
+ CalendarTestUtils.removeCalendar(calendar);
+ });
+
+ await CalendarTestUtils.setCalendarView(window, "multiweek");
+ await CalendarTestUtils.goToDate(window, 2009, 1, 1);
+
+ // Verify date.
+ await TestUtils.waitForCondition(() => {
+ let dateLabel = document.querySelector(
+ '#multiweek-view td[selected="true"] > calendar-month-day-box'
+ );
+ return dateLabel && dateLabel.mDate.icalString == "20090101";
+ }, "Inspecting the date");
+
+ // Create event.
+ // Thursday of 2009-01-05 should be the selected box in the first row with default settings.
+ let hour = new Date().getUTCHours(); // Remember time at click.
+ let eventBox = CalendarTestUtils.multiweekView.getDayBox(window, 1, 5);
+ let { dialogWindow, iframeWindow, iframeDocument } = await CalendarTestUtils.editNewEvent(
+ window,
+ eventBox
+ );
+
+ // Check that the start time is correct.
+ // Next full hour except last hour hour of the day.
+ let nextHour = hour == 23 ? hour : (hour + 1) % 24;
+ let someDate = cal.dtz.now();
+ someDate.resetTo(2009, 0, 5, nextHour, 0, 0, cal.dtz.UTC);
+
+ let startPicker = iframeDocument.getElementById("event-starttime");
+ Assert.equal(startPicker._datepicker._inputField.value, formatDate(someDate));
+ Assert.equal(startPicker._timepicker._inputField.value, formatTime(someDate));
+
+ // Fill in title, description and calendar.
+ await setData(dialogWindow, iframeWindow, {
+ title: TITLE1,
+ description: DESC,
+ calendar: "Test",
+ });
+
+ await saveAndCloseItemDialog(dialogWindow);
+
+ // If it was created successfully, it can be opened.
+ ({ dialogWindow, iframeWindow } = await CalendarTestUtils.multiweekView.editItemAt(
+ window,
+ 1,
+ 5,
+ 1
+ ));
+ // Change title and save changes.
+ await setData(dialogWindow, iframeWindow, { title: TITLE2 });
+ await saveAndCloseItemDialog(dialogWindow);
+
+ // Check if name was saved.
+ await TestUtils.waitForCondition(() => {
+ eventBox = CalendarTestUtils.multiweekView.getItemAt(window, 1, 5, 1);
+ if (eventBox === null) {
+ return false;
+ }
+ let eventName = eventBox.querySelector(".event-name-label");
+ return eventName && eventName.textContent == TITLE2;
+ }, "Wait for the new title");
+
+ // Delete event.
+ EventUtils.synthesizeMouseAtCenter(eventBox, {}, window);
+ eventBox.focus();
+ EventUtils.synthesizeKey("VK_DELETE", {}, window);
+ await CalendarTestUtils.multiweekView.waitForNoItemAt(window, 1, 5, 1);
+
+ Assert.ok(true, "Test ran to completion");
+});
diff --git a/comm/calendar/test/browser/views/browser_propertyChanges.js b/comm/calendar/test/browser/views/browser_propertyChanges.js
new file mode 100644
index 0000000000..79848a0e73
--- /dev/null
+++ b/comm/calendar/test/browser/views/browser_propertyChanges.js
@@ -0,0 +1,248 @@
+/* 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 that changes in a calendar's properties are reflected in the current view. */
+
+const { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
+const { CalEvent } = ChromeUtils.import("resource:///modules/CalEvent.jsm");
+
+let composite = cal.view.getCompositeCalendar(window);
+
+// This is the calendar we're going to change the properties of.
+let thisCalendar = CalendarTestUtils.createCalendar("This Calendar", "memory");
+thisCalendar.setProperty("color", "#ffee22");
+
+// This calendar isn't going to change, and we'll check it doesn't.
+let notThisCalendar = CalendarTestUtils.createCalendar("Not This Calendar", "memory");
+notThisCalendar.setProperty("color", "#dd3333");
+
+add_setup(async function () {
+ let { dedent } = CalendarTestUtils;
+ await thisCalendar.addItem(
+ new CalEvent(dedent`
+ BEGIN:VEVENT
+ SUMMARY:This Event 1
+ DTSTART;VALUE=DATE:20160205
+ DTEND;VALUE=DATE:20160206
+ END:VEVENT
+ `)
+ );
+ await thisCalendar.addItem(
+ new CalEvent(dedent`
+ BEGIN:VEVENT
+ SUMMARY:This Event 2
+ DTSTART:20160205T130000Z
+ DTEND:20160205T150000Z
+ END:VEVENT
+ `)
+ );
+ await thisCalendar.addItem(
+ new CalEvent(dedent`
+ BEGIN:VEVENT
+ SUMMARY:This Event 3
+ DTSTART;VALUE=DATE:20160208
+ DTEND;VALUE=DATE:20160209
+ RRULE:FREQ=DAILY;INTERVAL=2;COUNT=3
+ END:VEVENT
+ `)
+ );
+
+ await notThisCalendar.addItem(
+ new CalEvent(dedent`
+ BEGIN:VEVENT
+ SUMMARY:Not This Event 1
+ DTSTART;VALUE=DATE:20160205
+ DTEND;VALUE=DATE:20160207
+ END:VEVENT
+ `)
+ );
+ await notThisCalendar.addItem(
+ new CalEvent(dedent`
+ BEGIN:VEVENT
+ SUMMARY:Not This Event 2
+ DTSTART:20160205T140000Z
+ DTEND:20160205T170000Z
+ END:VEVENT
+ `)
+ );
+});
+
+/**
+ * Assert whether the given event box is draggable (editable).
+ *
+ * @param {MozCalendarEventBox} eventBox - The event box to test.
+ * @param {boolean} draggable - Whether we expect it to be draggable.
+ * @param {string} message - A message for assertions.
+ */
+async function assertCanDrag(eventBox, draggable, message) {
+ // Hover to see if the drag gripbars appear.
+ let enterPromise = BrowserTestUtils.waitForEvent(eventBox, "mouseenter");
+ EventUtils.synthesizeMouseAtCenter(eventBox, { type: "mouseover" }, window);
+ await enterPromise;
+ Assert.equal(
+ BrowserTestUtils.is_visible(eventBox.startGripbar),
+ draggable,
+ `Start gripbar should be ${draggable ? "visible" : "hidden"} on hover: ${message}`
+ );
+ Assert.equal(
+ BrowserTestUtils.is_visible(eventBox.endGripbar),
+ draggable,
+ `End gripbar should be ${draggable ? "visible" : "hidden"} on hover: ${message}`
+ );
+}
+
+/**
+ * Assert whether the given event element is editable.
+ *
+ * @param {Element} eventElement - The event element to test.
+ * @param {boolean} editable - Whether we expect it to be editable.
+ * @param {string} message - A message for assertions.
+ */
+async function assertEditable(eventElement, editable, message) {
+ // FIXME: Have more ways to test if an event is editable (e.g. test the
+ // context menu)
+ if (eventElement.matches("calendar-event-box")) {
+ await CalendarTestUtils.assertEventBoxDraggable(eventElement, editable, editable, message);
+ }
+}
+
+async function subTest(viewName, boxSelector, thisBoxCount, notThisBoxCount) {
+ async function makeChangeWithReload(changeFunction) {
+ await changeFunction();
+ await CalendarTestUtils.ensureViewLoaded(window);
+ }
+
+ async function checkBoxItems(expectedCount, checkFunction) {
+ await TestUtils.waitForCondition(
+ () => view.querySelectorAll(boxSelector).length == expectedCount,
+ "waiting for the correct number of boxes to be displayed"
+ );
+ let boxItems = view.querySelectorAll(boxSelector);
+
+ if (!checkFunction) {
+ return;
+ }
+
+ for (let boxItem of boxItems) {
+ // TODO: why is it named `item` in some places and `occurrence` elsewhere?
+ let isThisCalendar =
+ (boxItem.item && boxItem.item.calendar == thisCalendar) ||
+ boxItem.occurrence.calendar == thisCalendar;
+ await checkFunction(boxItem, isThisCalendar);
+ }
+ }
+
+ let view = document.getElementById(`${viewName}-view`);
+
+ await CalendarTestUtils.setCalendarView(window, viewName);
+ await CalendarTestUtils.goToDate(window, 2016, 2, 5);
+
+ info("Check initial state.");
+
+ await checkBoxItems(thisBoxCount + notThisBoxCount, async (boxItem, isThisCalendar) => {
+ let style = getComputedStyle(boxItem);
+
+ if (isThisCalendar) {
+ Assert.equal(style.backgroundColor, "rgb(255, 238, 34)", "item background correct");
+ Assert.equal(style.color, "rgb(34, 34, 34)", "item foreground correct");
+ } else {
+ Assert.equal(
+ style.backgroundColor,
+ "rgb(221, 51, 51)",
+ "item background correct (not target calendar)"
+ );
+ Assert.equal(
+ style.color,
+ "rgb(255, 255, 255)",
+ "item foreground correct (not target calendar)"
+ );
+ }
+ await assertEditable(boxItem, true, "Initial event");
+ });
+
+ info("Change color.");
+
+ thisCalendar.setProperty("color", "#16a765");
+ await checkBoxItems(thisBoxCount + notThisBoxCount, async (boxItem, isThisCalendar) => {
+ let style = getComputedStyle(boxItem);
+
+ if (isThisCalendar) {
+ Assert.equal(style.backgroundColor, "rgb(22, 167, 101)", "item background correct");
+ Assert.equal(style.color, "rgb(255, 255, 255)", "item foreground correct");
+ } else {
+ Assert.equal(
+ style.backgroundColor,
+ "rgb(221, 51, 51)",
+ "item background correct (not target calendar)"
+ );
+ Assert.equal(
+ style.color,
+ "rgb(255, 255, 255)",
+ "item foreground correct (not target calendar)"
+ );
+ }
+ });
+
+ info("Reset color.");
+ thisCalendar.setProperty("color", "#ffee22");
+
+ info("Disable.");
+
+ thisCalendar.setProperty("disabled", true);
+ await checkBoxItems(notThisBoxCount);
+
+ info("Enable.");
+
+ await makeChangeWithReload(() => thisCalendar.setProperty("disabled", false));
+ await checkBoxItems(thisBoxCount + notThisBoxCount);
+
+ info("Hide.");
+
+ composite.removeCalendar(thisCalendar);
+ await checkBoxItems(notThisBoxCount);
+
+ info("Show.");
+
+ await makeChangeWithReload(() => composite.addCalendar(thisCalendar));
+ await checkBoxItems(thisBoxCount + notThisBoxCount);
+
+ info("Set read-only.");
+
+ await makeChangeWithReload(() => thisCalendar.setProperty("readOnly", true));
+ await checkBoxItems(thisBoxCount + notThisBoxCount, async (boxItem, isThisCalendar) => {
+ if (isThisCalendar) {
+ await assertEditable(boxItem, false, "In readonly calendar");
+ } else {
+ await assertEditable(boxItem, true, "In non-readonly calendar");
+ }
+ });
+
+ info("Clear read-only.");
+
+ await makeChangeWithReload(() => thisCalendar.setProperty("readOnly", false));
+ await checkBoxItems(thisBoxCount + notThisBoxCount, async boxItem => {
+ await assertEditable(boxItem, true, "In non-readonly calendar after clearing");
+ });
+}
+
+add_task(async function testMonthView() {
+ await subTest("month", "calendar-month-day-box-item", 5, 3);
+});
+
+add_task(async function testMultiWeekView() {
+ await subTest("multiweek", "calendar-month-day-box-item", 5, 3);
+});
+
+add_task(async function testWeekView() {
+ await subTest("week", "calendar-editable-item, .multiday-events-list calendar-event-box", 4, 3);
+});
+
+add_task(async function testDayView() {
+ await subTest("day", "calendar-editable-item, .multiday-events-list calendar-event-box", 2, 2);
+});
+
+registerCleanupFunction(async () => {
+ CalendarTestUtils.removeCalendar(thisCalendar);
+ CalendarTestUtils.removeCalendar(notThisCalendar);
+});
diff --git a/comm/calendar/test/browser/views/browser_taskView.js b/comm/calendar/test/browser/views/browser_taskView.js
new file mode 100644
index 0000000000..c049c9668f
--- /dev/null
+++ b/comm/calendar/test/browser/views/browser_taskView.js
@@ -0,0 +1,148 @@
+/* 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/. */
+
+var { MID_SLEEP, execEventDialogCallback } = ChromeUtils.import(
+ "resource://testing-common/calendar/CalendarUtils.jsm"
+);
+var { saveAndCloseItemDialog, setData } = ChromeUtils.import(
+ "resource://testing-common/calendar/ItemEditingHelpers.jsm"
+);
+
+const TITLE = "Task";
+const DESCRIPTION = "1. Do A\n2. Do B";
+const PERCENTCOMPLETE = "50";
+
+add_task(async function () {
+ let calendar = CalendarTestUtils.createCalendar();
+ registerCleanupFunction(() => {
+ CalendarTestUtils.removeCalendar(calendar);
+ });
+
+ // Open task view.
+ EventUtils.synthesizeMouseAtCenter(document.getElementById("tasksButton"), {}, window);
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, MID_SLEEP));
+
+ // Make sure that testing calendar is selected.
+ let calList = document.querySelector(`#calendar-list > [calendar-id="${calendar.id}"]`);
+ Assert.ok(calList);
+ EventUtils.synthesizeMouseAtCenter(calList, {}, window);
+
+ let taskTreeNode = document.getElementById("calendar-task-tree");
+ Assert.equal(taskTreeNode.mTaskArray.length, 0);
+
+ // Add task.
+ let taskInput = document.getElementById("view-task-edit-field");
+ taskInput.focus();
+ EventUtils.sendString(TITLE, window);
+ EventUtils.synthesizeKey("VK_RETURN", {}, window);
+
+ // Verify added.
+ await TestUtils.waitForCondition(
+ () => taskTreeNode.mTaskArray.length == 1,
+ "Added Task did not appear"
+ );
+
+ // Last added task is automatically selected so verify detail window data.
+ Assert.equal(document.getElementById("calendar-task-details-title").textContent, TITLE);
+
+ // Open added task
+ // Double-click on completion checkbox is ignored as opening action, so don't
+ // click at immediate left where the checkbox is located.
+ let eventWindowPromise = CalendarTestUtils.waitForEventDialog("edit");
+ let treeChildren = document.querySelector("#calendar-task-tree .calendar-task-treechildren");
+ Assert.ok(treeChildren);
+ EventUtils.synthesizeMouse(treeChildren, 50, 0, { clickCount: 2 }, window);
+
+ await eventWindowPromise;
+ await execEventDialogCallback(async (taskWindow, iframeWindow) => {
+ // Verify calendar.
+ Assert.equal(iframeWindow.document.getElementById("item-calendar").value, "Test");
+
+ await setData(taskWindow, iframeWindow, {
+ status: "needs-action",
+ percent: PERCENTCOMPLETE,
+ description: DESCRIPTION,
+ });
+
+ await saveAndCloseItemDialog(taskWindow);
+ });
+
+ Assert.less(taskTreeNode.mTaskArray.length, 2, "Should not have added task");
+ Assert.greater(taskTreeNode.mTaskArray.length, 0, "Should not have removed task");
+
+ // Verify description and status in details pane.
+ await TestUtils.waitForCondition(() => {
+ let desc = document.getElementById("calendar-task-details-description");
+ return desc && desc.contentDocument.body.innerText == DESCRIPTION;
+ }, "Calendar task description");
+ Assert.equal(document.getElementById("calendar-task-details-status").textContent, "Needs Action");
+
+ // This is a hack.
+ taskTreeNode.getTaskAtRow(0).calendar.setProperty("capabilities.priority.supported", true);
+
+ // Set high priority and verify it in detail pane.
+ EventUtils.synthesizeMouseAtCenter(document.getElementById("task-actions-priority"), {}, window);
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, MID_SLEEP));
+
+ let priorityMenu = document.querySelector(
+ "#task-actions-priority-menupopup > .priority-1-menuitem"
+ );
+ Assert.ok(priorityMenu);
+ EventUtils.synthesizeMouseAtCenter(priorityMenu, {}, window);
+ await TestUtils.waitForCondition(
+ () => !document.getElementById("calendar-task-details-priority-high").hidden,
+ "#calendar-task-details-priority-high did not show"
+ );
+
+ // Verify that tooltip shows status, priority and percent complete.
+ let toolTipNode = document.getElementById("taskTreeTooltip");
+ toolTipNode.ownerGlobal.showToolTip(toolTipNode, taskTreeNode.getTaskAtRow(0));
+
+ function getTooltipDescription(index) {
+ return toolTipNode.querySelector(
+ `.tooltipHeaderTable > tr:nth-of-type(${index}) > .tooltipHeaderDescription`
+ ).textContent;
+ }
+
+ // Name
+ Assert.equal(getTooltipDescription(1), TITLE);
+ // Calendar
+ Assert.equal(getTooltipDescription(2), "Test");
+ // Priority
+ Assert.equal(getTooltipDescription(3), "High");
+ // Status
+ Assert.equal(getTooltipDescription(4), "Needs Action");
+ // Complete
+ Assert.equal(getTooltipDescription(5), PERCENTCOMPLETE + "%");
+
+ // Mark completed, verify.
+ EventUtils.synthesizeMouseAtCenter(
+ document.getElementById("task-actions-markcompleted"),
+ {},
+ window
+ );
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, MID_SLEEP));
+
+ toolTipNode.ownerGlobal.showToolTip(toolTipNode, taskTreeNode.getTaskAtRow(0));
+ Assert.equal(getTooltipDescription(4), "Completed");
+
+ // Delete task and verify.
+ EventUtils.synthesizeMouseAtCenter(
+ document.getElementById("calendar-delete-task-button"),
+ {},
+ window
+ );
+ await TestUtils.waitForCondition(
+ () => taskTreeNode.mTaskArray.length == 0,
+ "Task did not delete"
+ );
+
+ let tabmail = document.getElementById("tabmail");
+ tabmail.closeTab(tabmail.currentTabInfo);
+
+ Assert.ok(true, "Test ran to completion");
+});
diff --git a/comm/calendar/test/browser/views/browser_viewSwitch.js b/comm/calendar/test/browser/views/browser_viewSwitch.js
new file mode 100644
index 0000000000..e730f3d797
--- /dev/null
+++ b/comm/calendar/test/browser/views/browser_viewSwitch.js
@@ -0,0 +1,138 @@
+/* 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 that the time indicator is restarted and scroll position is restored
+ * when switching tabs or views.
+ */
+
+/**
+ * Wait until the view's timebar shows the given number of visible hours.
+ *
+ * @param {CalendarMultidayBaseView} view - The calendar view.
+ * @param {number} numHours - The expected number of visible hours.
+ *
+ * @returns {Promise} - Promise that resolves when the timebar has numHours
+ * visible hours.
+ */
+function waitForVisibleHours(view, numHours) {
+ // The timebar is the only scrollable child in its column (the others are
+ // sticky), so the difference between the scroll area's scrollTopMax and the
+ // timebar's clientHeight should give us the visible height.
+ return TestUtils.waitForCondition(() => {
+ let timebarHeight = view.timebar.clientHeight;
+ let visiblePx = timebarHeight - view.grid.scrollTopMax;
+ let expectPx = (numHours / 24) * timebarHeight;
+ // Allow up to 3px difference to accommodate accumulated integer rounding
+ // errors (e.g. clientHeight is a rounded integer, whilst client rectangles
+ // and expectPx are floating).
+ return Math.abs(visiblePx - expectPx) < 3;
+ }, `${view.id} should have ${numHours} hours visible`);
+}
+
+/**
+ * Wait until the view's timebar's first visible hour is the given hour.
+ *
+ * @param {CalendarMultidayBaseView} view - The calendar view.
+ * @param {number} hour - The expected first visible hour.
+ *
+ * @returns {Promise} - Promise that resolves when the timebar has the given
+ * first visible hour.
+ */
+function waitForFirstVisibleHour(view, hour) {
+ return TestUtils.waitForCondition(() => {
+ let expectPx = (hour / 24) * view.timebar.clientHeight;
+ let actualPx = view.grid.scrollTop;
+ return Math.abs(actualPx - expectPx) < 3;
+ }, `${view.id} first visible hour should be ${hour}`);
+}
+
+/**
+ * Perform a scroll on the view by one hour.
+ *
+ * @param {CalendarMultidayBaseView} view - The calendar view to scroll.
+ * @param {boolean} scrollDown - Whether to scroll down, otherwise scrolls up.
+ */
+async function doScroll(view, scrollDown) {
+ let scrollPromise = BrowserTestUtils.waitForEvent(view.grid, "scroll");
+ let viewRect = view.getBoundingClientRect();
+ EventUtils.synthesizeWheel(
+ view.grid,
+ viewRect.width / 2,
+ viewRect.height / 2,
+ { deltaY: scrollDown ? 1 : -1, deltaMode: WheelEvent.DOM_DELTA_LINE },
+ window
+ );
+ await scrollPromise;
+}
+
+add_task(async function () {
+ let expectedVisibleHours = 3;
+ let expectedStartHour = 3;
+
+ let tabmail = document.getElementById("tabmail");
+ Assert.equal(tabmail.tabInfo.length, 1);
+
+ Assert.equal(Services.prefs.getIntPref("calendar.view.daystarthour"), expectedStartHour);
+ Assert.equal(Services.prefs.getIntPref("calendar.view.dayendhour"), 12);
+ Assert.equal(Services.prefs.getIntPref("calendar.view.visiblehours"), expectedVisibleHours);
+
+ // Open the day view, check the display matches the prefs.
+
+ await CalendarTestUtils.setCalendarView(window, "day");
+
+ let dayView = document.getElementById("day-view");
+
+ await waitForFirstVisibleHour(dayView, expectedStartHour);
+ await waitForVisibleHours(dayView, expectedVisibleHours);
+
+ // Scroll down 3 hours. We'll check this scroll position later.
+ await doScroll(dayView, true);
+ await waitForFirstVisibleHour(dayView, expectedStartHour + 1);
+
+ await doScroll(dayView, true);
+ await doScroll(dayView, true);
+ await waitForFirstVisibleHour(dayView, expectedStartHour + 3);
+ await waitForVisibleHours(dayView, expectedVisibleHours);
+
+ // Open the week view, check the display matches the prefs.
+
+ await CalendarTestUtils.setCalendarView(window, "week");
+
+ let weekView = document.getElementById("week-view");
+
+ await waitForFirstVisibleHour(weekView, expectedStartHour);
+ await waitForVisibleHours(weekView, expectedVisibleHours);
+
+ // Scroll up 1 hour.
+ await doScroll(weekView, false);
+ await waitForFirstVisibleHour(weekView, expectedStartHour - 1);
+ await waitForVisibleHours(weekView, expectedVisibleHours);
+
+ // Go back to the day view, check the timer and scroll position.
+
+ await CalendarTestUtils.setCalendarView(window, "day");
+
+ await waitForFirstVisibleHour(dayView, expectedStartHour + 3);
+ await waitForVisibleHours(dayView, expectedVisibleHours);
+
+ // Switch away from the calendar tab.
+
+ tabmail.switchToTab(0);
+
+ // Switch back to the calendar tab. Check scroll position.
+
+ tabmail.switchToTab(1);
+ Assert.equal(window.currentView().id, "day-view");
+
+ await waitForFirstVisibleHour(dayView, expectedStartHour + 3);
+ await waitForVisibleHours(dayView, expectedVisibleHours);
+
+ // Go back to the week view. Check scroll position.
+
+ await CalendarTestUtils.setCalendarView(window, "week");
+
+ await waitForFirstVisibleHour(weekView, expectedStartHour - 1);
+ await waitForVisibleHours(weekView, expectedVisibleHours);
+});
diff --git a/comm/calendar/test/browser/views/browser_weekView.js b/comm/calendar/test/browser/views/browser_weekView.js
new file mode 100644
index 0000000000..0835da2f23
--- /dev/null
+++ b/comm/calendar/test/browser/views/browser_weekView.js
@@ -0,0 +1,81 @@
+/* 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/. */
+
+var { formatDate, formatTime, saveAndCloseItemDialog, setData } = ChromeUtils.import(
+ "resource://testing-common/calendar/ItemEditingHelpers.jsm"
+);
+
+var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
+
+var TITLE1 = "Week View Event";
+var TITLE2 = "Week View Event Changed";
+var DESC = "Week View Event Description";
+
+add_task(async function testWeekView() {
+ let calendar = CalendarTestUtils.createCalendar();
+ registerCleanupFunction(() => {
+ CalendarTestUtils.removeCalendar(calendar);
+ });
+
+ await CalendarTestUtils.setCalendarView(window, "week");
+ await CalendarTestUtils.goToDate(window, 2009, 1, 1);
+
+ // Verify date.
+ await TestUtils.waitForCondition(() => {
+ let dateLabel = document.querySelector("#week-view .day-column-selected calendar-event-column");
+ return dateLabel?.date.icalString == "20090101";
+ }, "Date is selected");
+
+ // Create event at 8 AM.
+ // Thursday of 2009-01-05 is 4th with default settings.
+ let eventBox = CalendarTestUtils.weekView.getHourBoxAt(window, 5, 8);
+ let { dialogWindow, iframeWindow, iframeDocument } = await CalendarTestUtils.editNewEvent(
+ window,
+ eventBox
+ );
+
+ // Check that the start time is correct.
+ let someDate = cal.createDateTime();
+ someDate.resetTo(2009, 0, 5, 8, 0, 0, cal.dtz.UTC);
+
+ let startPicker = iframeDocument.getElementById("event-starttime");
+ Assert.equal(startPicker._datepicker._inputField.value, formatDate(someDate));
+ Assert.equal(startPicker._timepicker._inputField.value, formatTime(someDate));
+
+ // Fill in title, description and calendar.
+ await setData(dialogWindow, iframeWindow, {
+ title: TITLE1,
+ description: DESC,
+ calendar: "Test",
+ });
+
+ await saveAndCloseItemDialog(dialogWindow);
+
+ // If it was created successfully, it can be opened.
+ ({ dialogWindow, iframeWindow } = await CalendarTestUtils.weekView.editEventAt(window, 5, 1));
+ // Change title and save changes.
+ await setData(dialogWindow, iframeWindow, { title: TITLE2 });
+ await saveAndCloseItemDialog(dialogWindow);
+
+ // Check if name was saved.
+ let eventName;
+ await TestUtils.waitForCondition(() => {
+ eventBox = CalendarTestUtils.weekView.getEventBoxAt(window, 5, 1);
+ if (!eventBox) {
+ return false;
+ }
+ eventName = eventBox.querySelector(".event-name-label").textContent;
+ return eventName == TITLE2;
+ }, "event name did not update in time");
+
+ Assert.equal(eventName, TITLE2);
+
+ // Delete event.
+ EventUtils.synthesizeMouseAtCenter(eventBox, {}, window);
+ eventBox.focus();
+ EventUtils.synthesizeKey("VK_DELETE", {}, window);
+ await CalendarTestUtils.weekView.waitForNoEventBoxAt(window, 5, 1);
+
+ Assert.ok(true, "Test ran to completion");
+});
diff --git a/comm/calendar/test/browser/views/head.js b/comm/calendar/test/browser/views/head.js
new file mode 100644
index 0000000000..c0f924d9b5
--- /dev/null
+++ b/comm/calendar/test/browser/views/head.js
@@ -0,0 +1,13 @@
+/* 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/. */
+
+const { CalendarTestUtils } = ChromeUtils.import(
+ "resource://testing-common/calendar/CalendarTestUtils.jsm"
+);
+
+const calendarViewsInitialState = CalendarTestUtils.saveCalendarViewsState(window);
+
+registerCleanupFunction(async () => {
+ await CalendarTestUtils.restoreCalendarViewsState(window, calendarViewsInitialState);
+});