diff options
Diffstat (limited to 'comm/calendar/test/browser/views')
-rw-r--r-- | comm/calendar/test/browser/views/browser.ini | 32 | ||||
-rw-r--r-- | comm/calendar/test/browser/views/browser_dayView.js | 185 | ||||
-rw-r--r-- | comm/calendar/test/browser/views/browser_monthView.js | 86 | ||||
-rw-r--r-- | comm/calendar/test/browser/views/browser_multiweekView.js | 88 | ||||
-rw-r--r-- | comm/calendar/test/browser/views/browser_propertyChanges.js | 248 | ||||
-rw-r--r-- | comm/calendar/test/browser/views/browser_taskView.js | 148 | ||||
-rw-r--r-- | comm/calendar/test/browser/views/browser_viewSwitch.js | 138 | ||||
-rw-r--r-- | comm/calendar/test/browser/views/browser_weekView.js | 81 | ||||
-rw-r--r-- | comm/calendar/test/browser/views/head.js | 13 |
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); +}); |