Bug 1491593 [mozmill] fix and enhance shared-module calendar-utils "setData()"-Function. r=darktrojan
authorMarkus Adrario <mozilla@adrario.de>
Sat, 13 Oct 2018 22:43:51 +0200
changeset 32755 a0437b33ea6c8100054d7b203f9da71219aab018
parent 32754 0680cc858ed9d25e748180abb9c6c5e0c77bfd90
child 32756 4a6558329193460f23dd78cb202003b032731785
push id2343
push userclokep@gmail.com
push dateMon, 10 Dec 2018 21:37:21 +0000
treeherdercomm-beta@a0750c375f71 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdarktrojan
bugs1491593
Bug 1491593 [mozmill] fix and enhance shared-module calendar-utils "setData()"-Function. r=darktrojan
calendar/test/mozmill/.eslintrc.js
calendar/test/mozmill/cal-recurrence/testAnnualRecurrence.js
calendar/test/mozmill/cal-recurrence/testBiweeklyRecurrence.js
calendar/test/mozmill/cal-recurrence/testDailyRecurrence.js
calendar/test/mozmill/cal-recurrence/testLastDayOfMonthRecurrence.js
calendar/test/mozmill/cal-recurrence/testWeeklyNRecurrence.js
calendar/test/mozmill/cal-recurrence/testWeeklyUntilRecurrence.js
calendar/test/mozmill/cal-recurrence/testWeeklyWithExceptionRecurrence.js
calendar/test/mozmill/eventDialog/testEventDialog.js
calendar/test/mozmill/eventDialog/testEventDialogModificationPrompt.js
calendar/test/mozmill/eventDialog/testEventDialogSize.js
calendar/test/mozmill/eventDialog/testUTF8.js
calendar/test/mozmill/invitations/test-imip-bar-eml.js
calendar/test/mozmill/recurrenceRotated/testAnnualRecurrence.js
calendar/test/mozmill/recurrenceRotated/testBiweeklyRecurrence.js
calendar/test/mozmill/recurrenceRotated/testDailyRecurrence.js
calendar/test/mozmill/recurrenceRotated/testLastDayOfMonthRecurrence.js
calendar/test/mozmill/recurrenceRotated/testWeeklyNRecurrence.js
calendar/test/mozmill/recurrenceRotated/testWeeklyUntilRecurrence.js
calendar/test/mozmill/recurrenceRotated/testWeeklyWithExceptionRecurrence.js
calendar/test/mozmill/shared-modules/test-calendar-utils.js
calendar/test/mozmill/shared-modules/test-item-editing-helpers.js
calendar/test/mozmill/testAlarmDefaultValue.js
calendar/test/mozmill/testBasicFunctionality.js
calendar/test/mozmill/testLocalICS.js
calendar/test/mozmill/testTimezones.js
calendar/test/mozmill/testTodayPane.js
calendar/test/mozmill/views/testDayView.js
calendar/test/mozmill/views/testMonthView.js
calendar/test/mozmill/views/testMultiweekView.js
calendar/test/mozmill/views/testTaskView.js
calendar/test/mozmill/views/testWeekView.js
--- a/calendar/test/mozmill/.eslintrc.js
+++ b/calendar/test/mozmill/.eslintrc.js
@@ -14,16 +14,18 @@ module.exports = {
         persisted: true,
 
         lookup: true,
         eid: true,
         xpath: true,
         sleep: true,
         getEventBoxPath: true,
         lookupEventBox: true,
+        iframeLookup: true,
+        getDateTimePicker: true,
     },
     rules: {
         // Allow mozmill test methods to be used without warning
         "no-unused-vars": [2, {
             vars: "all",
             args: "none",
             varsIgnorePattern: "(MODULE_NAME|MODULE_REQUIRES|RELATIVE_ROOT|setupModule|installInto|teardownTest|^test[A-Z_].*)"
         }]
--- a/calendar/test/mozmill/cal-recurrence/testAnnualRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testAnnualRecurrence.js
@@ -23,73 +23,61 @@ function setupModule(module) {
         handleOccurrencePrompt,
         switchToView,
         goToDate,
         invokeEventDialog,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
     createCalendar(controller, CALENDARNAME);
 }
 
 function testAnnualRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    sleep();
-
-    switchToView(controller, "day");
     goToDate(controller, STARTYEAR, 1, 1);
 
-    // create yearly recurring all-day event
+    // Create yearly recurring all-day event.
     let eventBox = lookupEventBox("day", ALLDAY, null, 1, null);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         menulistSelect(eventid("item-repeat"), "yearly", event);
         event.click(eventid("button-saveandclose"));
     });
 
     let checkYears = [STARTYEAR, STARTYEAR + 1, EPOCH - 1, EPOCH, EPOCH + 1];
     for (let year of checkYears) {
         goToDate(controller, year, 1, 1);
         let date = new Date(year, 0, 1);
         let column = date.getDay() + 1;
 
         // day view
         switchToView(controller, "day");
-        controller.waitForElement(
-            lookupEventBox("day", ALLDAY, null, 1, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("day", ALLDAY, null, 1, null, EVENTPATH));
 
         // week view
         switchToView(controller, "week");
-        controller.waitForElement(
-            lookupEventBox("week", ALLDAY, null, column, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", ALLDAY, null, column, null, EVENTPATH));
 
         // multiweek view
         switchToView(controller, "multiweek");
-        controller.waitForElement(
-            lookupEventBox("multiweek", ALLDAY, 1, column, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("multiweek", ALLDAY, 1, column, null, EVENTPATH));
 
         // month view
         switchToView(controller, "month");
-        controller.waitForElement(
-            lookupEventBox("month", ALLDAY, 1, column, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("month", ALLDAY, 1, column, null, EVENTPATH));
     }
 
-    // delete event
+    // Delete event.
     goToDate(controller, checkYears[0], 1, 1);
     switchToView(controller, "day");
     let box = getEventBoxPath("day", ALLDAY, null, 1, null) + EVENTPATH;
     controller.click(lookup(box));
-    handleOccurrencePrompt(controller, eid("day-view"), "delete", true, false);
+    handleOccurrencePrompt(controller, eid("day-view"), "delete", true);
     controller.waitForElementNotPresent(lookup(box));
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/cal-recurrence/testBiweeklyRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testBiweeklyRecurrence.js
@@ -24,89 +24,83 @@ function setupModule(module) {
         switchToView,
         goToDate,
         invokeEventDialog,
         viewForward,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
     createCalendar(controller, CALENDARNAME);
 }
 
 function testBiweeklyRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 31);
 
-    // create biweekly event
+    // Create biweekly event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         menulistSelect(eventid("item-repeat"), "bi.weekly", event);
         event.click(eventid("button-saveandclose"));
     });
 
-    // check day view
+    // Check day view.
     for (let i = 0; i < 4; i++) {
-        controller.waitForElement(
-            lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH));
         viewForward(controller, 14);
     }
 
-    // check week view
+    // Check week view.
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 31);
 
     for (let i = 0; i < 4; i++) {
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, 7, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH));
         viewForward(controller, 2);
     }
 
-    // check multiweek view
+    // Check multiweek view.
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 31);
 
-    // always two occurrences in view, 1st and 3rd or 2nd and 4th week
+    // Always two occurrences in view, 1st and 3rd or 2nd and 4th week.
     for (let i = 0; i < 5; i++) {
         controller.waitForElement(
             lookupEventBox("multiweek", EVENT_BOX, i % 2 + 1, 7, null, EVENTPATH)
         );
         controller.assertNode(
             lookupEventBox("multiweek", EVENT_BOX, i % 2 + 3, 7, null, EVENTPATH)
         );
         viewForward(controller, 1);
     }
 
-    // check month view
+    // Check month view.
     switchToView(controller, "month");
     goToDate(controller, 2009, 1, 31);
 
     // January
     controller.waitForElement(lookupEventBox("month", EVENT_BOX, 5, 7, null, EVENTPATH));
     viewForward(controller, 1);
 
     // February
     controller.waitForElement(lookupEventBox("month", EVENT_BOX, 2, 7, null, EVENTPATH));
     controller.assertNode(lookupEventBox("month", EVENT_BOX, 4, 7, null, EVENTPATH));
     viewForward(controller, 1);
 
     // March
     controller.waitForElement(lookupEventBox("month", EVENT_BOX, 2, 7, null, EVENTPATH));
     controller.assertNode(lookupEventBox("month", EVENT_BOX, 4, 7, null, EVENTPATH));
 
-    // delete event
+    // Delete event.
     let box = lookupEventBox("month", EVENT_BOX, 4, 7, null, EVENTPATH);
     controller.click(box);
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", true, false);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", true);
     controller.waitForElementNotPresent(box);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/cal-recurrence/testDailyRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testDailyRecurrence.js
@@ -1,20 +1,21 @@
 /* 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 MODULE_NAME = "testDailyRecurrence";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers"];
 
 var CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
 var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
 var switchToView, goToDate, viewForward, viewBack, handleOccurrencePrompt;
 var menulistSelect;
+var setData;
 
 const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         CALENDARNAME,
         EVENTPATH,
@@ -26,188 +27,169 @@ function setupModule(module) {
         goToDate,
         invokeEventDialog,
         viewForward,
         viewBack,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({ setData } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, CALENDARNAME);
 }
 
 function testDailyRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 1);
 
-    // create daily event
+    // Create daily event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        menulistSelect(eventid("item-repeat"), "daily", event);
+        setData(event, iframe, { repeat: "daily", repeatuntil: new Date(2009, 2, 20) });
         event.click(eventid("button-saveandclose"));
     });
 
-    // check day view for 7 days
-    let daybox = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR, null) + EVENTPATH;
-    controller.waitForElement(lookup(daybox));
+    // Check day view for 7 days.
+    let daybox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    controller.waitForElement(daybox);
 
     for (let day = 1; day <= 7; day++) {
-        controller.waitForElement(lookup(daybox));
+        controller.waitForElement(daybox);
         viewForward(controller, 1);
     }
 
-    // check week view for 2 weeks
+    // Check week view for 2 weeks.
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 1);
 
     for (let day = 5; day <= 7; day++) {
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, 1, day, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, 1, day, null, EVENTPATH));
     }
 
     viewForward(controller, 1);
 
     for (let day = 1; day <= 7; day++) {
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, 2, day, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, 2, day, null, EVENTPATH));
     }
 
-    // check multiweek view for 4 weeks
+    // Check multiweek view for 4 weeks.
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 1);
 
     for (let day = 5; day <= 7; day++) {
-        controller.waitForElement(
-            lookupEventBox("multiweek", EVENT_BOX, 1, day, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("multiweek", EVENT_BOX, 1, day, null, EVENTPATH));
     }
 
     for (let week = 2; week <= 4; week++) {
         for (let day = 1; day <= 7; day++) {
             controller.waitForElement(
-                lookupEventBox("multiweek", EVENT_BOX, week, day, HOUR, EVENTPATH)
-            );
-        }
-    }
-
-    // check month view for all 5 weeks
-    switchToView(controller, "month");
-    goToDate(controller, 2009, 1, 1);
-
-    for (let day = 5; day <= 7; day++) {
-        controller.waitForElement(
-            lookupEventBox("month", EVENT_BOX, 1, day, null, EVENTPATH)
-        );
-    }
-
-    for (let week = 2; week <= 5; week++) {
-        for (let day = 1; day <= 7; day++) {
-            controller.assertNode(
-                lookupEventBox("month", EVENT_BOX, week, day, null, EVENTPATH)
+                lookupEventBox("multiweek", EVENT_BOX, week, day, null, EVENTPATH)
             );
         }
     }
 
-    // delete 3rd January occurrence
-    let saturday = getEventBoxPath("month", EVENT_BOX, 1, 7, null) + EVENTPATH;
-    controller.click(lookup(saturday));
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", false, false);
+    // Check month view for all 5 weeks.
+    switchToView(controller, "month");
+    goToDate(controller, 2009, 1, 1);
+
+    for (let day = 5; day <= 7; day++) {
+        controller.waitForElement(lookupEventBox("month", EVENT_BOX, 1, day, null, EVENTPATH));
+    }
 
-    // verify in all views
-    controller.waitForElementNotPresent(lookup(saturday));
+    for (let week = 2; week <= 5; week++) {
+        for (let day = 1; day <= 7; day++) {
+            controller.assertNode(lookupEventBox("month", EVENT_BOX, week, day, null, EVENTPATH));
+        }
+    }
+
+    // Delete 3rd January occurrence.
+    let saturday = lookupEventBox("month", EVENT_BOX, 1, 7, null, EVENTPATH);
+    controller.click(saturday);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", false);
+
+    // Verify in all views.
+    controller.waitForElementNotPresent(saturday);
 
     switchToView(controller, "multiweek");
-    controller.assertNodeNotExist(
-        lookupEventBox("multiweek", EVENT_BOX, 1, 7, null, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("multiweek", EVENT_BOX, 1, 7, null, EVENTPATH));
 
     switchToView(controller, "week");
-    controller.assertNodeNotExist(
-        lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH));
 
     switchToView(controller, "day");
-    controller.assertNodeNotExist(
-        lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH));
 
-    // go to previous day to edit event to occur only on weekdays
+    // Go to previous day to edit event to occur only on weekdays.
     viewBack(controller, 1);
 
-    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH);
-    handleOccurrencePrompt(controller, eventBox, "modify", true, false);
+    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    handleOccurrencePrompt(controller, eventBox, "modify", true);
     invokeEventDialog(controller, null, (event, iframe) => {
         let { eid: eventid, sleep: eventsleep } = helpersForController(event);
 
         menulistSelect(eventid("item-repeat"), "every.weekday", event);
         eventsleep();
         event.click(eventid("button-saveandclose"));
     });
 
-    // check day view for 7 days
-    let day = getEventBoxPath("day", EVENT_BOX, null, 1, null) + EVENTPATH;
+    // Check day view for 7 days.
+    let day = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
     let dates = [
         [2009, 1, 3],
         [2009, 1, 4]
     ];
     for (let [y, m, d] of dates) {
         goToDate(controller, y, m, d);
-        controller.assertNodeNotExist(lookup(day));
+        controller.assertNodeNotExist(day);
     }
 
-    // check week view for 2 weeks
+    // Check week view for 2 weeks.
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 1);
 
     for (let i = 0; i <= 1; i++) {
         controller.waitForElementNotPresent(
             lookupEventBox("week", EVENT_BOX, null, 1, null, EVENTPATH)
         );
-        controller.assertNodeNotExist(
-            lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH)
-        );
+        controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH));
         viewForward(controller, 1);
     }
 
-    // check multiweek view for 4 weeks
+    // Check multiweek view for 4 weeks.
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 1);
 
     for (let i = 1; i <= 4; i++) {
         controller.waitForElementNotPresent(
             lookupEventBox("multiweek", EVENT_BOX, i, 1, null, EVENTPATH)
         );
         controller.assertNodeNotExist(
             lookupEventBox("multiweek", EVENT_BOX, i, 7, null, EVENTPATH)
         );
     }
 
-    // check month view for all 5 weeks
+    // Check month view for all 5 weeks.
     switchToView(controller, "month");
     goToDate(controller, 2009, 1, 1);
 
     for (let i = 1; i <= 5; i++) {
         controller.waitForElementNotPresent(
             lookupEventBox("month", EVENT_BOX, i, 1, null, EVENTPATH)
         );
-        controller.assertNodeNotExist(
-            lookupEventBox("month", EVENT_BOX, i, 7, null, EVENTPATH)
-        );
+        controller.assertNodeNotExist(lookupEventBox("month", EVENT_BOX, i, 7, null, EVENTPATH));
     }
 
-    // delete event
-    day = getEventBoxPath("month", EVENT_BOX, 1, 5, null) + EVENTPATH;
-    controller.click(lookup(day));
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(day));
+    // Delete event.
+    day = lookupEventBox("month", EVENT_BOX, 1, 5, null, EVENTPATH);
+    controller.click(day);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", true);
+    controller.waitForElementNotPresent(day);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/cal-recurrence/testLastDayOfMonthRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testLastDayOfMonthRecurrence.js
@@ -1,125 +1,121 @@
 /* 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 MODULE_NAME = "testLastDayOfMonthRecurrence";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
-var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
-var CANVAS_BOX, REC_DLG_ACCEPT;
+var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
 var invokeEventDialog, deleteCalendars, createCalendar, menulistSelect;
+var REC_DLG_ACCEPT;
 var plan_for_modal_dialog, wait_for_modal_dialog;
 
 const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         TIMEOUT_MODAL_DIALOG,
         CALENDARNAME,
         EVENTPATH,
         EVENT_BOX,
         CANVAS_BOX,
-        REC_DLG_ACCEPT,
         helpersForController,
         invokeEventDialog,
         createCalendar,
         deleteCalendars,
         switchToView,
         goToDate,
         handleOccurrencePrompt,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({ REC_DLG_ACCEPT } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers")
     );
 
     createCalendar(controller, CALENDARNAME);
 }
 
 function testLastDayOfMonthRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
-    goToDate(controller, 2008, 1, 31); // start with a leap year
+    goToDate(controller, 2008, 1, 31); // Start with a leap year.
 
-    // create monthly recurring event
+    // Create monthly recurring event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         menulistSelect(eventid("item-repeat"), "custom", event);
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
     // data tuple: [year, month, day, row in month view]
-    // note: month starts here with 1 for January
+    // note: Month starts here with 1 for January.
     let checkingData = [[2008, 1, 31, 5],
                         [2008, 2, 29, 5],
                         [2008, 3, 31, 6],
                         [2008, 4, 30, 5],
                         [2008, 5, 31, 5],
                         [2008, 6, 30, 5],
                         [2008, 7, 31, 5],
                         [2008, 8, 31, 6],
                         [2008, 9, 30, 5],
                         [2008, 10, 31, 5],
                         [2008, 11, 30, 6],
                         [2008, 12, 31, 5],
                         [2009, 1, 31, 5],
                         [2009, 2, 28, 4],
                         [2009, 3, 31, 5]];
-    // check all dates
+    // Check all dates.
     for (let [y, m, d, correctRow] of checkingData) {
         let date = new Date(y, m - 1, d);
         let column = date.getDay() + 1;
 
         goToDate(controller, y, m, d);
 
         // day view
         switchToView(controller, "day");
-        controller.waitForElement(
-            lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH));
 
         // week view
         switchToView(controller, "week");
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, column, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, column, null, EVENTPATH));
 
         // multiweek view
         switchToView(controller, "multiweek");
         controller.waitForElement(
             lookupEventBox("multiweek", EVENT_BOX, 1, column, null, EVENTPATH)
         );
 
         // month view
         switchToView(controller, "month");
         controller.waitForElement(
             lookupEventBox("month", EVENT_BOX, correctRow, column, null, EVENTPATH)
         );
     }
 
-    // delete event
+    // Delete event.
     goToDate(controller, checkingData[0][0], checkingData[0][1], checkingData[0][2]);
     switchToView(controller, "day");
-    let box = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
-    controller.waitThenClick(lookup(box));
-    handleOccurrencePrompt(controller, eid("day-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(box));
+    let box = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    controller.waitThenClick(box);
+    handleOccurrencePrompt(controller, eid("day-view"), "delete", true);
+    controller.waitForElementNotPresent(box);
 }
 
 function setRecurrence(recurrence) {
     let {
         sleep: recsleep,
         lookup: reclookup,
         eid: recid
     } = helpersForController(recurrence);
@@ -128,15 +124,15 @@ function setRecurrence(recurrence) {
     menulistSelect(recid("period-list"), "2", recurrence);
 
     // last day of month
     recurrence.radio(recid("montly-period-relative-date-radio"));
     menulistSelect(recid("monthly-ordinal"), "-1", recurrence);
     menulistSelect(recid("monthly-weekday"), "-1", recurrence);
     recsleep();
 
-    // close dialog
+    // Close dialog.
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/cal-recurrence/testWeeklyNRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testWeeklyNRecurrence.js
@@ -1,174 +1,159 @@
 /* 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 MODULE_NAME = "testWeeklyNRecurrence";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
 var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
-var REC_DLG_ACCEPT, REC_DLG_DAYS;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
 var invokeEventDialog, viewForward, deleteCalendars, createCalendar, menulistSelect;
+var REC_DLG_ACCEPT, REC_DLG_DAYS;
 var plan_for_modal_dialog, wait_for_modal_dialog;
 
 const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         TIMEOUT_MODAL_DIALOG,
         CALENDARNAME,
         EVENTPATH,
         EVENT_BOX,
         CANVAS_BOX,
-        REC_DLG_ACCEPT,
-        REC_DLG_DAYS,
         helpersForController,
         handleOccurrencePrompt,
         switchToView,
         goToDate,
         invokeEventDialog,
         viewForward,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        REC_DLG_ACCEPT,
+        REC_DLG_DAYS
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers")
     );
 
     createCalendar(controller, CALENDARNAME);
 }
 
 function testWeeklyNRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 5);
 
-    // create weekly recurring event
+    // Create weekly recurring event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         event.waitForElement(eventid("item-repeat"));
         menulistSelect(eventid("item-repeat"), "custom", event);
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
-    // check day view
-    let box = getEventBoxPath("day", EVENT_BOX, undefined, 1, HOUR) + EVENTPATH;
+    // Check day view.
+    let box = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
     // Monday, Tuesday, Wednesday, Thursday
     for (let i = 0; i < 4; i++) {
-        controller.waitForElement(lookup(box));
+        controller.waitForElement(box);
         viewForward(controller, 1);
     }
 
-    // Not Friday
-    sleep();
-    controller.assertNodeNotExist(lookup(box));
+    // Not Friday.
+    controller.waitForElementNotPresent(box);
     viewForward(controller, 1);
 
     // Not Saturday as only 4 occurrences are set.
-    sleep();
-    controller.assertNodeNotExist(lookup(box));
+    controller.waitForElementNotPresent(box);
 
-    // check week view
+    // Check week view.
     switchToView(controller, "week");
 
     // Monday, Tuesday, Wednesday, Thursday
     for (let i = 2; i < 6; i++) {
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, i, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, i, null, EVENTPATH));
     }
 
     // Saturday
-    controller.assertNodeNotExist(
-        lookupEventBox("week", EVENT_BOX, null, 7, HOUR, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH));
 
-    // check multiweek view
+    // Check multiweek view.
     switchToView(controller, "multiweek");
     checkMultiWeekView("multiweek");
 
-    // check month view
+    // Check month view.
     switchToView(controller, "month");
     checkMultiWeekView("month");
 
-    // delete event
-    box = getEventBoxPath("month", EVENT_BOX, 2, 2, HOUR) + EVENTPATH;
-    controller.click(lookup(box));
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(box));
+    // Delete event.
+    box = lookupEventBox("month", EVENT_BOX, 2, 2, null, EVENTPATH);
+    controller.click(box);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", true);
+    controller.waitForElementNotPresent(box);
 }
 
 function setRecurrence(recurrence) {
-    let {
-        sleep: recsleep,
-        lookup: reclookup,
-        eid: recid,
-    } = helpersForController(recurrence);
+    let { sleep: recsleep, lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
     recurrence.waitForElement(recid("period-list"));
     menulistSelect(recid("period-list"), "1", recurrence);
     recsleep();
 
     let mon = cal.l10n.getDateFmtString("day.2.Mmm");
     let tue = cal.l10n.getDateFmtString("day.3.Mmm");
     let wed = cal.l10n.getDateFmtString("day.4.Mmm");
     let thu = cal.l10n.getDateFmtString("day.5.Mmm");
     let sat = cal.l10n.getDateFmtString("day.7.Mmm");
 
-    // starting from Monday so it should be checked. We have to wait a little,
+    // Starting from Monday so it should be checked. We have to wait a little,
     // because the checkedstate is set in background by JS.
     recurrence.waitFor(() => {
         return recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
     }, 30000);
-    // check Tuesday, Wednesday, Thursday and Saturday too
+    // Check Tuesday, Wednesday, Thursday and Saturday too.
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${tue}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${thu}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${sat}"}`));
 
-    // set number of occurrences
+    // Set number of recurrences.
     recurrence.click(recid("recurrence-range-for"));
     let ntimesField = recid("repeat-ntimes-count");
     ntimesField.getNode().value = "4";
 
-    // close dialog
+    // Close dialog.
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function checkMultiWeekView(view) {
-    // make sure, the view has time to load
-    sleep();
-
-    // In month view event starts from 2nd row
+    // In month view event starts from 2nd row.
     let week = view == "month" ? 2 : 1;
 
     // Monday, Tuesday, Wednesday, Thursday
     for (let i = 2; i < 6; i++) {
-        controller.assertNode(
-            lookupEventBox(view, EVENT_BOX, week, i, null, EVENTPATH)
-        );
+        controller.assertNode(lookupEventBox(view, EVENT_BOX, week, i, null, EVENTPATH));
     }
 
     // Saturday
-    controller.assertNodeNotExist(
-        getEventBoxPath(view, EVENT_BOX, week, 7, null, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox(view, EVENT_BOX, week, 7, null, EVENTPATH));
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/cal-recurrence/testWeeklyUntilRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testWeeklyUntilRecurrence.js
@@ -1,216 +1,201 @@
 /* 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 MODULE_NAME = "testWeeklyUntilRecurrence";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
-var SHORT_SLEEP, TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
-var CANVAS_BOX, REC_DLG_DAYS, REC_DLG_ACCEPT, REC_DLG_UNTIL_INPUT;
+var SHORT_SLEEP, TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
 var invokeEventDialog, viewForward, deleteCalendars, createCalendar, menulistSelect;
+var REC_DLG_DAYS, REC_DLG_ACCEPT, REC_DLG_UNTIL_INPUT;
 var plan_for_modal_dialog, wait_for_modal_dialog;
 
-const ENDDATE = new Date(2009, 0, 26); // last Monday in month
+const ENDDATE = new Date(2009, 0, 26); // Last Monday in month.
 const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         SHORT_SLEEP,
         TIMEOUT_MODAL_DIALOG,
         CALENDARNAME,
         EVENTPATH,
         EVENT_BOX,
         CANVAS_BOX,
-        REC_DLG_DAYS,
-        REC_DLG_ACCEPT,
-        REC_DLG_UNTIL_INPUT,
         helpersForController,
         handleOccurrencePrompt,
         switchToView,
         goToDate,
         invokeEventDialog,
         viewForward,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        REC_DLG_DAYS,
+        REC_DLG_ACCEPT,
+        REC_DLG_UNTIL_INPUT
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers")
     );
 
     createCalendar(controller, CALENDARNAME);
 }
 
 function testWeeklyUntilRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 5); // Monday
 
-    // create weekly recurring event
+    // Create weekly recurring event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         event.waitForElement(eventid("item-repeat"));
         menulistSelect(eventid("item-repeat"), "custom", event);
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
-    let box = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
+    let box = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
 
-    // check day view
+    // Check day view.
     for (let week = 0; week < 3; week++) {
         // Monday
-        controller.waitForElement(lookup(box));
+        controller.waitForElement(box);
         viewForward(controller, 2);
 
         // Wednesday
-        controller.waitForElement(lookup(box));
+        controller.waitForElement(box);
         viewForward(controller, 2);
 
         // Friday
-        controller.waitForElement(lookup(box));
+        controller.waitForElement(box);
         viewForward(controller, 3);
     }
 
     // Monday, last occurrence
-    controller.waitForElement(lookup(box));
+    controller.waitForElement(box);
     viewForward(controller, 2);
 
     // Wednesday
-    controller.waitForElementNotPresent(lookup(box));
+    controller.waitForElementNotPresent(box);
 
-    // check week view
+    // Check week view.
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 5);
     for (let week = 0; week < 3; week++) {
         // Monday
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, 2, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 2, null, EVENTPATH));
 
         // Wednesday
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, 4, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 4, null, EVENTPATH));
 
         // Friday
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, 6, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, null, EVENTPATH));
 
         viewForward(controller, 1);
     }
 
     // Monday, last occurrence
-    controller.waitForElement(
-        lookupEventBox("week", EVENT_BOX, null, 2, HOUR, EVENTPATH)
-    );
+    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 2, null, EVENTPATH));
     // Wednesday
-    controller.assertNodeNotExist(
-        lookupEventBox("week", EVENT_BOX, null, 4, HOUR, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 4, null, EVENTPATH));
 
-    // check multiweek view
+    // Check multiweek view.
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 5);
     checkMultiWeekView("multiweek");
 
-    // check month view
+    // Check month view.
     switchToView(controller, "month");
     goToDate(controller, 2009, 1, 5);
     checkMultiWeekView("month");
 
-    // delete event
-    box = getEventBoxPath("month", EVENT_BOX, 2, 2, null) + EVENTPATH;
-    controller.click(lookup(box));
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(box));
+    // Delete event.
+    box = lookupEventBox("month", EVENT_BOX, 2, 2, null, EVENTPATH);
+    controller.click(box);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", true);
+    controller.waitForElementNotPresent(box);
 }
 
 function setRecurrence(recurrence) {
-    let { sleep: recsleep, lookup: reclookup, eid: recid } =
-        helpersForController(recurrence);
+    let { sleep: recsleep, lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
     recurrence.waitForElement(recid("period-list"));
     menulistSelect(recid("period-list"), "1", recurrence);
 
     let mon = cal.l10n.getDateFmtString("day.2.Mmm");
     let wed = cal.l10n.getDateFmtString("day.4.Mmm");
     let fri = cal.l10n.getDateFmtString("day.6.Mmm");
 
-    // starting from Monday so it should be checked. We have to wait a little,
+    // Starting from Monday so it should be checked. We have to wait a little,
     // because the checkedstate is set in background by JS.
     recurrence.waitFor(() => {
         return recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
     }, 30000);
-    // starting from Monday so it should be checked
+    // Starting from Monday so it should be checked.
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
-    // check Wednesday and Friday too
+    // Check Wednesday and Friday too.
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${fri}"}`));
 
-    // set until date
+    // Set until date.
     recurrence.radio(recid("recurrence-range-until"));
 
-    // delete previous date
+    // Delete previous date.
     let untilInput = reclookup(REC_DLG_UNTIL_INPUT);
     recurrence.keypress(untilInput, "a", { accelKey: true });
     recurrence.keypress(untilInput, "VK_DELETE", {});
 
     let dateFormatter = cal.getDateFormatter();
 
-    let endDateString = dateFormatter.formatDateShort(cal.dtz.jsDateToDateTime(ENDDATE, cal.dtz.floating));
+    let endDateString = dateFormatter.formatDateShort(
+        cal.dtz.jsDateToDateTime(ENDDATE, cal.dtz.floating)
+    );
     recsleep(SHORT_SLEEP);
     recurrence.type(untilInput, endDateString);
 
     recsleep(SHORT_SLEEP);
-    // Move focus to ensure the date is selected
+    // Move focus to ensure the date is selected.
     recurrence.keypress(untilInput, "VK_TAB", {});
 
-    // close dialog
+    // Close dialog.
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function checkMultiWeekView(view) {
     let startWeek = view == "month" ? 2 : 1;
 
     for (let week = startWeek; week < startWeek + 3; week++) {
         // Monday
-        controller.waitForElement(
-            lookupEventBox(view, EVENT_BOX, week, 2, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox(view, EVENT_BOX, week, 2, null, EVENTPATH));
         // Wednesday
-        controller.assertNode(
-            lookupEventBox(view, EVENT_BOX, week, 4, null, EVENTPATH)
-        );
+        controller.assertNode(lookupEventBox(view, EVENT_BOX, week, 4, null, EVENTPATH));
         // Friday
-        controller.assertNode(
-            lookupEventBox(view, EVENT_BOX, week, 6, null, EVENTPATH)
-        );
+        controller.assertNode(lookupEventBox(view, EVENT_BOX, week, 6, null, EVENTPATH));
     }
 
     // Monday, last occurrence
-    controller.assertNode(
-        lookupEventBox(view, EVENT_BOX, startWeek + 3, 2, null, EVENTPATH)
-    );
+    controller.assertNode(lookupEventBox(view, EVENT_BOX, startWeek + 3, 2, null, EVENTPATH));
 
     // Wednesday
     controller.assertNodeNotExist(
         lookupEventBox(view, EVENT_BOX, startWeek + 3, 4, null, EVENTPATH)
     );
 }
 
 function teardownTest(module) {
--- a/calendar/test/mozmill/cal-recurrence/testWeeklyWithExceptionRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testWeeklyWithExceptionRecurrence.js
@@ -1,296 +1,285 @@
 /* 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 MODULE_NAME = "testWeeklyWithExceptionRecurrence";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
-var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
-var CANVAS_BOX, REC_DLG_ACCEPT, REC_DLG_DAYS;
+var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENT_BOX, CANVAS_BOX;
+var DAY_VIEW, WEEK_VIEW, EVENTPATH;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
-var invokeEventDialog, viewForward, deleteCalendars, createCalendar, setData;
+var invokeEventDialog, viewForward, deleteCalendars, createCalendar;
 var menulistSelect;
+var REPEAT_DETAILS, REC_DLG_ACCEPT, REC_DLG_DAYS;
+var helpersForEditUI, setData;
 var plan_for_modal_dialog, wait_for_modal_dialog;
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
 const HOUR = 8;
 const STARTDATE = new Date(2009, 0, 6);
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         TIMEOUT_MODAL_DIALOG,
         CALENDARNAME,
         EVENT_BOX,
         CANVAS_BOX,
         EVENTPATH,
-        REC_DLG_ACCEPT,
-        REC_DLG_DAYS,
+        DAY_VIEW,
+        WEEK_VIEW,
         helpersForController,
         handleOccurrencePrompt,
         switchToView,
         goToDate,
         invokeEventDialog,
         viewForward,
         deleteCalendars,
         createCalendar,
-        setData,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        REPEAT_DETAILS,
+        REC_DLG_ACCEPT,
+        REC_DLG_DAYS,
+        helpersForEditUI,
+        setData
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers")
     );
 
     createCalendar(controller, CALENDARNAME);
 }
 
 function testWeeklyWithExceptionRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 5);
 
-    // create weekly recurring event
+    // Create weekly recurring event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         event.waitForElement(eventid("item-repeat"));
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         menulistSelect(eventid("item-repeat"), "custom", event);
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
-    // move 5th January occurrence to 6th January
-    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH);
-    handleOccurrencePrompt(controller, eventBox, "modify", false, false);
+    // Move 5th January occurrence to 6th January.
+    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    handleOccurrencePrompt(controller, eventBox, "modify", false);
     invokeEventDialog(controller, null, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         setData(event, iframe, { startdate: STARTDATE, enddate: STARTDATE });
         event.click(eventid("button-saveandclose"));
     });
 
-    // change recurrence rule
+    // Change recurrence rule.
     goToDate(controller, 2009, 1, 7);
-    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH);
-    handleOccurrencePrompt(controller, eventBox, "modify", true, false);
+    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    handleOccurrencePrompt(controller, eventBox, "modify", true);
     invokeEventDialog(controller, null, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
-        let { lookup: iframelookup } = helpersForController(iframe);
+        let { iframeLookup } = helpersForEditUI(iframe);
 
         event.waitForElement(eventid("item-repeat"));
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", changeRecurrence);
-        event.click(iframelookup(`
-            /id("calendar-event-dialog-inner")/id("event-grid")/
-            id("event-grid-rows")/id("event-grid-recurrence-row")/
-            id("event-grid-recurrence-picker-box")/id("repeat-deck")/
-            id("repeat-details")/[0]
-        `));
+        event.click(iframeLookup(REPEAT_DETAILS));
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
-    // check two weeks
+    // Check two weeks.
     // day view
     switchToView(controller, "day");
-    let path = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
+    let path = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
 
     goToDate(controller, 2009, 1, 5);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
 
     viewForward(controller, 1);
     let tuesPath = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("day-view")/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
+        ${DAY_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
         anon({"anonid":"daybox"})/[0]/anon({"anonid":"boxstack"})/
         anon({"anonid":"topbox"})/{"flex":"1"}/{"flex":"1"}/[eventIndex]
     `;
 
-    // assert exactly two
+    // Assert exactly two.
     controller.waitForElement(lookup(tuesPath.replace("eventIndex", "0") + EVENTPATH));
     controller.assertNode(lookup(tuesPath.replace("eventIndex", "1") + EVENTPATH));
     controller.assertNodeNotExist(lookup(tuesPath.replace("eventIndex", "2") + EVENTPATH));
 
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
 
     // next week
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
 
     // week view
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 5);
 
     tuesPath = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("week-view")/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
-        anon({"anonid":"daybox"})/[dayIndex]/anon({"anonid":"boxstack"})/
+        ${WEEK_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
+        anon({"anonid":"daybox"})/[2]/anon({"anonid":"boxstack"})/
         anon({"anonid":"topbox"})/{"flex":"1"}/{"flex":"1"}/[eventIndex]
     `;
 
-    // assert exactly two
-    controller.waitForElement(lookup(
-        tuesPath.replace("dayIndex", "2").replace("eventIndex", "0") + EVENTPATH
-    ));
-    controller.assertNode(lookup(
-        tuesPath.replace("dayIndex", "2").replace("eventIndex", "1") + EVENTPATH
-    ));
-    controller.assertNodeNotExist(lookup(
-        tuesPath.replace("dayIndex", "2").replace("eventIndex", "2") + EVENTPATH
-    ));
+    // Assert exactly two.
+    controller.waitForElement(lookup(tuesPath.replace("eventIndex", "0") + EVENTPATH));
+    controller.assertNode(lookup(tuesPath.replace("eventIndex", "1") + EVENTPATH));
+    controller.assertNodeNotExist(lookup(tuesPath.replace("eventIndex", "2") + EVENTPATH));
 
-    // wait for the last occurrence because this appears latest.
-    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 1, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 2, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 4, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 5, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, HOUR));
+    // Wait for the last occurrence because this appears last.
+    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 1, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 2, null));
+    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 4, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 5, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null));
 
     viewForward(controller, 1);
-    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 1, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 2, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 3, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 4, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 5, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, HOUR));
+    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 1, null));
+    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 2, null));
+    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 3, null));
+    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 4, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 5, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null));
 
     // multiweek view
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 5);
     checkMultiWeekView("multiweek");
 
     // month view
     switchToView(controller, "month");
     checkMultiWeekView("month");
 
     // delete event
     switchToView(controller, "day");
     goToDate(controller, 2009, 1, 12);
-    path = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
-    controller.click(lookup(path));
-    handleOccurrencePrompt(controller, eid("day-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(path));
+    path = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    controller.click(path);
+    handleOccurrencePrompt(controller, eid("day-view"), "delete", true);
+    controller.waitForElementNotPresent(path);
 }
 
 function setRecurrence(recurrence) {
     let { lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
     menulistSelect(recid("period-list"), "1", recurrence);
 
     let mon = cal.l10n.getDateFmtString("day.2.Mmm");
     let wed = cal.l10n.getDateFmtString("day.4.Mmm");
     let fri = cal.l10n.getDateFmtString("day.6.Mmm");
 
-    // starting from Monday so it should be checked. We have to wait a little,
+    // Starting from Monday so it should be checked. We have to wait a little,
     // because the checkedstate is set in background by JS.
     recurrence.waitFor(() => {
         return recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
     }, 10000);
-    // check Wednesday and Friday too
+    // Check Wednesday and Friday too.
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${fri}"}`));
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${fri}"}`));
 
-    // close dialog
+    // Close dialog.
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function changeRecurrence(recurrence) {
     let { lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
     menulistSelect(recid("period-list"), "1", recurrence);
 
     let mon = cal.l10n.getDateFmtString("day.2.Mmm");
     let tue = cal.l10n.getDateFmtString("day.3.Mmm");
     let wed = cal.l10n.getDateFmtString("day.4.Mmm");
     let fri = cal.l10n.getDateFmtString("day.6.Mmm");
 
-    // check old rule
-    // starting from Monday so it should be checked. We have to wait a little,
+    // Check old rule.
+    // Starting from Monday so it should be checked. We have to wait a little,
     // because the checkedstate is set in background by JS.
     recurrence.waitFor(() => {
         return recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
     }, 10000);
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${fri}"}`));
 
-    // check Tuesday
+    // Check Tuesday.
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${tue}"}`));
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${tue}"}`));
 
-    // close dialog
+    // Close dialog.
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function checkMultiWeekView(view) {
     let startWeek = view == "multiweek" ? 1 : 2;
     let assertNodeLookup = (...args) => {
         return controller.assertNode(lookupEventBox(...args));
     };
     let assertNodeNotExistLookup = (...args) => {
         return controller.assertNodeNotExist(lookupEventBox(...args));
     };
 
-    // wait for the first items, then check the ones not to be present
-    // assert exactly two
-    controller.waitForElement(
-        lookupEventBox(view, EVENT_BOX, startWeek, 3, HOUR, "/[0]")
-    );
-    assertNodeLookup(view, EVENT_BOX, startWeek, 3, HOUR, "/[1]");
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 3, HOUR, "/[2]");
+    // Wait for the first items, then check the ones not to be present.
+    // ASssert exactly two.
+    controller.waitForElement(lookupEventBox(view, EVENT_BOX, startWeek, 3, null, "/[0]"));
+    assertNodeLookup(view, EVENT_BOX, startWeek, 3, null, "/[1]");
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 3, null, "/[2]");
     // Then check no item on the 5th.
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 2, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 3, HOUR, "/[2]");
-    assertNodeLookup(view, EVENT_BOX, startWeek, 4, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 5, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek, 6, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 7, HOUR, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 2, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 3, null, "/[2]");
+    assertNodeLookup(view, EVENT_BOX, startWeek, 4, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 5, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek, 6, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 7, null, EVENTPATH);
 
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 1, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 2, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 3, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 4, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 5, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 6, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 7, HOUR, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 1, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 2, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 3, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 4, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 5, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 6, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 7, null, EVENTPATH);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/eventDialog/testEventDialog.js
+++ b/calendar/test/mozmill/eventDialog/testEventDialog.js
@@ -1,309 +1,234 @@
 /* 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 MODULE_NAME = "testEventDialog";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
+var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
+var helpersForController, handleOccurrencePrompt, goToDate, lookupEventBox;
+var invokeEventDialog, checkAlarmIcon, deleteCalendars, createCalendar;
+var EVENT_TABPANELS, ATTENDEES_ROW;
+var helpersForEditUI, setData;
 var plan_for_modal_dialog, wait_for_modal_dialog;
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var handleAddingAttachment, handleOccurrencePrompt;
-var goToDate, setData, lookupEventBox;
-var CALENDARNAME, TIMEOUT_MODAL_DIALOG;
 
-var eventTitle = "Event";
-var eventLocation = "Location";
-var eventDescription = "Event Description";
-var eventAttendee = "foo@bar.com";
-var eventUrl = "http://mozilla.org";
+const EVENTTITLE = "Event";
+const EVENTLOCATION = "Location";
+const EVENTDESCRIPTION = "Event Description";
+const EVENTATTENDEE = "foo@bar.com";
+const EVENTURL = "http://mozilla.org/";
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers"));
     ({
+        TIMEOUT_MODAL_DIALOG,
+        CALENDARNAME,
+        EVENTPATH,
+        EVENT_BOX,
         helpersForController,
-        invokeEventDialog,
-        createCalendar,
-        deleteCalendars,
-        handleAddingAttachment,
         handleOccurrencePrompt,
         goToDate,
-        setData,
         lookupEventBox,
-        CALENDARNAME,
-        TIMEOUT_MODAL_DIALOG
+        invokeEventDialog,
+        checkAlarmIcon,
+        deleteCalendars,
+        createCalendar
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        EVENT_TABPANELS,
+        ATTENDEES_ROW,
+        helpersForEditUI,
+        setData
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, CALENDARNAME);
 }
 
 function testEventDialog() {
     let dateFormatter = cal.getDateFormatter();
-    // paths
-    let monthView = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("month-view")
-    `;
-    let eventDialog = `
-        /id("calendar-event-dialog-inner")/id("event-grid")/id("event-grid-rows")/
-    `;
 
-    let eventBox = `
-        ${monthView}/anon({"anonid":"mainbox"})/anon({"anonid":"monthgrid"})/
-        anon({"anonid":"monthgridrows"})/[rowNumber]/[columnNumber]/
-        {"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}/
-        anon({"flex":"1"})/[0]/anon({"anonid":"event-container"})/
-        {"class":"calendar-event-selection"}/anon({"anonid":"eventbox"})/
-        {"class":"calendar-event-details"}
-    `;
-
-    // open month view
-    controller.click(eid("calendar-tab-button"));
+    // Open month view.
     controller.waitThenClick(eid("calendar-month-view-button"));
 
     goToDate(controller, 2009, 1, 1);
-    sleep();
 
-    // create new event
+    // Create new event.
+    controller.mainMenu.click("#ltnNewEvent");
+
+    // Check that the start time is correct -
+    // next full hour except last hour of the day.
     let now = new Date();
     let hour = now.getHours();
     let startHour = hour == 23 ? hour : (hour + 1) % 24;
 
     let nextHour = cal.dtz.now();
     nextHour.resetTo(2009, 0, 1, startHour, 0, 0, cal.dtz.floating);
     let startTime = dateFormatter.formatTime(nextHour);
     nextHour.resetTo(2009, 0, 1, (startHour + 1) % 24, 0, 0, cal.dtz.floating);
     let endTime = dateFormatter.formatTime(nextHour);
 
-    controller.mainMenu.click("#ltnNewEvent");
     invokeEventDialog(controller, null, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
-        let { lookup: iframeLookup, eid: iframeId } = helpersForController(iframe);
+        let { eid: iframeId } = helpersForController(iframe);
+        let { iframeLookup, getDateTimePicker } = helpersForEditUI(iframe);
 
-        let timeInput = `
-            anon({"anonid":"hbox"})/anon({"anonid":"time-picker"})/
-            anon({"class":"timepicker-box-class"})/
-            anon({"class":"timepicker-text-class"})/anon({"flex":"1"})/
-            anon({"anonid":"input"})
-        `;
-        let startTimeInput = iframeLookup(`
-            /id("calendar-event-dialog-inner")/id("event-grid")/id("event-grid-rows")/
-            id("event-grid-startdate-row")/
-            id("event-grid-startdate-picker-box")/id("event-starttime")/${timeInput}
-        `);
+        // First check all standard-values are set correctly.
+        let startTimeInput = getDateTimePicker("STARTTIME");
 
         event.waitForElement(startTimeInput);
         event.assertValue(startTimeInput, startTime);
 
-        // check selected calendar
+        // Check selected calendar.
         event.assertValue(iframeId("item-calendar"), CALENDARNAME);
 
-        // fill in name, location, description
-        setData(event, iframe, {
-            title: eventTitle,
-            location: eventLocation,
-            description: eventDescription,
-            category: "Clients",
-            repeat: "daily"
-        });
-        event.click(iframeId("item-alarm"));
-        event.click(iframeId("reminder-5minutes-menuitem"));
-        event.waitFor(() => iframeId("item-alarm").getNode().label == "5 minutes before");
-        iframeId("item-alarm-menupopup").getNode().hidePopup();
+        // Check standard title.
+        let defTitle = cal.calGetString("calendar", "newEvent");
+        event.assertValue(eventid("item-title"), defTitle);
+
+        // Prepare category.
+        let categories = cal.calGetString("categories", "categories2");
+        // Pick 4th value in a comma-separated list.
+        let category = categories.split(",")[4];
 
-        // add an attendee and verify added
-        event.click(iframeId("event-grid-tab-attendees"));
+        // Fill in the rest of the values.
+        setData(event, iframe, {
+            title: EVENTTITLE,
+            location: EVENTLOCATION,
+            description: EVENTDESCRIPTION,
+            categories: [category],
+            repeat: "daily",
+            reminder: "5minutes",
+            privacy: "private",
+            attachment: { add: EVENTURL },
+            attendees: { add: EVENTATTENDEE }
+        });
 
-        plan_for_modal_dialog("Calendar:EventDialog:Attendees", handleAttendees);
-        event.click(eventid("options-attendees-menuitem"));
-        wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
-        event.assertNode(iframeLookup(`
-            ${eventDialog}/id("event-grid-tabbox")/id("event-grid-tabpanels")/
-            id("event-grid-tabpanel-attendees")/[0]/[1]/id("item-attendees-box")/
-            {"class":"item-attendees-row"}/{"class":"item-attendees-cell"}/
-            {"class":"item-attendees-cell-label","value":"${eventAttendee}"}
-        `));
-        event.click(iframeId("notify-attendees-checkbox"));
+        // Verify attendee added.
+        let attendeeLabel = iframeLookup(`
+            ${ATTENDEES_ROW}/{"class":"item-attendees-cell"}/{"class":"item-attendees-cell-label"}
+        `);
+
+        event.click(eventid("event-grid-tab-attendees"));
+        event.assertValue(attendeeLabel, EVENTATTENDEE);
         event.waitFor(() => !iframeId("notify-attendees-checkbox").getNode().checked);
 
-        // make it private and verify label visible
-        let toolbarbutton = eventid("button-privacy");
-        let rect = toolbarbutton.getNode().getBoundingClientRect();
-        event.click(toolbarbutton, rect.width - 5, 5);
-        event.click(eventid("event-privacy-private-menuitem"));
-        event.waitFor(() => !eventid("status-privacy-private-box").getNode().hasAttribute("collapsed"));
+        // Verify private label visible.
+        event.waitFor(
+            () => !eventid("status-privacy-private-box").getNode().hasAttribute("collapsed")
+        );
         eventid("event-privacy-menupopup").getNode().hidePopup();
 
-        // add attachment and verify added
+        // Add attachment and verify added.
         event.click(iframeId("event-grid-tab-attachments"));
-
-        handleAddingAttachment(event, eventUrl);
-        event.click(eventid("button-url"));
-        wait_for_modal_dialog("commonDialog");
         event.assertNode(iframeLookup(`
-            ${eventDialog}/id("event-grid-tabbox")/id("event-grid-tabpanels")/
-            id("event-grid-tabpanel-attachments")/{"flex":"1"}/
+            ${EVENT_TABPANELS}/id("event-grid-tabpanel-attachments")/{"flex":"1"}/
             id("attachment-link")/[0]/{"value":"mozilla.org"}
         `));
 
         // save
         event.click(eventid("button-saveandclose"));
     });
 
-    // catch and dismiss alarm
+    // Catch and dismiss alarm.
     plan_for_modal_dialog("Calendar:AlarmWindow", alarm => {
         let { lookup: alarmlookup } = helpersForController(alarm);
-        alarm.waitThenClick(alarmlookup('/id("calendar-alarm-dialog")/id("alarm-actionbar")/[1]'));
+        alarm.waitThenClick(alarmlookup(`
+            /id("calendar-alarm-dialog")/id("alarm-actionbar")/[1]`
+        ));
     });
-    wait_for_modal_dialog("Calendar:AlarmWindow");
-
-    // verify event and alarm icon visible every day of the month and check tooltip
-    // 1st January is Thursday so there's three days to check in the first row
-    controller.assertNode(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "4")
-    ));
-    checkIcon(eventBox, "0", "4");
-    checkTooltip(monthView, 0, 4, 1, startTime, endTime);
+    wait_for_modal_dialog("Calendar:AlarmWindow", TIMEOUT_MODAL_DIALOG);
 
-    controller.assertNode(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "5")
-    ));
-    checkIcon(eventBox, "0", "5");
-    checkTooltip(monthView, 0, 5, 2, startTime, endTime);
+    // Verify event and alarm icon visible every day of the month and check tooltip.
+    // 1st January is Thursday so there's three days to check in the first row.
+    let date = 1;
+    for (col = 5; col <= 7; col++) {
+        controller.waitForElement(lookupEventBox("month", EVENT_BOX, 1, col, null, EVENTPATH));
+        checkAlarmIcon(controller, "month", 1, col);
+        checkTooltip(1, col, date, startTime, endTime);
+        date++;
+    }
 
-    controller.assertNode(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "6")
-    ));
-    checkIcon(eventBox, "0", "6");
-    checkTooltip(monthView, 0, 6, 3, startTime, endTime);
-
-    // 31st of January is Saturday so there's four more full rows to check
-    let date = 4;
-    for (let row = 1; row < 5; row++) {
-        for (let col = 0; col < 7; col++) {
-            controller.assertNode(lookup(
-                eventBox.replace("rowNumber", row).replace("columnNumber", col)
-            ));
-            checkIcon(eventBox, row, col);
-            checkTooltip(monthView, row, col, date, startTime, endTime);
+    // 31st of January is Saturday so there's four more full rows to check.
+    for (let row = 2; row <= 5; row++) {
+        for (let col = 1; col <= 7; col++) {
+            controller.assertNode(lookupEventBox("month", EVENT_BOX, row, col, null, EVENTPATH));
+            checkAlarmIcon(controller, "month", row, col);
+            checkTooltip(row, col, date, startTime, endTime);
             date++;
         }
     }
 
-    // delete and verify deleted 2nd Jan
-    controller.click(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "5")
-    ));
+    // Delete and verify deleted 2nd Jan.
+    controller.click(lookupEventBox("month", EVENT_BOX, 1, 6, null, EVENTPATH));
     let elemToDelete = eid("month-view");
-    handleOccurrencePrompt(controller, elemToDelete, "delete", false, false);
-    controller.waitForElementNotPresent(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "5")
-    ));
+    handleOccurrencePrompt(controller, elemToDelete, "delete", false);
+    controller.waitForElementNotPresent(lookupEventBox("month", EVENT_BOX, 1, 6, null, EVENTPATH));
 
-    // verify all others still exist
-    controller.assertNode(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "4")
-    ));
-    controller.assertNode(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "6")
-    ));
+    // Verify all others still exist.
+    controller.assertNode(lookupEventBox("month", EVENT_BOX, 1, 5, null, EVENTPATH));
+    controller.assertNode(lookupEventBox("month", EVENT_BOX, 1, 7, null, EVENTPATH));
 
-    for (let row = 1; row < 5; row++) {
-        for (let col = 0; col < 7; col++) {
-            controller.assertNode(lookup(
-                eventBox.replace("rowNumber", row).replace("columnNumber", col)
-            ));
+    for (let row = 2; row <= 5; row++) {
+        for (let col = 1; col <= 7; col++) {
+            controller.assertNode(lookupEventBox("month", EVENT_BOX, row, col, null, EVENTPATH));
         }
     }
 
-    // delete series by deleting 3rd January and confirming to delete all
-    controller.click(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "6")
-    ));
+    // Delete series by deleting 3rd January and confirming to delete all.
+    controller.click(lookupEventBox("month", EVENT_BOX, 1, 7, null, EVENTPATH));
     elemToDelete = eid("month-view");
-    handleOccurrencePrompt(controller, elemToDelete, "delete", true, false);
+    handleOccurrencePrompt(controller, elemToDelete, "delete", true);
 
-    // verify all deleted
-    controller.waitForElementNotPresent(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "4")
-    ));
-    controller.assertNodeNotExist(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "5")
-    ));
-    controller.assertNodeNotExist(lookup(
-        eventBox.replace("rowNumber", "0").replace("columnNumber", "6")
-    ));
+    // Verify all deleted.
+    controller.waitForElementNotPresent(lookupEventBox("month", EVENT_BOX, 1, 5, null, EVENTPATH));
+    controller.assertNodeNotExist(lookupEventBox("month", EVENT_BOX, 1, 6, null, EVENTPATH));
+    controller.assertNodeNotExist(lookupEventBox("month", EVENT_BOX, 1, 7, null, EVENTPATH));
 
-    for (let row = 1; row < 5; row++) {
-        for (let col = 0; col < 7; col++) {
-            controller.assertNodeNotExist(lookup(
-                eventBox.replace("rowNumber", row).replace("columnNumber", col)
+    for (let row = 2; row <= 5; row++) {
+        for (let col = 1; col <= 7; col++) {
+            controller.assertNodeNotExist(lookupEventBox(
+                "month", EVENT_BOX, row, col, null, EVENTPATH
             ));
         }
     }
 }
 
-function handleAttendees(attendees) {
-    let { lookup: attendeeslookup } = helpersForController(attendees);
-
-    let input = attendeeslookup(`
-        /id("calendar-event-dialog-attendees-v2")/{"flex":"1"}/
-        id("attendees-container")/id("attendees-list")/[1]/[2]/[0]
-    `);
-    attendees.waitForElement(input);
-    attendees.type(input, eventAttendee);
-    attendees.click(attendeeslookup(`
-        /id("calendar-event-dialog-attendees-v2")/anon({"anonid":"buttons"})/
-        {"dlgtype":"accept"}
-    `));
-}
-
-function checkIcon(eventBox, row, col) {
-    let icon = lookup((`
-        ${eventBox}/anon({"anonid":"category-box-stack"})/
-        anon({"align": "center"})/anon({"class":"alarm-icons-box"})/
-        anon({"class": "reminder-icon"})
-    `).replace("rowNumber", row).replace("columnNumber", col));
-
-    controller.assertJS(icon.getNode().getAttribute("value") == "DISPLAY");
-}
-
-function checkTooltip(monthView, row, col, date, startTime, endTime) {
-    let item = lookupEventBox(
-        "month", null, row + 1, col + 1, null,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    );
+function checkTooltip(row, col, date, startTime, endTime) {
+    let item = lookupEventBox("month", null, row, col, null, EVENTPATH);
 
     let toolTip = '/id("messengerWindow")/id("calendar-popupset")/id("itemTooltip")';
     let toolTipNode = lookup(toolTip).getNode();
     toolTipNode.ownerGlobal.onMouseOverItem({ currentTarget: item.getNode() });
 
-    // check title
+    // Check title.
     let toolTipGrid = toolTip + '/{"class":"tooltipBox"}/{"class":"tooltipHeaderGrid"}/';
     let eventName = lookup(`${toolTipGrid}/[1]/[0]/[1]`);
-    controller.assert(() => eventName.getNode().textContent == eventTitle);
+    controller.assert(() => eventName.getNode().textContent == EVENTTITLE);
 
-    // check date and time
+    // Check date and time.
     let dateTime = lookup(`${toolTipGrid}/[1]/[2]/[1]`);
 
     let formatter = new Services.intl.DateTimeFormat(undefined, { dateStyle: "full" });
     let startDate = formatter.format(new Date(2009, 0, date));
 
     controller.assert(() => {
         let text = dateTime.getNode().textContent;
+        dump(`${text} / ${startDate} ${startTime} -\n`);
         return text.includes(`${startDate} ${startTime} – `);
     });
 
     // This could be on the next day if it is 00:00.
     controller.assert(() => dateTime.getNode().textContent.endsWith(endTime));
 }
 
 function teardownTest(module) {
--- a/calendar/test/mozmill/eventDialog/testEventDialogModificationPrompt.js
+++ b/calendar/test/mozmill/eventDialog/testEventDialogModificationPrompt.js
@@ -1,153 +1,216 @@
 /* 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 MODULE_NAME = "testEventDialogModificationPrompt";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers",
+    "window-helpers", "folder-display-helpers"];
+
+var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
-var helpersForController, invokeEventDialog, createCalendar;
-var deleteCalendars, switchToView, goToDate, setData;
-var CALENDARNAME, EVENT_BOX, CANVAS_BOX;
+var CALENDARNAME, EVENT_BOX, CANVAS_BOX, EVENTPATH;
+var helpersForController, invokeEventDialog, createCalendar, deleteCalendars, goToDate;
+var setData;
+var plan_for_modal_dialog, wait_for_modal_dialog;
+var mark_failure;
 
+const TIMEOUT_COMMON_DIALOG = 3000;
 var savePromptAppeared = false;
+var failPoints = {
+    first: "no change",
+    second: "change all and back",
+    third: ["1st pass", "2nd pass", "3rd pass", "4th pass", "5th pass"]
+};
+
 var { date1, date2, date3, data, newlines } = setupData();
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        EVENT_BOX,
+        CANVAS_BOX,
+        EVENTPATH,
         helpersForController,
         invokeEventDialog,
         createCalendar,
         deleteCalendars,
-        switchToView,
-        goToDate,
-        setData,
-        CALENDARNAME,
-        EVENT_BOX,
-        CANVAS_BOX,
+        goToDate
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({ setData } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
+    ({ plan_for_modal_dialog, wait_for_modal_dialog } =
+        collector.getModule("window-helpers"));
+
+    ({ mark_failure } =
+        collector.getModule("folder-display-helpers"));
+
     createCalendar(controller, CALENDARNAME);
 }
 
-// Test that closing an event dialog with no changes does not prompt for save
+// Test that closing an event dialog with no changes does not prompt for save.
 function testEventDialogModificationPrompt() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 1);
 
-    // create new event
-    let eventbox = lookupEventBox("day", CANVAS_BOX, null, 1, 8);
-    invokeEventDialog(controller, eventbox, (event, iframe) => {
+    let createbox = lookupEventBox("day", CANVAS_BOX, null, 1, 8);
+    let eventbox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+
+    // Create new event.
+    invokeEventDialog(controller, createbox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        // enter first set of data
+        let categories = cal.calGetString("categories", "categories2").split(",");
+        data[0].categories.push(categories[0]);
+        data[1].categories.push(categories[1], categories[2]);
+
+        // Enter first set of data.
         setData(event, iframe, data[0]);
 
         // save
         event.click(eventid("button-saveandclose"));
     });
 
-    eventbox = lookupEventBox("day", EVENT_BOX, null, 1, 8, '/{"tooltip":"itemTooltip"}');
     invokeEventDialog(controller, eventbox, (event, iframe) => {
-        // open, but change nothing
-        // escape the event window, there should be no prompt to save event
+        // Open, but change nothing.
+        plan_for_modal_dialog("commonDialog", handleSavePrompt);
+
+        // Escape the event window, there should be no prompt to save event.
         event.keypress(null, "VK_ESCAPE", {});
+        try {
+            wait_for_modal_dialog("commonDialog", TIMEOUT_COMMON_DIALOG);
+        } catch (e) {
+            failPoints.first = "";
+        }
     });
 
     // open
-    eventbox = lookupEventBox("day", EVENT_BOX, null, 1, 8, '/{"tooltip":"itemTooltip"}');
     invokeEventDialog(controller, eventbox, (event, iframe) => {
-        // change all values
+        // Change all values.
         setData(event, iframe, data[1]);
 
-        // edit all values back to original
+        // Edit all values back to original.
         setData(event, iframe, data[0]);
 
-        // escape the event window, there should be no prompt to save event
+        plan_for_modal_dialog("commonDialog", handleSavePrompt);
+
+        // Escape the event window, there should be no prompt to save event.
         event.keypress(null, "VK_ESCAPE", {});
+        try {
+            wait_for_modal_dialog("commonDialog", TIMEOUT_COMMON_DIALOG);
+        } catch (e) {
+            failPoints.second = "";
+        }
     });
 
-    // delete event
-    controller.click(lookupEventBox("day", EVENT_BOX, null, 1, 8, '/{"tooltip":"itemTooltip"}'));
+    // Delete event.
+    controller.click(eventbox);
     controller.keypress(eid("day-view"), "VK_DELETE", {});
-    controller.waitForElementNotPresent(lookupEventBox("day", EVENT_BOX, null, 1, 8));
+    controller.waitForElementNotPresent(eventbox);
 
     for (let i = 0; i < newlines.length; i++) {
         // test set i
-        eventbox = lookupEventBox("day", CANVAS_BOX, null, 1, 8);
-        invokeEventDialog(controller, eventbox, (event, iframe) => {
+        invokeEventDialog(controller, createbox, (event, iframe) => {
             let { eid: eventid } = helpersForController(event);
+
             setData(event, iframe, newlines[i]);
             event.click(eventid("button-saveandclose"));
         });
 
-        // open and close
-        eventbox = lookupEventBox("day", EVENT_BOX, null, 1, 8, '/{"tooltip":"itemTooltip"}');
+        // Open and close.
         invokeEventDialog(controller, eventbox, (event, iframe) => {
             setData(event, iframe, newlines[i]);
+            plan_for_modal_dialog("commonDialog", handleSavePrompt);
             event.keypress(null, "VK_ESCAPE", {});
+            try {
+                wait_for_modal_dialog("commonDialog", TIMEOUT_COMMON_DIALOG);
+            } catch (e) {
+                failPoints.third[i] = "";
+            }
         });
 
-        // delete it
-        // XXX somehow the event is selected at this point, this didn't use to
-        // be the case and can't be reproduced manually
+        // Delete it.
+        // XXX Somehow the event is selected at this point, this didn't use to
+        // be the case and can't be reproduced manually.
         controller.keypress(eid("day-view"), "VK_DELETE", {});
-        controller.waitForElementNotPresent(lookupEventBox("day", EVENT_BOX, null, 1, 8));
+        controller.waitForElementNotPresent(eventbox);
     }
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
     if (savePromptAppeared) {
-        controller.assertJS('"Prompt appeared" == "Prompt didn\'t appear."');
+        mark_failure(["Save Prompt unexpectedly appeared on: ", failPoints.first,
+            failPoints.second, failPoints.third]);
     }
 }
 
+function handleSavePrompt(controller) {
+    let { lookup: cdlglookup } = helpersForController(controller);
+    // Unexpected prompt, thus the test has already failed.
+    // Can't trigger a failure though, because the following click wouldn't
+    // be executed. So remembering it.
+    savePromptAppeared = true;
+
+    // application close is blocked without it
+    controller.waitThenClick(cdlglookup(`
+        /id("commonDialog")/anon({"anonid":"buttons"})/{"dlgtype":"extra1"}
+    `));
+}
+
 function setupData() {
     return {
         date1: new Date(2009, 0, 1, 8, 0),
         date2: new Date(2009, 0, 2, 9, 0),
         date3: new Date(2009, 0, 3, 10, 0),
         data: [{
             title: "title1",
             location: "location1",
-            category: "Anniversary",
             description: "description1",
+            categories: [],
             allday: false,
             startdate: date1,
             starttime: date1,
             enddate: date2,
             endtime: date2,
             repeat: "none",
+            reminder: "none",
             priority: "normal",
             privacy: "public",
             status: "confirmed",
             freebusy: "busy",
-            timezone: true,
+            timezonedisplay: true,
+            attachment: { add: "http://mozilla.org" },
+            // Test fails when changing attendees, therefore leaving out for now.
+            // attendees: { add: "foo@bar.de,foo@bar.com" }
         }, {
             title: "title2",
             location: "location2",
-            category: "Birthday",
             description: "description2",
+            categories: [],
             allday: true,
             startdate: date2,
             starttime: date2,
             enddate: date3,
             endtime: date3,
             repeat: "daily",
+            reminder: "5minutes",
             priority: "high",
             privacy: "private",
             status: "tentative",
             freebusy: "free",
-            timezone: true,
+            timezonedisplay: false,
+            attachment: { remove: "mozilla.org" },
+            // attendees: { remove: "foo@bar.de,foo@bar.com" }
         }],
         newlines: [
             { title: "title", description: "  test spaces  " },
             { title: "title", description: "\ntest newline\n" },
             { title: "title", description: "\rtest \\r\r" },
             { title: "title", description: "\r\ntest \\r\\n\r\n" },
             { title: "title", description: "\ttest \\t\t" }
         ]
--- a/calendar/test/mozmill/eventDialog/testEventDialogSize.js
+++ b/calendar/test/mozmill/eventDialog/testEventDialogSize.js
@@ -1,32 +1,34 @@
 /* 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 MODULE_NAME = "testEventDialogSize";
 var RELATIVE_ROOT = "../shared-modules";
 var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
 
 var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
 var CALENDARNAME;
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
+const SMALL_TOLERANCE = 5;
 const LARGE_TOLERANCE = 10;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         helpersForController,
         invokeEventDialog,
         createCalendar,
         deleteCalendars,
         CALENDARNAME,
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
     createCalendar(controller, CALENDARNAME);
 }
 
 function testEventDialog() {
     dump("#ltnNewEvent click\n");
     controller.mainMenu.click("#ltnNewEvent");
@@ -131,18 +133,18 @@ function teardownTest(module) {
 
 // Check the dialog is resized large enough to hold the iframe.
 function checkLargeEnough(outer, inner) {
     let { eid: outerId } = helpersForController(outer);
 
     let iframeNode = outerId("lightning-item-panel-iframe").getNode();
     let { scrollWidth, scrollHeight } = inner.window.document.documentElement;
     outer.waitFor(() => {
-        return (iframeNode.clientWidth + 1 >= scrollWidth) &&
-            (iframeNode.clientHeight + 1 >= scrollHeight);
+        return (iframeNode.clientWidth + SMALL_TOLERANCE >= scrollWidth) &&
+            (iframeNode.clientHeight + SMALL_TOLERANCE >= scrollHeight);
     });
     dump(`Dialog is ${outer.window.outerWidth} by ${outer.window.outerHeight}\n`);
 }
 
 function getPersistedValue(type, which) {
     return Services.xulStore.getValue("chrome://calendar/content/calendar-event-dialog.xul",
                                       `calendar-${type}-dialog`, which);
 }
--- a/calendar/test/mozmill/eventDialog/testUTF8.js
+++ b/calendar/test/mozmill/eventDialog/testUTF8.js
@@ -1,85 +1,77 @@
 /* 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 MODULE_NAME = "testUTF8";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
-
-var helpersForController, invokeEventDialog, createCalendar;
-var deleteCalendars, switchToView, setData;
-var EVENT_BOX, CANVAS_BOX;
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers"];
 
 ChromeUtils.import("resource://gre/modules/Preferences.jsm");
 
+var EVENT_BOX, CANVAS_BOX;
+var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
+var setData;
+
 var UTF8STRING = " 💣 💥  ☣  ";
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        EVENT_BOX,
+        CANVAS_BOX,
         helpersForController,
         invokeEventDialog,
         createCalendar,
-        deleteCalendars,
-        switchToView,
-        setData,
-        EVENT_BOX,
-        CANVAS_BOX
+        deleteCalendars
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({ setData } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, UTF8STRING);
     Preferences.set("calendar.categories.names", UTF8STRING);
 }
 
 function testUTF8() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
-
-    // create new event
+    // Create new event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, 8);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
-        let { lookup: iframeLookup, eid: iframeId } = helpersForController(iframe);
 
-        // fill in name, location, description
-        setData(event, iframe, { title: UTF8STRING, location: UTF8STRING, description: UTF8STRING });
-
-        let menuitem = iframeLookup(`
-            /id("calendar-event-dialog-inner")/id("event-grid")/
-            id("event-grid-rows")/id("event-grid-category-color-row")/
-            id("event-grid-category-box")/id("item-categories")/
-            id("item-categories-popup")/[2]
-        `);
-
-        event.click(iframeId("item-categories"));
-        menuitem.getNode().click();
-        menuitem.getNode().setAttribute("checked", "true"); // When in doubt, cheat.
-        event.waitFor(() => iframeId("item-categories").getNode().label == UTF8STRING);
-        iframeId("item-categories-popup").getNode().hidePopup();
+        // Fill in name, location, description.
+        setData(event, iframe, {
+            title: UTF8STRING,
+            location: UTF8STRING,
+            description: UTF8STRING,
+            categories: [UTF8STRING]
+        });
 
         // save
         event.click(eventid("button-saveandclose"));
     });
 
     // open
     let eventPath = `/{"tooltip":"itemTooltip","calendar":"${UTF8STRING.toLowerCase()}"}`;
-    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, 8, eventPath);
+    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, null, eventPath);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: iframeId } = helpersForController(iframe);
 
-        // check values
+        // Check values.
         event.assertValue(iframeId("item-title"), UTF8STRING);
         event.assertValue(iframeId("item-location"), UTF8STRING);
         event.assertValue(iframeId("item-description"), UTF8STRING);
-        event.assert(() => iframeId("item-categories").getNode().querySelector(`menuitem[label="${UTF8STRING}"][checked]`));
+        event.assert(() => iframeId("item-categories").getNode().querySelector(`
+            menuitem[label="${UTF8STRING}"][checked]
+        `));
 
-        // escape the event window
+        // Escape the event window.
         event.keypress(null, "VK_ESCAPE", {});
     });
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, UTF8STRING);
     Preferences.reset("calendar.categories.names");
 }
--- a/calendar/test/mozmill/invitations/test-imip-bar-eml.js
+++ b/calendar/test/mozmill/invitations/test-imip-bar-eml.js
@@ -3,24 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * Test that the IMIP bar behaves properly for eml files.
  */
 
 // make -C calendar/test/mozmill SOLO_TEST=invitations/test-imip-bar-eml.js mozmill-one
 
-var MODULE_NAME = "invitations";
+var MODULE_NAME = "testInvitations";
 
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = [
-    "folder-display-helpers",
-    "window-helpers",
-    "notificationbox-helpers"
-];
+var MODULE_REQUIRES = ["folder-display-helpers", "window-helpers", "notificationbox-helpers"];
 
 var os = {};
 ChromeUtils.import("chrome://mozmill/content/stdlib/os.js", os);
 
 function setupModule(module) {
     for (let dep of MODULE_REQUIRES) {
         collector.getModule(dep).installInto(module);
     }
--- a/calendar/test/mozmill/recurrenceRotated/testAnnualRecurrence.js
+++ b/calendar/test/mozmill/recurrenceRotated/testAnnualRecurrence.js
@@ -1,13 +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/. */
 
-var MODULE_NAME = "testAnnualRecurrence";
+var MODULE_NAME = "testAnnualRecurrenceRotated";
 var RELATIVE_ROOT = "../shared-modules";
 var MODULE_REQUIRES = ["calendar-utils"];
 
 var CALENDARNAME, EVENTPATH, ALLDAY;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
 var invokeEventDialog, deleteCalendars, createCalendar, menulistSelect;
 
 const STARTYEAR = 1950;
@@ -23,81 +23,69 @@ function setupModule(module) {
         handleOccurrencePrompt,
         switchToView,
         goToDate,
         invokeEventDialog,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
     createCalendar(controller, CALENDARNAME);
+    // Rotate view.
+    controller.mainMenu.click("#ltnViewRotated");
+    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
 }
 
 function testAnnualRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    sleep();
-
-    switchToView(controller, "day");
     goToDate(controller, STARTYEAR, 1, 1);
 
-    // rotate view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
-
-    // create yearly recurring all-day event
+    // Create yearly recurring all-day event.
     let eventBox = lookupEventBox("day", ALLDAY, null, 1, null);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         menulistSelect(eventid("item-repeat"), "yearly", event);
         event.click(eventid("button-saveandclose"));
     });
 
     let checkYears = [STARTYEAR, STARTYEAR + 1, EPOCH - 1, EPOCH, EPOCH + 1];
     for (let year of checkYears) {
         goToDate(controller, year, 1, 1);
         let date = new Date(year, 0, 1);
         let column = date.getDay() + 1;
 
         // day view
         switchToView(controller, "day");
-        controller.waitForElement(
-            lookupEventBox("day", ALLDAY, null, 1, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("day", ALLDAY, null, 1, null, EVENTPATH));
 
         // week view
         switchToView(controller, "week");
-        controller.waitForElement(
-            lookupEventBox("week", ALLDAY, null, column, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", ALLDAY, null, column, null, EVENTPATH));
 
         // multiweek view
         switchToView(controller, "multiweek");
-        controller.waitForElement(
-            lookupEventBox("multiweek", ALLDAY, 1, column, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("multiweek", ALLDAY, 1, column, null, EVENTPATH));
 
         // month view
         switchToView(controller, "month");
-        controller.waitForElement(
-            lookupEventBox("month", ALLDAY, 1, column, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("month", ALLDAY, 1, column, null, EVENTPATH));
     }
 
-    // delete event
+    // Delete event.
     goToDate(controller, checkYears[0], 1, 1);
     switchToView(controller, "day");
     let box = getEventBoxPath("day", ALLDAY, null, 1, null) + EVENTPATH;
     controller.click(lookup(box));
-    handleOccurrencePrompt(controller, eid("day-view"), "delete", true, false);
+    handleOccurrencePrompt(controller, eid("day-view"), "delete", true);
     controller.waitForElementNotPresent(lookup(box));
-
-    // reset view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
+    // Reset view.
+    if (eid("day-view").getNode().orient == "horizontal") {
+        controller.mainMenu.click("#ltnViewRotated");
+    }
+    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
 }
--- a/calendar/test/mozmill/recurrenceRotated/testBiweeklyRecurrence.js
+++ b/calendar/test/mozmill/recurrenceRotated/testBiweeklyRecurrence.js
@@ -1,13 +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/. */
 
-var MODULE_NAME = "testBiweeklyRecurrence";
+var MODULE_NAME = "testBiweeklyRecurrenceRotated";
 var RELATIVE_ROOT = "../shared-modules";
 var MODULE_REQUIRES = ["calendar-utils"];
 
 var CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
 var invokeEventDialog, viewForward, createCalendar, deleteCalendars, menulistSelect;
 
 const HOUR = 8;
@@ -24,98 +24,92 @@ function setupModule(module) {
         switchToView,
         goToDate,
         invokeEventDialog,
         viewForward,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
     createCalendar(controller, CALENDARNAME);
+    // rotate view
+    controller.mainMenu.click("#ltnViewRotated");
+    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
 }
 
 function testBiweeklyRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 31);
 
-    // rotate view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
-
-    // create biweekly event
+    // Create biweekly event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         menulistSelect(eventid("item-repeat"), "bi.weekly", event);
         event.click(eventid("button-saveandclose"));
     });
 
-    // check day view
+    // Check day view.
     for (let i = 0; i < 4; i++) {
-        controller.waitForElement(
-            lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH));
         viewForward(controller, 14);
     }
 
-    // check week view
+    // Check week view.
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 31);
 
     for (let i = 0; i < 4; i++) {
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, 7, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH));
         viewForward(controller, 2);
     }
 
-    // check multiweek view
+    // Check multiweek view.
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 31);
 
-    // always two occurrences in view, 1st and 3rd or 2nd and 4th week
+    // Always two occurrences in view, 1st and 3rd or 2nd and 4th week.
     for (let i = 0; i < 5; i++) {
         controller.waitForElement(
             lookupEventBox("multiweek", EVENT_BOX, i % 2 + 1, 7, null, EVENTPATH)
         );
         controller.assertNode(
             lookupEventBox("multiweek", EVENT_BOX, i % 2 + 3, 7, null, EVENTPATH)
         );
         viewForward(controller, 1);
     }
 
-    // check month view
+    // Check month view.
     switchToView(controller, "month");
     goToDate(controller, 2009, 1, 31);
 
     // January
     controller.waitForElement(lookupEventBox("month", EVENT_BOX, 5, 7, null, EVENTPATH));
     viewForward(controller, 1);
 
     // February
     controller.waitForElement(lookupEventBox("month", EVENT_BOX, 2, 7, null, EVENTPATH));
     controller.assertNode(lookupEventBox("month", EVENT_BOX, 4, 7, null, EVENTPATH));
     viewForward(controller, 1);
 
     // March
     controller.waitForElement(lookupEventBox("month", EVENT_BOX, 2, 7, null, EVENTPATH));
     controller.assertNode(lookupEventBox("month", EVENT_BOX, 4, 7, null, EVENTPATH));
 
-    // delete event
+    // Delete event.
     let box = lookupEventBox("month", EVENT_BOX, 4, 7, null, EVENTPATH);
     controller.click(box);
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", true, false);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", true);
     controller.waitForElementNotPresent(box);
-
-    // reset view
-    switchToView(controller, "day");
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
+    // Reset view.
+    switchToView(controller, "day");
+    if (eid("day-view").getNode().orient == "horizontal") {
+        controller.mainMenu.click("#ltnViewRotated");
+    }
+    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
 }
--- a/calendar/test/mozmill/recurrenceRotated/testDailyRecurrence.js
+++ b/calendar/test/mozmill/recurrenceRotated/testDailyRecurrence.js
@@ -1,20 +1,21 @@
 /* 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 MODULE_NAME = "testDailyRecurrence";
+var MODULE_NAME = "testDailyRecurrenceRotated";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers"];
 
 var CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
 var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
 var switchToView, goToDate, viewForward, viewBack, handleOccurrencePrompt;
 var menulistSelect;
+var setData;
 
 const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         CALENDARNAME,
         EVENTPATH,
@@ -26,197 +27,178 @@ function setupModule(module) {
         goToDate,
         invokeEventDialog,
         viewForward,
         viewBack,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({ setData } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, CALENDARNAME);
+
+    // Rotate view.
+    controller.mainMenu.click("#ltnViewRotated");
+    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
 }
 
 function testDailyRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 1);
 
-    // rotate view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
-
-    // create daily event
+    // Create daily event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        menulistSelect(eventid("item-repeat"), "daily", event);
+        setData(event, iframe, { repeat: "daily", repeatuntil: new Date(2009, 2, 20) });
         event.click(eventid("button-saveandclose"));
     });
 
-    // check day view for 7 days
-    let daybox = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR, null) + EVENTPATH;
-    controller.waitForElement(lookup(daybox));
+    // Check day view for 7 days.
+    let daybox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    controller.waitForElement(daybox);
 
     for (let day = 1; day <= 7; day++) {
-        controller.waitForElement(lookup(daybox));
+        controller.waitForElement(daybox);
         viewForward(controller, 1);
     }
 
-    // check week view for 2 weeks
+    // Check week view for 2 weeks.
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 1);
 
     for (let day = 5; day <= 7; day++) {
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, 1, day, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, 1, day, null, EVENTPATH));
     }
 
     viewForward(controller, 1);
 
     for (let day = 1; day <= 7; day++) {
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, 2, day, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, 2, day, null, EVENTPATH));
     }
 
-    // check multiweek view for 4 weeks
+    // Check multiweek view for 4 weeks.
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 1);
 
     for (let day = 5; day <= 7; day++) {
-        controller.waitForElement(
-            lookupEventBox("multiweek", EVENT_BOX, 1, day, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("multiweek", EVENT_BOX, 1, day, null, EVENTPATH));
     }
 
     for (let week = 2; week <= 4; week++) {
         for (let day = 1; day <= 7; day++) {
             controller.waitForElement(
-                lookupEventBox("multiweek", EVENT_BOX, week, day, HOUR, EVENTPATH)
+                lookupEventBox("multiweek", EVENT_BOX, week, day, null, EVENTPATH)
             );
         }
     }
-
-    // check month view for all 5 weeks
+    // Check month view for all 5 weeks.
     switchToView(controller, "month");
     goToDate(controller, 2009, 1, 1);
 
     for (let day = 5; day <= 7; day++) {
-        controller.waitForElement(
-            lookupEventBox("month", EVENT_BOX, 1, day, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("month", EVENT_BOX, 1, day, null, EVENTPATH));
     }
 
     for (let week = 2; week <= 5; week++) {
         for (let day = 1; day <= 7; day++) {
-            controller.assertNode(
-                lookupEventBox("month", EVENT_BOX, week, day, null, EVENTPATH)
-            );
+            controller.assertNode(lookupEventBox("month", EVENT_BOX, week, day, null, EVENTPATH));
         }
     }
 
-    // delete 3rd January occurrence
-    let saturday = getEventBoxPath("month", EVENT_BOX, 1, 7, null) + EVENTPATH;
-    controller.click(lookup(saturday));
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", false, false);
+    // Delete 3rd January occurrence.
+    let saturday = lookupEventBox("month", EVENT_BOX, 1, 7, null, EVENTPATH);
+    controller.click(saturday);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", false);
 
-    // verify in all views
-    controller.waitForElementNotPresent(lookup(saturday));
+    // Verify in all views.
+    controller.waitForElementNotPresent(saturday);
 
     switchToView(controller, "multiweek");
-    controller.assertNodeNotExist(
-        lookupEventBox("multiweek", EVENT_BOX, 1, 7, null, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("multiweek", EVENT_BOX, 1, 7, null, EVENTPATH));
 
     switchToView(controller, "week");
-    controller.assertNodeNotExist(
-        lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH));
 
     switchToView(controller, "day");
-    controller.assertNodeNotExist(
-        lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH));
 
-    // go to previous day to edit event to occur only on weekdays
+    // Go to previous day to edit event to occur only on weekdays.
     viewBack(controller, 1);
 
-    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH);
-    handleOccurrencePrompt(controller, eventBox, "modify", true, false);
+    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    handleOccurrencePrompt(controller, eventBox, "modify", true);
     invokeEventDialog(controller, null, (event, iframe) => {
         let { eid: eventid, sleep: eventsleep } = helpersForController(event);
 
         menulistSelect(eventid("item-repeat"), "every.weekday", event);
         eventsleep();
         event.click(eventid("button-saveandclose"));
     });
 
-    // check day view for 7 days
-    let day = getEventBoxPath("day", EVENT_BOX, null, 1, null) + EVENTPATH;
+    // Check day view for 7 days.
+    let day = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
     let dates = [
         [2009, 1, 3],
         [2009, 1, 4]
     ];
     for (let [y, m, d] of dates) {
         goToDate(controller, y, m, d);
-        controller.assertNodeNotExist(lookup(day));
+        controller.assertNodeNotExist(day);
     }
 
-    // check week view for 2 weeks
+    // Check week view for 2 weeks.
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 1);
 
     for (let i = 0; i <= 1; i++) {
         controller.waitForElementNotPresent(
             lookupEventBox("week", EVENT_BOX, null, 1, null, EVENTPATH)
         );
-        controller.assertNodeNotExist(
-            lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH)
-        );
+        controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH));
         viewForward(controller, 1);
     }
 
-    // check multiweek view for 4 weeks
+    // Check multiweek view for 4 weeks.
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 1);
 
     for (let i = 1; i <= 4; i++) {
         controller.waitForElementNotPresent(
             lookupEventBox("multiweek", EVENT_BOX, i, 1, null, EVENTPATH)
         );
         controller.assertNodeNotExist(
             lookupEventBox("multiweek", EVENT_BOX, i, 7, null, EVENTPATH)
         );
     }
 
-    // check month view for all 5 weeks
+    // Check month view for all 5 weeks.
     switchToView(controller, "month");
     goToDate(controller, 2009, 1, 1);
 
     for (let i = 1; i <= 5; i++) {
         controller.waitForElementNotPresent(
             lookupEventBox("month", EVENT_BOX, i, 1, null, EVENTPATH)
         );
-        controller.assertNodeNotExist(
-            lookupEventBox("month", EVENT_BOX, i, 7, null, EVENTPATH)
-        );
+        controller.assertNodeNotExist(lookupEventBox("month", EVENT_BOX, i, 7, null, EVENTPATH));
     }
 
-    // delete event
-    day = getEventBoxPath("month", EVENT_BOX, 1, 5, null) + EVENTPATH;
-    controller.click(lookup(day));
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(day));
-
-    // reset view
-    switchToView(controller, "day");
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
+    // Delete event.
+    day = lookupEventBox("month", EVENT_BOX, 1, 5, null, EVENTPATH);
+    controller.click(day);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", true);
+    controller.waitForElementNotPresent(day);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
+    // Reset view.
+    switchToView(controller, "day");
+    if (eid("day-view").getNode().orient == "horizontal") {
+        controller.mainMenu.click("#ltnViewRotated");
+    }
+    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
 }
--- a/calendar/test/mozmill/recurrenceRotated/testLastDayOfMonthRecurrence.js
+++ b/calendar/test/mozmill/recurrenceRotated/testLastDayOfMonthRecurrence.js
@@ -1,133 +1,124 @@
 /* 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 MODULE_NAME = "testLastDayOfMonthRecurrence";
+var MODULE_NAME = "testLastDayOfMonthRecurrenceRotated";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
-var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
-var CANVAS_BOX, REC_DLG_ACCEPT;
+var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
 var invokeEventDialog, deleteCalendars, createCalendar, menulistSelect;
+var REC_DLG_ACCEPT;
 var plan_for_modal_dialog, wait_for_modal_dialog;
 
 const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         TIMEOUT_MODAL_DIALOG,
         CALENDARNAME,
         EVENTPATH,
         EVENT_BOX,
         CANVAS_BOX,
-        REC_DLG_ACCEPT,
         helpersForController,
         invokeEventDialog,
         createCalendar,
         deleteCalendars,
         switchToView,
         goToDate,
         handleOccurrencePrompt,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({ REC_DLG_ACCEPT } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers")
     );
 
     createCalendar(controller, CALENDARNAME);
+    // Rotate view.
+    controller.mainMenu.click("#ltnViewRotated");
+    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
 }
 
 function testLastDayOfMonthRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
-    goToDate(controller, 2008, 1, 31); // start with a leap year
+    goToDate(controller, 2008, 1, 31); // Start with a leap year.
 
-    // rotate view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
-
-    // create monthly recurring event
+    // Create monthly recurring event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         menulistSelect(eventid("item-repeat"), "custom", event);
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
     // data tuple: [year, month, day, row in month view]
-    // note: month starts here with 1 for January
+    // note: Month starts here with 1 for January.
     let checkingData = [[2008, 1, 31, 5],
                         [2008, 2, 29, 5],
                         [2008, 3, 31, 6],
                         [2008, 4, 30, 5],
                         [2008, 5, 31, 5],
                         [2008, 6, 30, 5],
                         [2008, 7, 31, 5],
                         [2008, 8, 31, 6],
                         [2008, 9, 30, 5],
                         [2008, 10, 31, 5],
                         [2008, 11, 30, 6],
                         [2008, 12, 31, 5],
                         [2009, 1, 31, 5],
                         [2009, 2, 28, 4],
                         [2009, 3, 31, 5]];
-    // check all dates
+    // Check all dates.
     for (let [y, m, d, correctRow] of checkingData) {
         let date = new Date(y, m - 1, d);
         let column = date.getDay() + 1;
 
         goToDate(controller, y, m, d);
 
         // day view
         switchToView(controller, "day");
-        controller.waitForElement(
-            lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH));
 
         // week view
         switchToView(controller, "week");
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, column, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, column, null, EVENTPATH));
 
         // multiweek view
         switchToView(controller, "multiweek");
         controller.waitForElement(
             lookupEventBox("multiweek", EVENT_BOX, 1, column, null, EVENTPATH)
         );
 
         // month view
         switchToView(controller, "month");
         controller.waitForElement(
             lookupEventBox("month", EVENT_BOX, correctRow, column, null, EVENTPATH)
         );
     }
 
-    // delete event
+    // Delete event.
     goToDate(controller, checkingData[0][0], checkingData[0][1], checkingData[0][2]);
     switchToView(controller, "day");
-    let box = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
-    controller.waitThenClick(lookup(box));
-    handleOccurrencePrompt(controller, eid("day-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(box));
-
-    // reset view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
+    let box = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    controller.waitThenClick(box);
+    handleOccurrencePrompt(controller, eid("day-view"), "delete", true);
+    controller.waitForElementNotPresent(box);
 }
 
 function setRecurrence(recurrence) {
     let {
         sleep: recsleep,
         lookup: reclookup,
         eid: recid
     } = helpersForController(recurrence);
@@ -136,15 +127,20 @@ function setRecurrence(recurrence) {
     menulistSelect(recid("period-list"), "2", recurrence);
 
     // last day of month
     recurrence.radio(recid("montly-period-relative-date-radio"));
     menulistSelect(recid("monthly-ordinal"), "-1", recurrence);
     menulistSelect(recid("monthly-weekday"), "-1", recurrence);
     recsleep();
 
-    // close dialog
+    // Close dialog.
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
+    // Reset view.
+    if (eid("day-view").getNode().orient == "horizontal") {
+        controller.mainMenu.click("#ltnViewRotated");
+    }
+    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
 }
--- a/calendar/test/mozmill/recurrenceRotated/testWeeklyNRecurrence.js
+++ b/calendar/test/mozmill/recurrenceRotated/testWeeklyNRecurrence.js
@@ -1,183 +1,168 @@
 /* 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 MODULE_NAME = "testWeeklyNRecurrence";
+var MODULE_NAME = "testWeeklyNRecurrenceRotated";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
 var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
-var REC_DLG_ACCEPT, REC_DLG_DAYS;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
 var invokeEventDialog, viewForward, deleteCalendars, createCalendar, menulistSelect;
+var REC_DLG_ACCEPT, REC_DLG_DAYS;
 var plan_for_modal_dialog, wait_for_modal_dialog;
 
 const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         TIMEOUT_MODAL_DIALOG,
         CALENDARNAME,
         EVENTPATH,
         EVENT_BOX,
         CANVAS_BOX,
-        REC_DLG_ACCEPT,
-        REC_DLG_DAYS,
         helpersForController,
         handleOccurrencePrompt,
         switchToView,
         goToDate,
         invokeEventDialog,
         viewForward,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        REC_DLG_ACCEPT,
+        REC_DLG_DAYS
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers")
     );
 
     createCalendar(controller, CALENDARNAME);
+    // Rotate view.
+    controller.mainMenu.click("#ltnViewRotated");
+    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
 }
 
 function testWeeklyNRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 5);
 
-    // rotate view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
-
-    // create weekly recurring event
+    // Create weekly recurring event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         event.waitForElement(eventid("item-repeat"));
         menulistSelect(eventid("item-repeat"), "custom", event);
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
-    // check day view
-    let box = getEventBoxPath("day", EVENT_BOX, undefined, 1, HOUR) + EVENTPATH;
+    // Check day view.
+    let box = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
     // Monday, Tuesday, Wednesday, Thursday
     for (let i = 0; i < 4; i++) {
-        controller.waitForElement(lookup(box));
+        controller.waitForElement(box);
         viewForward(controller, 1);
     }
 
     // Not Friday
-    sleep();
-    controller.assertNodeNotExist(lookup(box));
+    controller.waitForElementNotPresent(box);
     viewForward(controller, 1);
 
     // Not Saturday as only 4 occurrences are set.
-    sleep();
-    controller.assertNodeNotExist(lookup(box));
+    controller.waitForElementNotPresent(box);
 
-    // check week view
+    // Check week view.
     switchToView(controller, "week");
 
     // Monday, Tuesday, Wednesday, Thursday
     for (let i = 2; i < 6; i++) {
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, i, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, i, null, EVENTPATH));
     }
 
     // Saturday
-    controller.assertNodeNotExist(
-        lookupEventBox("week", EVENT_BOX, null, 7, HOUR, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH));
 
     // check multiweek view
     switchToView(controller, "multiweek");
     checkMultiWeekView("multiweek");
 
-    // check month view
+    // Check month view.
     switchToView(controller, "month");
     checkMultiWeekView("month");
 
-    // delete event
-    box = getEventBoxPath("month", EVENT_BOX, 2, 2, HOUR) + EVENTPATH;
-    controller.click(lookup(box));
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(box));
-
-    // reset view
-    switchToView(controller, "day");
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
+    // Delete event.
+    box = lookupEventBox("month", EVENT_BOX, 2, 2, null, EVENTPATH);
+    controller.click(box);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", true);
+    controller.waitForElementNotPresent(box);
 }
 
 function setRecurrence(recurrence) {
-    let {
-        sleep: recsleep,
-        lookup: reclookup,
-        eid: recid,
-    } = helpersForController(recurrence);
+    let { sleep: recsleep, lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
     recurrence.waitForElement(recid("period-list"));
     menulistSelect(recid("period-list"), "1", recurrence);
     recsleep();
 
     let mon = cal.l10n.getDateFmtString("day.2.Mmm");
     let tue = cal.l10n.getDateFmtString("day.3.Mmm");
     let wed = cal.l10n.getDateFmtString("day.4.Mmm");
     let thu = cal.l10n.getDateFmtString("day.5.Mmm");
     let sat = cal.l10n.getDateFmtString("day.7.Mmm");
 
-    // starting from Monday so it should be checked. We have to wait a little,
+    // Starting from Monday so it should be checked. We have to wait a little,
     // because the checkedstate is set in background by JS.
     recurrence.waitFor(() => {
         return recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
     }, 30000);
-    // check Tuesday, Wednesday, Thursday and Saturday too
+    // Check Tuesday, Wednesday, Thursday and Saturday too.
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${tue}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${thu}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${sat}"}`));
 
-    // set number of occurrences
+    // Set number of recurrences.
     recurrence.click(recid("recurrence-range-for"));
     let ntimesField = recid("repeat-ntimes-count");
     ntimesField.getNode().value = "4";
 
     // close dialog
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function checkMultiWeekView(view) {
-    // make sure, the view has time to load
-    sleep();
-
-    // In month view event starts from 2nd row
+    // In month view event starts from 2nd row.
     let week = view == "month" ? 2 : 1;
 
     // Monday, Tuesday, Wednesday, Thursday
     for (let i = 2; i < 6; i++) {
-        controller.assertNode(
-            lookupEventBox(view, EVENT_BOX, week, i, null, EVENTPATH)
-        );
+        controller.assertNode(lookupEventBox(view, EVENT_BOX, week, i, null, EVENTPATH));
     }
 
     // Saturday
-    controller.assertNodeNotExist(
-        getEventBoxPath(view, EVENT_BOX, week, 7, null, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox(view, EVENT_BOX, week, 7, null, EVENTPATH));
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
+    // Reset view.
+    switchToView(controller, "day");
+    if (eid("day-view").getNode().orient == "horizontal") {
+        controller.mainMenu.click("#ltnViewRotated");
+    }
+    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
 }
--- a/calendar/test/mozmill/recurrenceRotated/testWeeklyUntilRecurrence.js
+++ b/calendar/test/mozmill/recurrenceRotated/testWeeklyUntilRecurrence.js
@@ -1,227 +1,212 @@
 /* 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 MODULE_NAME = "testWeeklyUntilRecurrence";
+var MODULE_NAME = "testWeeklyUntilRecurrenceRotated";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
-var SHORT_SLEEP, TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
-var CANVAS_BOX, REC_DLG_DAYS, REC_DLG_ACCEPT, REC_DLG_UNTIL_INPUT;
+var SHORT_SLEEP, TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
 var invokeEventDialog, viewForward, deleteCalendars, createCalendar, menulistSelect;
+var REC_DLG_DAYS, REC_DLG_ACCEPT, REC_DLG_UNTIL_INPUT;
 var plan_for_modal_dialog, wait_for_modal_dialog;
 
 const ENDDATE = new Date(2009, 0, 26); // last Monday in month
 const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         SHORT_SLEEP,
         TIMEOUT_MODAL_DIALOG,
         CALENDARNAME,
         EVENTPATH,
         EVENT_BOX,
         CANVAS_BOX,
-        REC_DLG_DAYS,
-        REC_DLG_ACCEPT,
-        REC_DLG_UNTIL_INPUT,
         helpersForController,
         handleOccurrencePrompt,
         switchToView,
         goToDate,
         invokeEventDialog,
         viewForward,
         deleteCalendars,
         createCalendar,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        REC_DLG_DAYS,
+        REC_DLG_ACCEPT,
+        REC_DLG_UNTIL_INPUT
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers")
     );
 
     createCalendar(controller, CALENDARNAME);
+    // Rotate view.
+    controller.mainMenu.click("#ltnViewRotated");
+    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
 }
 
 function testWeeklyUntilRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 5); // Monday
 
-    // rotate view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
-
-    // create weekly recurring event
+    // Create weekly recurring event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         event.waitForElement(eventid("item-repeat"));
         menulistSelect(eventid("item-repeat"), "custom", event);
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
-    let box = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
+    let box = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
 
-    // check day view
+    // Check day view.
     for (let week = 0; week < 3; week++) {
         // Monday
-        controller.waitForElement(lookup(box));
+        controller.waitForElement(box);
         viewForward(controller, 2);
 
         // Wednesday
-        controller.waitForElement(lookup(box));
+        controller.waitForElement(box);
         viewForward(controller, 2);
 
         // Friday
-        controller.waitForElement(lookup(box));
+        controller.waitForElement(box);
         viewForward(controller, 3);
     }
 
     // Monday, last occurrence
-    controller.waitForElement(lookup(box));
+    controller.waitForElement(box);
     viewForward(controller, 2);
 
     // Wednesday
-    controller.waitForElementNotPresent(lookup(box));
+    controller.waitForElementNotPresent(box);
 
-    // check week view
+    // Check week view.
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 5);
     for (let week = 0; week < 3; week++) {
         // Monday
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, 2, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 2, null, EVENTPATH));
 
         // Wednesday
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, 4, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 4, null, EVENTPATH));
 
         // Friday
-        controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, 6, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, null, EVENTPATH));
 
         viewForward(controller, 1);
     }
 
     // Monday, last occurrence
-    controller.waitForElement(
-        lookupEventBox("week", EVENT_BOX, null, 2, HOUR, EVENTPATH)
-    );
+    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 2, null, EVENTPATH));
     // Wednesday
-    controller.assertNodeNotExist(
-        lookupEventBox("week", EVENT_BOX, null, 4, HOUR, EVENTPATH)
-    );
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 4, null, EVENTPATH));
 
-    // check multiweek view
+    // Check multiweek view.
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 5);
     checkMultiWeekView("multiweek");
 
-    // check month view
+    // Check month view.
     switchToView(controller, "month");
     goToDate(controller, 2009, 1, 5);
     checkMultiWeekView("month");
 
-    // delete event
-    box = getEventBoxPath("month", EVENT_BOX, 2, 2, null) + EVENTPATH;
-    controller.click(lookup(box));
-    handleOccurrencePrompt(controller, eid("month-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(box));
-
-    // reset view
-    switchToView(controller, "day");
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
+    // Delete event.
+    box = lookupEventBox("month", EVENT_BOX, 2, 2, null, EVENTPATH);
+    controller.click(box);
+    handleOccurrencePrompt(controller, eid("month-view"), "delete", true);
+    controller.waitForElementNotPresent(box);
 }
 
 function setRecurrence(recurrence) {
-    let { sleep: recsleep, lookup: reclookup, eid: recid } =
-        helpersForController(recurrence);
+    let { sleep: recsleep, lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
     recurrence.waitForElement(recid("period-list"));
     menulistSelect(recid("period-list"), "1", recurrence);
 
     let mon = cal.l10n.getDateFmtString("day.2.Mmm");
     let wed = cal.l10n.getDateFmtString("day.4.Mmm");
     let fri = cal.l10n.getDateFmtString("day.6.Mmm");
 
-    // starting from Monday so it should be checked. We have to wait a little,
+    // Starting from Monday so it should be checked. We have to wait a little,
     // because the checkedstate is set in background by JS.
     recurrence.waitFor(() => {
         return recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
     }, 30000);
-    // starting from Monday so it should be checked
+    // Starting from Monday so it should be checked.
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
-    // check Wednesday and Friday too
+    // Check Wednesday and Friday too.
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${fri}"}`));
 
-    // set until date
+    // Set until date.
     recurrence.radio(recid("recurrence-range-until"));
 
-    // delete previous date
+    // Delete previous date.
     let untilInput = reclookup(REC_DLG_UNTIL_INPUT);
     recurrence.keypress(untilInput, "a", { accelKey: true });
     recurrence.keypress(untilInput, "VK_DELETE", {});
 
     let dateFormatter = cal.getDateFormatter();
 
-    let endDateString = dateFormatter.formatDateShort(cal.dtz.jsDateToDateTime(ENDDATE, cal.dtz.floating));
+    let endDateString = dateFormatter.formatDateShort(
+        cal.dtz.jsDateToDateTime(ENDDATE, cal.dtz.floating)
+    );
     recsleep(SHORT_SLEEP);
     recurrence.type(untilInput, endDateString);
 
     recsleep(SHORT_SLEEP);
-    // Move focus to ensure the date is selected
+    // Move focus to ensure the date is selected.
     recurrence.keypress(untilInput, "VK_TAB", {});
 
-    // close dialog
+    // Close dialog.
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function checkMultiWeekView(view) {
     let startWeek = view == "month" ? 2 : 1;
 
     for (let week = startWeek; week < startWeek + 3; week++) {
         // Monday
-        controller.waitForElement(
-            lookupEventBox(view, EVENT_BOX, week, 2, null, EVENTPATH)
-        );
+        controller.waitForElement(lookupEventBox(view, EVENT_BOX, week, 2, null, EVENTPATH));
         // Wednesday
-        controller.assertNode(
-            lookupEventBox(view, EVENT_BOX, week, 4, null, EVENTPATH)
-        );
+        controller.assertNode(lookupEventBox(view, EVENT_BOX, week, 4, null, EVENTPATH));
         // Friday
-        controller.assertNode(
-            lookupEventBox(view, EVENT_BOX, week, 6, null, EVENTPATH)
-        );
+        controller.assertNode(lookupEventBox(view, EVENT_BOX, week, 6, null, EVENTPATH));
     }
 
     // Monday, last occurrence
-    controller.assertNode(
-        lookupEventBox(view, EVENT_BOX, startWeek + 3, 2, null, EVENTPATH)
-    );
+    controller.assertNode(lookupEventBox(view, EVENT_BOX, startWeek + 3, 2, null, EVENTPATH));
 
     // Wednesday
     controller.assertNodeNotExist(
         lookupEventBox(view, EVENT_BOX, startWeek + 3, 4, null, EVENTPATH)
     );
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
+    // Reset view.
+    switchToView(controller, "day");
+    if (eid("day-view").getNode().orient == "horizontal") {
+        controller.mainMenu.click("#ltnViewRotated");
+    }
+    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
 }
--- a/calendar/test/mozmill/recurrenceRotated/testWeeklyWithExceptionRecurrence.js
+++ b/calendar/test/mozmill/recurrenceRotated/testWeeklyWithExceptionRecurrence.js
@@ -1,304 +1,294 @@
 /* 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 MODULE_NAME = "testWeeklyWithExceptionRecurrence";
+var MODULE_NAME = "testWeeklyWithExceptionRecurrenceRotated";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
-var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
-var CANVAS_BOX, REC_DLG_ACCEPT, REC_DLG_DAYS;
+var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENT_BOX, CANVAS_BOX;
+var DAY_VIEW, WEEK_VIEW, EVENTPATH;
 var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
-var invokeEventDialog, viewForward, deleteCalendars, createCalendar, setData;
+var invokeEventDialog, viewForward, deleteCalendars, createCalendar;
 var menulistSelect;
+var REPEAT_DETAILS, REC_DLG_ACCEPT, REC_DLG_DAYS;
+var helpersForEditUI, setData;
 var plan_for_modal_dialog, wait_for_modal_dialog;
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
 const HOUR = 8;
 const STARTDATE = new Date(2009, 0, 6);
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         TIMEOUT_MODAL_DIALOG,
         CALENDARNAME,
         EVENT_BOX,
         CANVAS_BOX,
         EVENTPATH,
-        REC_DLG_ACCEPT,
-        REC_DLG_DAYS,
+        DAY_VIEW,
+        WEEK_VIEW,
         helpersForController,
         handleOccurrencePrompt,
         switchToView,
         goToDate,
         invokeEventDialog,
         viewForward,
         deleteCalendars,
         createCalendar,
-        setData,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        REPEAT_DETAILS,
+        REC_DLG_ACCEPT,
+        REC_DLG_DAYS,
+        helpersForEditUI,
+        setData
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers")
     );
 
     createCalendar(controller, CALENDARNAME);
+    // Rotate view.
+    controller.mainMenu.click("#ltnViewRotated");
+    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
 }
 
 function testWeeklyWithExceptionRecurrence() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 5);
 
-    // rotate view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "horizontal");
-
-    // create weekly recurring event
+    // Create weekly recurring event.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         event.waitForElement(eventid("item-repeat"));
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         menulistSelect(eventid("item-repeat"), "custom", event);
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
-    // move 5th January occurrence to 6th January
-    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH);
-    handleOccurrencePrompt(controller, eventBox, "modify", false, false);
+    // Move 5th January occurrence to 6th January.
+    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    handleOccurrencePrompt(controller, eventBox, "modify", false);
     invokeEventDialog(controller, null, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         setData(event, iframe, { startdate: STARTDATE, enddate: STARTDATE });
         event.click(eventid("button-saveandclose"));
     });
 
-    // change recurrence rule
+    // Change recurrence rule.
     goToDate(controller, 2009, 1, 7);
-    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH);
-    handleOccurrencePrompt(controller, eventBox, "modify", true, false);
+    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    handleOccurrencePrompt(controller, eventBox, "modify", true);
     invokeEventDialog(controller, null, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
-        let { lookup: iframelookup } = helpersForController(iframe);
+        let { iframeLookup } = helpersForEditUI(iframe);
 
         event.waitForElement(eventid("item-repeat"));
         plan_for_modal_dialog("Calendar:EventDialog:Recurrence", changeRecurrence);
-        event.click(iframelookup(`
-            /id("calendar-event-dialog-inner")/id("event-grid")/
-            id("event-grid-rows")/id("event-grid-recurrence-row")/
-            id("event-grid-recurrence-picker-box")/id("repeat-deck")/
-            id("repeat-details")/[0]
-        `));
+        event.click(iframeLookup(REPEAT_DETAILS));
         wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
-    // check two weeks
+    // Check two weeks.
     // day view
     switchToView(controller, "day");
-    let path = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
+    let path = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
 
     goToDate(controller, 2009, 1, 5);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
 
     viewForward(controller, 1);
     let tuesPath = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("day-view")/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
+        ${DAY_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
         anon({"anonid":"daybox"})/[0]/anon({"anonid":"boxstack"})/
         anon({"anonid":"topbox"})/{"flex":"1"}/{"flex":"1"}/[eventIndex]
     `;
 
-    // assert exactly two
+    // Assert exactly two.
     controller.waitForElement(lookup(tuesPath.replace("eventIndex", "0") + EVENTPATH));
     controller.assertNode(lookup(tuesPath.replace("eventIndex", "1") + EVENTPATH));
     controller.assertNodeNotExist(lookup(tuesPath.replace("eventIndex", "2") + EVENTPATH));
 
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
 
     // next week
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
     viewForward(controller, 1);
-    controller.waitForElement(lookup(path));
+    controller.waitForElement(path);
     viewForward(controller, 1);
-    controller.waitForElementNotPresent(lookup(path));
+    controller.waitForElementNotPresent(path);
 
     // week view
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 5);
 
     tuesPath = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("week-view")/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
-        anon({"anonid":"daybox"})/[dayIndex]/anon({"anonid":"boxstack"})/
+        ${WEEK_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
+        anon({"anonid":"daybox"})/[2]/anon({"anonid":"boxstack"})/
         anon({"anonid":"topbox"})/{"flex":"1"}/{"flex":"1"}/[eventIndex]
     `;
 
-    // assert exactly two
-    controller.waitForElement(lookup(
-        tuesPath.replace("dayIndex", "2").replace("eventIndex", "0") + EVENTPATH
-    ));
-    controller.assertNode(lookup(
-        tuesPath.replace("dayIndex", "2").replace("eventIndex", "1") + EVENTPATH
-    ));
-    controller.assertNodeNotExist(lookup(
-        tuesPath.replace("dayIndex", "2").replace("eventIndex", "2") + EVENTPATH
-    ));
+    // Assert exactly two.
+    controller.waitForElement(lookup(tuesPath.replace("eventIndex", "0") + EVENTPATH));
+    controller.assertNode(lookup(tuesPath.replace("eventIndex", "1") + EVENTPATH));
+    controller.assertNodeNotExist(lookup(tuesPath.replace("eventIndex", "2") + EVENTPATH));
 
-    // wait for the last occurrence because this appears latest.
-    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 1, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 2, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 4, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 5, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, HOUR));
+    // Wait for the last occurrence because this appears last.
+    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 1, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 2, null));
+    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 4, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 5, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null));
 
     viewForward(controller, 1);
-    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 1, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 2, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 3, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 4, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 5, HOUR));
-    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, HOUR));
+    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 6, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 1, null));
+    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 2, null));
+    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 3, null));
+    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 4, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 5, null));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, null));
 
     // multiweek view
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 5);
     checkMultiWeekView("multiweek");
 
     // month view
     switchToView(controller, "month");
     checkMultiWeekView("month");
 
-    // delete event
+    // Delete event.
     switchToView(controller, "day");
     goToDate(controller, 2009, 1, 12);
-    path = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
-    controller.click(lookup(path));
-    handleOccurrencePrompt(controller, eid("day-view"), "delete", true, false);
-    controller.waitForElementNotPresent(lookup(path));
-
-    // reset view
-    controller.mainMenu.click("#ltnViewRotated");
-    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
+    path = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
+    controller.click(path);
+    handleOccurrencePrompt(controller, eid("day-view"), "delete", true);
+    controller.waitForElementNotPresent(path);
 }
 
 function setRecurrence(recurrence) {
     let { lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
     menulistSelect(recid("period-list"), "1", recurrence);
 
     let mon = cal.l10n.getDateFmtString("day.2.Mmm");
     let wed = cal.l10n.getDateFmtString("day.4.Mmm");
     let fri = cal.l10n.getDateFmtString("day.6.Mmm");
 
-    // starting from Monday so it should be checked. We have to wait a little,
+    // Starting from Monday so it should be checked. We have to wait a little,
     // because the checkedstate is set in background by JS.
     recurrence.waitFor(() => {
         return recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
     }, 10000);
-    // check Wednesday and Friday too
+    // Check Wednesday and Friday too.
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${fri}"}`));
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${fri}"}`));
 
-    // close dialog
+    // Close dialog.
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function changeRecurrence(recurrence) {
     let { lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
     menulistSelect(recid("period-list"), "1", recurrence);
 
     let mon = cal.l10n.getDateFmtString("day.2.Mmm");
     let tue = cal.l10n.getDateFmtString("day.3.Mmm");
     let wed = cal.l10n.getDateFmtString("day.4.Mmm");
     let fri = cal.l10n.getDateFmtString("day.6.Mmm");
 
-    // check old rule
-    // starting from Monday so it should be checked. We have to wait a little,
+    // Check old rule.
+    // Starting from Monday so it should be checked. We have to wait a little,
     // because the checkedstate is set in background by JS.
     recurrence.waitFor(() => {
         return recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
     }, 10000);
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${fri}"}`));
 
-    // check Tuesday
+    // Check Tuesday.
     recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${tue}"}`));
     recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${tue}"}`));
 
-    // close dialog
+    // Close dialog.
     recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function checkMultiWeekView(view) {
     let startWeek = view == "multiweek" ? 1 : 2;
     let assertNodeLookup = (...args) => {
         return controller.assertNode(lookupEventBox(...args));
     };
     let assertNodeNotExistLookup = (...args) => {
         return controller.assertNodeNotExist(lookupEventBox(...args));
     };
 
-    // wait for the first items, then check the ones not to be present
-    // assert exactly two
-    controller.waitForElement(
-        lookupEventBox(view, EVENT_BOX, startWeek, 3, HOUR, "/[0]")
-    );
-    assertNodeLookup(view, EVENT_BOX, startWeek, 3, HOUR, "/[1]");
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 3, HOUR, "/[2]");
+    // Wait for the first items, then check the ones not to be present.
+    // Assert exactly two.
+    controller.waitForElement(lookupEventBox(view, EVENT_BOX, startWeek, 3, null, "/[0]"));
+    assertNodeLookup(view, EVENT_BOX, startWeek, 3, null, "/[1]");
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 3, null, "/[2]");
     // Then check no item on the 5th.
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 2, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 3, HOUR, "/[2]");
-    assertNodeLookup(view, EVENT_BOX, startWeek, 4, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 5, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek, 6, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 7, HOUR, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 2, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 3, null, "/[2]");
+    assertNodeLookup(view, EVENT_BOX, startWeek, 4, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 5, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek, 6, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 7, null, EVENTPATH);
 
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 1, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 2, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 3, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 4, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 5, HOUR, EVENTPATH);
-    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 6, HOUR, EVENTPATH);
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 7, HOUR, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 1, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 2, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 3, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 4, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 5, null, EVENTPATH);
+    assertNodeLookup(view, EVENT_BOX, startWeek + 1, 6, null, EVENTPATH);
+    assertNodeNotExistLookup(view, EVENT_BOX, startWeek + 1, 7, null, EVENTPATH);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
+
+    // Reset view.
+    if (eid("day-view").getNode().orient == "horizontal") {
+        controller.mainMenu.click("#ltnViewRotated");
+    }
+    controller.waitFor(() => eid("day-view").getNode().orient == "vertical");
 }
--- a/calendar/test/mozmill/shared-modules/test-calendar-utils.js
+++ b/calendar/test/mozmill/shared-modules/test-calendar-utils.js
@@ -2,100 +2,149 @@
  * 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 MODULE_NAME = "calendar-utils";
 var RELATIVE_ROOT = "../shared-modules";
 var MODULE_REQUIRES = ["window-helpers", "folder-display-helpers", "pref-window-helpers"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 var os = {};
 ChromeUtils.import("chrome://mozmill/content/stdlib/os.js", os);
 var frame = {};
 ChromeUtils.import("chrome://mozmill/content/modules/frame.js", frame);
 var utils = {};
 ChromeUtils.import("chrome://mozmill/content/modules/utils.js", utils);
 
 var SHORT_SLEEP = 100;
 var MID_SLEEP = 500;
 var TIMEOUT_MODAL_DIALOG = 30000;
 var TIMEOUT_MONTHCHANGE = 10000;
 var CALENDARNAME = "Mozmill";
 
-// these are used in EventBox lookup.
-var EVENT_BOX = 0; // Use when you need an event box
-var CANVAS_BOX = 1; // Use when you need a calendar canvas box
-var ALLDAY = 2; // Use when you need an allday canvas or event box
+// These are used in EventBox lookup.
+var EVENT_BOX = 0; // Use when you need an event box.
+var CANVAS_BOX = 1; // Use when you need a calendar canvas box.
+var ALLDAY = 2; // Use when you need an allday canvas or event box.
 
-// Lookup paths and path-snippets
-var EVENTPATH = `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`;
-var REC_DLG_ACCEPT = `
-        /id("calendar-event-dialog-recurrence")
-        /anon({"anonid":"buttons"})/{"dlgtype":"accept"}
+// Lookup paths and path-snippets.
+var CALENDAR_PANEL = `
+    /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
+    id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")
+`;
+var VIEWDECK = `
+    ${CALENDAR_PANEL}/id("calendarDisplayDeck")/id("calendar-view-box")/
+    id("view-deck")
+`;
+var DAY_VIEW = `${VIEWDECK}/id("day-view")`;
+var WEEK_VIEW = `${VIEWDECK}/id("week-view")`;
+// Multiday-view-day-box of day and week view.
+var DAYBOX = `
+    anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/anon({"anonid":"daybox"})
+`;
+// Multiday-view-label-day-box of day and week view.
+var LABELDAYBOX = `
+    anon({"anonid":"mainbox"})/anon({"anonid":"labelbox"})/anon({"anonid":"labeldaybox"})
 `;
-var REC_DLG_DAYS = `
-        /id("calendar-event-dialog-recurrence")
-        /id("recurrence-pattern-groupbox")/id("recurrence-pattern-grid")
-        /id("recurrence-pattern-rows")/id("recurrence-pattern-period-row")
-        /id("period-deck")/id("period-deck-weekly-box")/[1]/id("daypicker-weekday")
-        /anon({"anonid":"mainbox"})
+var MULTIWEEK_VIEW = `${VIEWDECK}/id("multiweek-view")`;
+var MONTH_VIEW = `${VIEWDECK}/id("month-view")`;
+var TASK_VIEW = `${CALENDAR_PANEL}/id("calendarDisplayDeck")/id("calendar-task-box")/`;
+
+var MINIMONTH = `
+    ${CALENDAR_PANEL}/id("ltnSidebar")/id("minimonth-pane")/{"align":"center"}/
+    id("calMinimonthBox")/id("calMinimonth")
+`;
+var TODAY_BUTTON = `
+    ${MINIMONTH}/anon({"anonid":"minimonth-header"})/anon({"anonid":"today-button"})
 `;
-var REC_DLG_UNTIL_INPUT = `
-        /id("calendar-event-dialog-recurrence")/id("recurrence-range-groupbox")/[1]/
-        id("recurrence-duration")/id("recurrence-range-until-box")/
-        id("repeat-until-date")/anon({"class":"datepicker-box-class"})/
-        {"class":"datepicker-text-class"}/
-        anon({"class":"menulist-editable-box textbox-input-box"})/
-        anon({"anonid":"input"})
+var CALENDARLIST = `
+    ${CALENDAR_PANEL}/id("ltnSidebar")/id("calendar-panel")/id("calendar-list-pane")/
+    id("calendar-listtree-pane")/id("calendar-list-tree-widget")/
+    anon({"anonid":"tree"})/anon({"anonid":"treechildren"})
+`;
+var TODAY_PANE = `
+    /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")
+`;
+var AGENDA_LISTBOX = `
+    ${TODAY_PANE}/{"flex":"1"}/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")
+`;
+
+var EVENTPATH = `
+    /{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}
+`;
+// Used after "${EVENTPATH}/${getEventDetials([view])}/".
+var ALARM_ICON_PATH = `
+    anon({"anonid":"category-box-stack"})/anon({"align":"center"})/
+    anon({"anonid":"alarm-icons-box"})/anon({"class":"reminder-icon"})
 `;
 
 var plan_for_modal_dialog, wait_for_modal_dialog, open_pref_tab;
 
-function setupModule() {
+function setupModule(controller) {
     ({ plan_for_modal_dialog, wait_for_modal_dialog } =
         collector.getModule("window-helpers"));
 
-    // this setup is needed for pref-win-helpers. For some reason, the automatic
+    // This setup is needed for pref-win-helpers. For some reason, the automatic
     // loading of modules in shared modules does not setup the module correctly.
     collector.getModule("folder-display-helpers").setupModule();
 
     ({ open_pref_tab } = collector.getModule("pref-window-helpers"));
     collector.getModule("pref-window-helpers").setupModule();
+
+    // For our tests, we assume that Sunday is start of week.
+    Services.prefs.setIntPref("calendar.week.start", 0);
+
+    // We are in calendarTests, so we make sure, calendar-tab with day-view is displayed.
+    let { eid } = helpersForController(controller);
+    controller.click(eid("calendar-tab-button"));
+    switchToView(controller, "day");
 }
 
 function installInto(module) {
-    // copy constants into module
+    // Copy constants into module.
     module.SHORT_SLEEP = SHORT_SLEEP;
     module.MID_SLEEP = MID_SLEEP;
     module.TIMEOUT_MODAL_DIALOG = TIMEOUT_MODAL_DIALOG;
     module.CALENDARNAME = CALENDARNAME;
+    module.CALENDAR_PANEL = CALENDAR_PANEL;
+    module.VIEWDECK = VIEWDECK;
+    module.DAY_VIEW = DAY_VIEW;
+    module.WEEK_VIEW = WEEK_VIEW;
+    module.DAYBOX = DAYBOX;
+    module.LABELDAYBOX = LABELDAYBOX;
+    module.MULTIWEEK_VIEW = MULTIWEEK_VIEW;
+    module.MONTH_VIEW = MONTH_VIEW;
+    module.TASK_VIEW = TASK_VIEW;
+    module.MINIMONTH = MINIMONTH;
+    module.TODAY_BUTTON = TODAY_BUTTON;
+    module.CALENDARLIST = CALENDARLIST;
+    module.TODAY_PANE = TODAY_PANE;
+    module.AGENDA_LISTBOX = AGENDA_LISTBOX;
     module.EVENTPATH = EVENTPATH;
+    module.ALARM_ICON_PATH = ALARM_ICON_PATH;
     module.EVENT_BOX = EVENT_BOX;
     module.CANVAS_BOX = CANVAS_BOX;
     module.ALLDAY = ALLDAY;
-    module.REC_DLG_ACCEPT = REC_DLG_ACCEPT;
-    module.REC_DLG_DAYS = REC_DLG_DAYS;
-    module.REC_DLG_UNTIL_INPUT = REC_DLG_UNTIL_INPUT;
-    // Now copy helper functions
+
+    // Now copy helper functions.
     module.helpersForController = helpersForController;
-    module.acceptSendingNotificationMail = acceptSendingNotificationMail;
-    module.handleAddingAttachment = handleAddingAttachment;
+    module.setupLightning = setupLightning;
     module.handleOccurrencePrompt = handleOccurrencePrompt;
     module.switchToView = switchToView;
     module.goToDate = goToDate;
     module.invokeEventDialog = invokeEventDialog;
     module.getEventBoxPath = getEventBoxPath;
+    module.getEventDetails = getEventDetails;
+    module.checkAlarmIcon = checkAlarmIcon;
     module.viewForward = viewForward;
     module.viewBack = viewBack;
     module.deleteCalendars = deleteCalendars;
     module.createCalendar = createCalendar;
     module.handleNewCalendarWizard = handleNewCalendarWizard;
     module.findEventsInNode = findEventsInNode;
-    module.setData = setData;
     module.openLightningPrefs = openLightningPrefs;
     module.menulistSelect = menulistSelect;
 }
 
 function helpersForController(controller) {
     function selector(sel) {
         return sel.trim().replace(/\n(\s*)/g, "");
     }
@@ -104,157 +153,115 @@ function helpersForController(controller
         lookup: (sel) => new elementslib.Lookup(controller.window.document, selector(sel)),
         eid: (id) => new elementslib.ID(controller.window.document, id),
         xpath: (path) => new elementslib.XPath(controller.window.document, selector(path)),
         sleep: (timeout = MID_SLEEP) => controller.sleep(timeout),
         getEventBoxPath: (...args) => getEventBoxPath(controller, ...args),
         lookupEventBox: (view, option, row, column, hour, extra = "/") => {
             let path = getEventBoxPath(controller, view, option, row, column, hour);
             return new elementslib.Lookup(controller.window.document, selector(path + extra));
+        },
+        replaceText: (textbox, text) => {
+            controller.keypress(textbox, "a", { accelKey: true });
+            controller.type(textbox, text);
         }
     };
 }
 
 /**
- * make sure, the current view has finished loading
+ * Make sure, the current view has finished loading.
  *
  * @param controller        Mozmill window controller
  */
 function ensureViewLoaded(controller) {
     let { sleep } = helpersForController(controller);
     controller.waitFor(() =>
         controller.window.getViewDeck().selectedPanel.mPendingRefreshJobs.size == 0
     );
-    // after the queue is empty the view needs a moment to settle.
+    // After the queue is empty the view needs a moment to settle.
     sleep(200);
 }
 
 /**
- * Accept to send notification email with event to attendees
- *
- * @param controller        Mozmill window controller
- */
-function acceptSendingNotificationMail(controller) {
-    plan_for_modal_dialog("commonDialog", (dialog) => {
-        let { lookup: cdlglookup } = helpersForController(dialog);
-        dialog.waitThenClick(cdlglookup(`
-            /id("commonDialog")/anon({"anonid":"buttons"})/{"dlgtype":"accept"}
-        `));
-    });
-
-    wait_for_modal_dialog("commonDialog");
-}
-
-/**
- * Add an attachment with url
- *
- * @param controller        Mozmill window controller
- */
-function handleAddingAttachment(controller, url) {
-    plan_for_modal_dialog("commonDialog", (attachment) => {
-        let { lookup: cdlglookup, eid: cdlgid } = helpersForController(attachment);
-        attachment.waitForElement(cdlgid("loginTextbox"));
-        cdlgid("loginTextbox").getNode().value = url;
-        attachment.click(cdlglookup(`
-            /id("commonDialog")/anon({"anonid":"buttons"})/{"dlgtype":"accept"}
-        `));
-    });
-}
-
-/**
- * open and click the appropriate button on the recurrence-Prompt Dialog
+ * Open and click the appropriate button on the recurrence-Prompt Dialog.
  *
  * @param controller      Mozmill window controller
- * @param element         Mozmill element which will open the dialog
- * @param mode            action to exec on element (delete OR modify)
- * @param selectParent    true if all occurrences should be deleted
- * @param attendees       Whether there are attendees that can be notified or not
+ * @param element         Mozmill element which will open the dialog.
+ * @param mode            Action to exec on element (delete OR modify).
+ * @param selectParent    true if all occurrences should be deleted.
  */
-function handleOccurrencePrompt(controller, element, mode, selectParent, attendees) {
+function handleOccurrencePrompt(controller, element, mode, selectParent) {
     controller.waitForElement(element);
     plan_for_modal_dialog("Calendar:OccurrencePrompt", (dialog) => {
         let { eid: dlgid } = helpersForController(dialog);
-        if (attendees) {
-            acceptSendingNotificationMail();
-        }
         if (selectParent) {
             dialog.waitThenClick(dlgid("accept-parent-button"));
         } else {
             dialog.waitThenClick(dlgid("accept-occurrence-button"));
         }
     });
     if (mode == "delete") {
         controller.keypress(element, "VK_DELETE", {});
     } else if (mode == "modify") {
         controller.doubleClick(element);
     }
     wait_for_modal_dialog("Calendar:OccurrencePrompt", TIMEOUT_MODAL_DIALOG);
 }
 
 /**
- * Switch to a view and make sure it's displayed
+ * Switch to a view and make sure it's displayed.
  *
  * @param controller        Mozmill window controller
  * @param view              day, week, multiweek or month
  */
 function switchToView(controller, view) {
     let { eid } = helpersForController(controller);
 
     let button = `calendar-${view}-view-button`;
 
     controller.waitThenClick(eid(button));
     ensureViewLoaded(controller);
 }
 
 /**
- * Go to a specific date using minimonth
+ * Go to a specific date using minimonth.
  *
  * @param controller    Main window controller
  * @param year          Four-digit year
  * @param month         1-based index of a month
  * @param day           1-based index of a day
  */
 function goToDate(controller, year, month, day) {
     let { eid, lookup } = helpersForController(controller);
 
-    let miniMonth = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("ltnSidebar")/id("minimonth-pane")/{"align":"center"}/
-        id("calMinimonthBox")/id("calMinimonth")
-    `;
-
     let activeYear = lookup(`
-        ${miniMonth}/anon({"anonid":"minimonth-header"})/
-        anon({"anonid":"yearcell"})
+        ${MINIMONTH}/anon({"anonid":"minimonth-header"})/anon({"anonid":"yearcell"})
     `).getNode().getAttribute("label");
 
     let activeMonth = lookup(`
-        ${miniMonth}/anon({"anonid":"minimonth-header"})/anon({"anonid":"monthheader"})
+        ${MINIMONTH}/anon({"anonid":"minimonth-header"})/anon({"anonid":"monthheader"})
     `).getNode().getAttribute("selectedIndex");
 
     let yearDifference = activeYear - year;
     let monthDifference = activeMonth - (month - 1);
 
     if (yearDifference != 0) {
         let direction = yearDifference > 0 ? "up" : "down";
         let scrollArrow = lookup(`
-            ${miniMonth}/anon({"anonid":"minimonth-header"})/
-            anon({"anonid":"minmonth-popupset"})/anon({"anonid":"years-popup"})/
-            {"class":"autorepeatbutton-${direction}"}`);
+            ${MINIMONTH}/anon({"anonid":"minimonth-header"})/anon({"anonid":"minmonth-popupset"})/
+            anon({"anonid":"years-popup"})/{"class":"autorepeatbutton-${direction}"}`);
 
-        // pick year
+        // Pick year.
         controller.click(lookup(`
-            ${miniMonth}/anon({"anonid":"minimonth-header"})/
-            anon({"anonid":"yearcell"})
+            ${MINIMONTH}/anon({"anonid":"minimonth-header"})/anon({"anonid":"yearcell"})
         `));
 
         let getYearListitem = function(aYear) {
             return lookup(`
-                ${miniMonth}/anon({"anonid":"minimonth-header"})/
+                ${MINIMONTH}/anon({"anonid":"minimonth-header"})/
                 anon({"anonid":"minmonth-popupset"})/anon({"anonid":"years-popup"})/
                 {"label":"${aYear}"}
             `);
         };
 
         controller.waitForElement(scrollArrow);
         scrollArrow = scrollArrow.getNode();
 
@@ -267,40 +274,39 @@ function goToDate(controller, year, mont
 
         controller.waitForEvents.init(eid("calMinimonth"), ["monthchange"]);
         controller.click(getYearListitem(year));
         controller.waitForEvents.wait(TIMEOUT_MONTHCHANGE);
     }
 
     if (monthDifference != 0) {
         controller.waitForEvents.init(eid("calMinimonth"), ["monthchange"]);
-        // pick month
+        // Pick month.
         controller.click(lookup(`
-            ${miniMonth}/anon({"anonid":"minimonth-header"})/
-            anon({"anonid":"monthheader"})/[${activeMonth}]
+            ${MINIMONTH}/anon({"anonid":"minimonth-header"})/anon({"anonid":"monthheader"})/
+            [${activeMonth}]
         `));
         controller.waitThenClick(lookup(`
-            ${miniMonth}/anon({"anonid":"minimonth-header"})/
-            anon({"anonid":"minmonth-popupset"})/anon({"anonid":"months-popup"})/
-            {"index":"${month - 1}"}
+            ${MINIMONTH}/anon({"anonid":"minimonth-header"})/anon({"anonid":"minmonth-popupset"})/
+            anon({"anonid":"months-popup"})/{"index":"${month - 1}"}
         `));
         controller.waitForEvents.wait(TIMEOUT_MONTHCHANGE);
     }
 
     let lastDayInFirstRow = lookup(`
-        ${miniMonth}/anon({"anonid":"minimonth-calendar"})/[3]/[15]
+        ${MINIMONTH}/anon({"anonid":"minimonth-calendar"})/[3]/[15]
     `).getNode().innerHTML;
 
     let positionOfFirst = 7 - lastDayInFirstRow;
     let dateColumn = (positionOfFirst + day - 1) % 7;
     let dateRow = Math.floor((positionOfFirst + day - 1) / 7);
 
-    // pick day
+    // Pick day.
     controller.click(lookup(`
-        ${miniMonth}/anon({"anonid":"minimonth-calendar"})/[${(dateRow + 1) * 2 + 1}]/
+        ${MINIMONTH}/anon({"anonid":"minimonth-calendar"})/[${(dateRow + 1) * 2 + 1}]/
         [${(dateColumn + 1) * 2 + 1}]
     `));
     ensureViewLoaded(controller);
 }
 
 /**
  * Opens the event dialog by clicking on the (optional) box and executing the
  * body. The event dialog must be closed in the body function.
@@ -319,120 +325,149 @@ function invokeEventDialog(controller, c
         return mozmill.utils.getWindows("Calendar:EventDialog").length > 0;
     }, "event-dialog did not load in time", MID_SLEEP);
 
     let eventWindow = mozmill.utils.getWindows("Calendar:EventDialog")[0];
     let eventController = new mozmill.controller.MozMillController(eventWindow);
     let iframe = eventController.window.document.getElementById("lightning-item-panel-iframe");
 
     eventController.waitFor(() => {
-        return iframe.contentWindow.onLoad &&
-               iframe.contentWindow.onLoad.hasLoaded;
+        return iframe.contentWindow.onLoad && iframe.contentWindow.onLoad.hasLoaded;
     }, "event-dialog did not load in time", 10000);
 
     // We can't use a full mozmill controller on an iframe, but we need
     // something for helpersForController.
     let mockIframeController = { window: iframe.contentWindow };
 
     body(eventController, mockIframeController);
 
-    // Wait for close
+    // Wait for close.
     controller.waitFor(() => mozmill.utils.getWindows("Calendar:EventDialog").length == 0);
 }
 
 /**
- * Gets the path for an event box
+ * Gets the path for an event box.
  *
  * @param controller    main window controller
  * @param view          day, week, multiweek or month
  * @param option        CANVAS_BOX or ALLDAY for creating event, EVENT_BOX for existing event
- * @param row           only used in multiweek and month view, 1-based index of a row
+ * @param row           Only used in multiweek and month view, 1-based index of a row.
  * @param column        1-based index of a column
- * @param hour          index of hour box
+ * @param hour          Only used in day and week view, index of hour box.
  * @returns             path string
  */
 function getEventBoxPath(controller, view, option, row, column, hour) {
-    let viewDeck = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")
-    `;
-
-    let path = `${viewDeck}/id("${view}-view")`;
-
+    let path = `${VIEWDECK}/id("${view}-view")`;
 
     if ((view == "day" || view == "week") && option == ALLDAY) {
         return path + `
             /anon({"anonid":"mainbox"})/anon({"anonid":"headerbox"})/
-            anon({"anonid":"headerdaybox"})/
-            [${column - 1}]
+            anon({"anonid":"headerdaybox"})/[${column - 1}]
         `;
     } else if (view == "day" || view == "week") {
         path += `
-            /anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
-            anon({"anonid":"daybox"})/[${column - 1}]/
-            anon({"anonid":"boxstack"})
+            /anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/anon({"anonid":"daybox"})/
+            [${column - 1}]/anon({"anonid":"boxstack"})
         `;
 
         if (option == CANVAS_BOX) {
             path += `/anon({"anonid":"bgbox"})/[${hour}]`;
         } else {
-            path += '/anon({"anonid":"topbox"})/{"flex":"1"}/{"flex":"1"}/{"flex":"1"}';
+            path += `
+                /anon({"anonid":"topbox"})/{"flex":"1"}/{"flex":"1"}/{"flex":"1"}
+            `;
         }
 
         return path;
     } else {
         path += `
             /anon({"anonid":"mainbox"})/anon({"anonid":"monthgrid"})/
-            anon({"anonid":"monthgridrows"})/[${row - 1}]/
-            [${column - 1}]
+            anon({"anonid":"monthgridrows"})/[${row - 1}]/[${column - 1}]
         `;
 
         if (option == CANVAS_BOX) {
-            path += '/anon({"anonid":"day-items"})';
+            path += `
+                /anon({"anonid":"day-items"})
+            `;
         }
 
         return path;
     }
 }
 
 /**
- * Moves the view n times forward
+ * Gets the path snippet for event-details. This is different for day/week and
+ * multiweek/month view.
+ *
+ * @param view          day, week, multiweek or month
+ */
+function getEventDetails(view) {
+    if (view == "day" || view == "week") {
+        return `
+            anon({"flex":"1"})/anon({"anonid":"event-container"})/
+            {"class":"calendar-event-selection"}/anon({"anonid":"eventbox"})/
+            {"class":"calendar-event-details"}
+        `;
+    } else {
+        return `
+            anon({"flex":"1"})/[0]/anon({"anonid":"event-container"})/
+            {"class":"calendar-event-selection"}/anon({"anonid":"eventbox"})/
+            {"class":"calendar-event-details"}
+        `;
+    }
+}
+
+/**
+ * Checks if Alarm-Icon is shown on a given Event-Box.
+ *
+ * @param view          day, week, multiweek or month
+ * @param row           Only used in multiweek and month view, 1-based index of a row.
+ * @param column        1-based index of a column
+ */
+function checkAlarmIcon(controller, view, row, column) {
+    let { lookupEventBox } = helpersForController(controller);
+    controller.assertNode(lookupEventBox(view, EVENT_BOX, row, column, null, `
+        ${EVENTPATH}/${getEventDetails([view])}/${ALARM_ICON_PATH}
+    `));
+}
+
+/**
+ * Moves the view n times forward.
  *
  * @param controller    Mozmill window controller
- * @param n             how many times next button in view is clicked
+ * @param n             How many times next button in view is clicked.
  */
 function viewForward(controller, n) {
     let { eid, sleep } = helpersForController(controller);
 
     for (let i = 0; i < n; i++) {
         controller.click(eid("next-view-button"));
         sleep(SHORT_SLEEP);
     }
     ensureViewLoaded(controller);
 }
 
 /**
- * Moves the view n times back
+ * Moves the view n times back.
  *
  * @param controller    Mozmill window controller
- * @param n             how many times previous button in view is clicked
+ * @param n             How many times previous button in view is clicked.
  */
 function viewBack(controller, n) {
     let { eid, sleep } = helpersForController(controller);
 
     for (let i = 0; i < n; i++) {
         controller.click(eid("previous-view-button"));
         sleep(SHORT_SLEEP);
     }
     ensureViewLoaded(controller);
 }
 
 /**
- * Deletes all calendars with given name
+ * Deletes all calendars with given name.
  *
  * @param controller    Mozmill window controller
  * @param name          calendar name
  */
 function deleteCalendars(controller, name) {
     let { eid } = helpersForController(controller);
 
     let win = eid("messengerWindow").getNode().ownerGlobal;
@@ -441,404 +476,166 @@ function deleteCalendars(controller, nam
     for (let calendar of manager.getCalendars({})) {
         if (calendar.name == name) {
             manager.removeCalendar(calendar);
         }
     }
 }
 
 /**
- * Creates local calendar with given name and select it in calendars list
+ * Creates local calendar with given name and select it in calendars list.
  *
  * @param controller    Mozmill window controller
  * @param name          calendar name
  */
 function createCalendar(controller, name) {
     let { lookup, eid } = helpersForController(controller);
 
     let win = eid("messengerWindow").getNode().ownerGlobal;
     let manager = win.cal.getCalendarManager();
 
     let url = Services.io.newURI("moz-storage-calendar://");
     let calendar = manager.createCalendar("storage", url);
     calendar.name = name;
     manager.registerCalendar(calendar);
 
     let calendarTree = lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("ltnSidebar")/id("calendar-panel")/id("calendar-list-pane")/
+        ${CALENDAR_PANEL}/id("ltnSidebar")/id("calendar-panel")/id("calendar-list-pane")/
         id("calendar-listtree-pane")/id("calendar-list-tree-widget")
     `).getNode();
 
     for (let i = 0; i < calendarTree.mCalendarList.length; i++) {
         if (calendarTree.mCalendarList[i].id == calendar.id) {
             calendarTree.tree.view.selection.select(i);
         }
     }
 }
 
 /**
- * Handles the "Create New Calendar" Wizard
+ * Handles the "Create New Calendar" Wizard.
  *
  * @param wizard            wizard dialog controller
  * @param name              calendar name
  * @param data              (optional) dataset object
- *                              showReminders - false to disable reminders
+ *                              showReminders - False to disable reminders.
  *                              eMail - id of eMail account
  *                              network.format - ics/caldav/wcap
  *                              network.location - URI (undefined for local ICS)
- *                              network.offline - false to disable cache
+ *                              network.offline - False to disable cache.
  */
 function handleNewCalendarWizard(wizard, name, data = undefined) {
     let { lookup: wizardlookup, eid: wizardId } = helpersForController(wizard);
     let dlgButton = (btn) => wizard.window.document.documentElement.getButton(btn);
     if (data == undefined) {
         data = {};
     }
 
-    // choose network calendar if any network data is set.
+    // Choose network calendar if any network data is set.
     if (data.network) {
         let remoteOption = wizardlookup(`
-            /id("calendar-wizard")/{"pageid":"initialPage"}/
-            id("calendar-type")/{"value":"remote"}
+            /id("calendar-wizard")/{"pageid":"initialPage"}/id("calendar-type")/{"value":"remote"}
         `);
         wizard.waitForElement(remoteOption);
         wizard.radio(remoteOption);
         dlgButton("next").doCommand();
 
-        // choose format
+        // Choose format.
         if (data.network.format == undefined) {
             data.network.format = "ics";
         }
         let formatOption = wizardlookup(`
             /id("calendar-wizard")/{"pageid":"locationPage"}/[1]/[1]/[0]/
             id("calendar-format")/{"value":"${data.network.format}"}
         `);
         wizard.waitForElement(formatOption);
         wizard.radio(formatOption);
 
-        // enter location
+        // Enter location.
         if (data.network.location == undefined) {
             let calendarFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
             calendarFile.append(name + ".ics");
             let fileURI = Services.io.newFileURI(calendarFile);
             data.network.location = fileURI.prePath + fileURI.pathQueryRef;
         }
         wizard.type(wizardlookup(`
-            /id("calendar-wizard")/{"pageid":"locationPage"}/[1]/[1]/
-            {"align":"center"}/id("calendar-uri")/
-            anon({"anonid":"moz-input-box"})/anon({"anonid":"input"})
+            /id("calendar-wizard")/{"pageid":"locationPage"}/[1]/[1]/{"align":"center"}/
+            id("calendar-uri")/anon({"anonid":"moz-input-box"})/anon({"anonid":"input"})
         `), data.network.location);
 
-        // choose offline support
+        // Choose offline support.
         if (data.network.offline == undefined) {
             data.network.offline = true;
         }
         wizard.check(wizardId("cache"), data.network.offline);
         wizard.waitFor(() => !dlgButton("next").disabled);
         dlgButton("next").doCommand();
     } else {
-        // local calendar is default
+        // Local calendar is default.
         dlgButton("next").doCommand();
     }
-    // set calendar Name
+    // Set calendar Name.
     wizard.waitForElement(wizardId("calendar-name"));
-    // not on all platforms setting the value activates the next button
-    // so we need to type in case the field is empty
+    // Not on all platforms setting the value activates the next button,
+    // so we need to type in case the field is empty.
     if (wizardId("calendar-name").getNode().value == "") {
         wizard.type(wizardId("calendar-name"), name);
-    } // else the name is already filled in from URI
+    } // Else the name is already filled in from URI.
 
-    // set reminder Option
+    // Set reminder Option.
     if (data.showReminders == undefined) {
         data.showReminders = true;
     }
     wizard.check(wizardId("fire-alarms"), data.showReminders);
 
-    // set eMail Account
+    // Set eMail Account.
     if (data.eMail == undefined) {
         data.eMail = "none";
     }
     menulistSelect(wizardId("email-identity-menulist"), data.eMail, wizard);
     wizard.waitFor(() => !dlgButton("next").disabled);
     dlgButton("next").doCommand();
 
     // finish
     dlgButton("finish").doCommand();
 }
 
 /**
- * Retrieves array of all calendar-event-box elements in node
+ * Retrieves array of all calendar-event-box elements in node.
  *
- * @param node          node to be searched
- * @param eventNodes    array where to put resultíng nodes
+ * @param node          Node to be searched.
+ * @param eventNodes    Array where to put resulting nodes.
  */
 function findEventsInNode(node, eventNodes) {
     if (node.tagName == "calendar-event-box") {
         eventNodes.push(node);
     } else if (node.children.length > 0) {
         for (let child of node.children) {
             findEventsInNode(child, eventNodes);
         }
     }
 }
 
-/**
- * Helper function to enter event/task dialog data
- *
- * @param dialog        event/task dialog controller
- * @param iframe        event/task dialog iframe controller
- * @param data          dataset object
- *                          title - event/task title
- *                          location - event/task location
- *                          description - event/task description
- *                          category - category label
- *                          calendar - calendar the item should be in
- *                          allday - boolean value
- *                          startdate - Date object
- *                          starttime - Date object
- *                          enddate - Date object
- *                          endtime - Date object
- *                          repeat - reccurrence value, one of none/daily/weekly/
- *                                   every.weekday/bi.weekly/
- *                                   monthly/yearly
- *                                   (custom is not supported)
- *                          reminder - reminder option index (custom not supp.)
- *                          priority - none/low/normal/high
- *                          privacy - public/confidential/private
- *                          status - none/tentative/confirmed/canceled for events
- *                                   none/needs-action/in-process/completed/cancelled for tasks
- *                          completed - Date object for tasks
- *                          percent - percent complete for tasks
- *                          freebusy - free/busy
- *                          attachment.add - url to add
- *                          attachment.remove - label of url to remove (without http://)
- */
-function setData(dialog, iframe, data) {
-    let { eid, sleep } = helpersForController(dialog);
-    let { lookup: iframeLookup, eid: iframeId } = helpersForController(iframe);
-
-    let eventIframe = '/id("calendar-event-dialog-inner")/id("event-grid")/id("event-grid-rows")/';
-    let taskIframe = '/id("calendar-task-dialog-inner")/id("event-grid")/id("event-grid-rows")/';
-    let innerFrame;
-    let isEvent = true;
-
-    // see if it's an event dialog
-    try {
-        iframeLookup(eventIframe).getNode();
-        innerFrame = eventIframe;
-    } catch (error) {
-        innerFrame = taskIframe;
-        isEvent = false;
-    }
-
-    let dateInput = `
-        anon({"class":"datepicker-box-class"})/{"class":"datepicker-text-class"}/
-        anon({"class":"menulist-editable-box textbox-input-box"})/
-        anon({"anonid":"input"})
-    `;
-    let timeInput = `
-        anon({"anonid":"hbox"})/anon({"anonid":"time-picker"})/
-        anon({"class":"timepicker-box-class"})/
-        anon({"class":"timepicker-text-class"})/anon({"flex":"1"})/
-        anon({"anonid":"input"})
-    `;
-    let startId = isEvent ? "event-starttime" : "todo-entrydate";
-    let startDateInput = iframeLookup(`
-        ${innerFrame}/id("event-grid-startdate-row")/
-        id("event-grid-startdate-picker-box")/id("${startId}")/
-        anon({"anonid":"hbox"})/anon({"anonid":"date-picker"})/${dateInput}
-    `);
-    let endId = isEvent ? "event-endtime" : "todo-duedate";
-    let endDateInput = iframeLookup(`
-        ${innerFrame}id("event-grid-enddate-row")/[1]/
-        id("event-grid-enddate-picker-box")/id("${endId}")/
-        anon({"anonid":"hbox"})/anon({"anonid":"date-picker"})/${dateInput}
-    `);
-    let startTimeInput = iframeLookup(`
-        ${innerFrame}/id("event-grid-startdate-row")/
-        id("event-grid-startdate-picker-box")/id("${startId}")/${timeInput}
-    `);
-    let endTimeInput = iframeLookup(`
-        ${innerFrame}/id("event-grid-enddate-row")/[1]/
-        id("event-grid-enddate-picker-box")/id("${endId}")/${timeInput}
-    `);
-    let completedDateInput = iframeLookup(`
-        ${innerFrame}/id("event-grid-todo-status-row")/
-        id("event-grid-todo-status-picker-box")/id("completed-date-picker")/${dateInput}
-    `);
-    let dateFormatter = cal.getDateFormatter();
-    // wait for input elements' values to be populated
-    sleep();
-
-    // title
-    if (data.title != undefined) {
-        // we need to set directly here in case there is already a title.
-        // accelKey+a won't work in all OS
-        iframeId("item-title").getNode().value = data.title;
-    }
-
-    // location
-    if (data.location != undefined) {
-        // see comment above
-        iframeId("item-location").getNode().value = data.location;
-    }
-
-    // category
-    // TODO: needs adjustment for the menulist-panel now used for categories.
-    // will be fixed with Bug 984044
-    if (data.category != undefined) {
-        menulistSelect(iframeId("item-categories"), data.category, dialog);
-    }
-
-    // calendar
-    if (data.calendar != undefined) {
-        menulistSelect(iframeId("item-calendar"), data.calendar, dialog);
-    }
-
-    // all-day
-    if (data.allday != undefined && isEvent) {
-        dialog.check(iframeId("event-all-day"), data.allday);
-    }
-
-    // startdate
-    if (data.startdate != undefined && data.startdate.constructor.name == "Date") {
-        let startdate = dateFormatter.formatDateShort(cal.dtz.jsDateToDateTime(data.startdate, cal.dtz.floating));
-
-        if (!isEvent) {
-            dialog.check(iframeId("todo-has-entrydate"), true);
-        }
-        dialog.keypress(startDateInput, "a", { accelKey: true });
-        dialog.type(startDateInput, startdate);
-    }
-
-    // starttime
-    if (data.starttime != undefined && data.starttime.constructor.name == "Date") {
-        let starttime = dateFormatter.formatTime(cal.dtz.jsDateToDateTime(data.starttime, cal.dtz.floating));
-        dialog.click(startTimeInput);
-        dialog.keypress(startTimeInput, "a", { accelKey: true });
-        dialog.type(startTimeInput, starttime);
-    }
-
-    // enddate
-    if (data.enddate != undefined && data.enddate.constructor.name == "Date") {
-        let enddate = dateFormatter.formatDateShort(cal.dtz.jsDateToDateTime(data.enddate, cal.dtz.floating));
-        if (!isEvent) {
-            dialog.check(iframeId("todo-has-duedate"), true);
-        }
-        dialog.keypress(endDateInput, "a", { accelKey: true });
-        dialog.type(endDateInput, enddate);
-    }
-
-    // endtime
-    if (data.endtime != undefined && data.endtime.constructor.name == "Date") {
-        let endtime = dateFormatter.formatTime(cal.dtz.jsDateToDateTime(data.endtime, cal.dtz.floating));
-        dialog.click(endTimeInput);
-        dialog.keypress(endTimeInput, "a", { accelKey: true });
-        dialog.type(endTimeInput, endtime);
-    }
-
-    // recurrence
-    if (data.repeat != undefined) {
-        menulistSelect(iframeId("item-repeat"), data.repeat, dialog);
-    }
-
-    // reminder
-    // TODO: menulistSelect does not work here, because menuitems have no value.
-    // will be fixed with Bug 984044
-    if (data.reminder != undefined) {
-        menulistSelect(iframeId("item-alarm"), data.reminder, dialog);
-    }
-
-    // description
-    if (data.description != undefined) {
-        let descField = iframeId("item-description");
-        descField.getNode().value = data.description;
-    }
-
-    // priority
-    if (data.priority != undefined) {
-        dialog.mainMenu.click(`#options-priority-${data.priority}-label`);
-    }
-
-    // privacy
-    if (data.privacy != undefined) {
-        dialog.mainMenu.click(`#options-privacy-${data.privacy}-menuitem`);
-    }
-
-    // status
-    if (data.status != undefined) {
-        if (isEvent) {
-            dialog.mainMenu.click(`#options-status-${data.status}-menuitem`);
-        } else {
-            menulistSelect(iframeId("todo-status"), data.status.toUpperCase(), dialog);
-        }
-    }
-
-    let currentStatus = iframeId("todo-status").getNode().value;
-
-    // completed on
-    if (data.completed != undefined && data.completed.constructor.name == "Date" && !isEvent) {
-        let completeddate = dateFormatter.formatDateShort(cal.dtz.jsDateToDateTime(data.completed, cal.dtz.floating));
-
-        if (currentStatus == "COMPLETED") {
-            completedDateInput.getNode().value = completeddate;
-        }
-    }
-
-    // percent complete
-    if (data.percent != undefined &&
-        (currentStatus == "NEEDS-ACTION" ||
-         currentStatus == "IN-PROCESS" ||
-         currentStatus == "COMPLETED")) {
-        iframeId("percent-complete-textbox").getNode().value = data.percent;
-    }
-
-    // free/busy
-    if (data.freebusy != undefined) {
-        dialog.mainMenu.click(`#options-freebusy-${data.freebusy}-menuitem`);
-    }
-
-    // attachment
-    // TODO: Needs fixing,
-    // will be fixed with Bug 984044
-    if (data.attachment != undefined) {
-        if (data.attachment.add != undefined) {
-            handleAddingAttachment(dialog, data.attachment.add);
-            dialog.click(eid("button-url"));
-            wait_for_modal_dialog("commonDialog");
-        }
-        if (data.attachment.delete != undefined) {
-            dialog.click(iframeLookup(`
-                ${innerFrame}/id("event-grid-attachment-row")/id("attachment-link")/
-                {"label":"${data.attachment.delete}"}
-            `));
-            dialog.keypress(iframeId("attachment-link"), "VK_DELETE", {});
-        }
-    }
-    dialog.click(iframeId("item-title"));
-    sleep();
-}
-
 function openLightningPrefs(aCallback, aParentController) {
-    // Since the Lightning pane is added after load, asking for it with open_pref_tab won't work. Cheat instead.
+    // Since the Lightning pane is added after load, asking for it with open_pref_tab won't work.
+    // Cheat instead.
     let tab = open_pref_tab("paneGeneral");
     tab.browser.contentDocument.querySelector('#category-box radio[pane="paneLightning"]').click();
-    utils.waitFor(() => tab.browser.contentDocument.documentElement.currentPane.id == "paneLightning",
-                  "Timed out waiting for prefpane paneLightning to load.");
+    utils.waitFor(
+        () => tab.browser.contentDocument.documentElement.currentPane.id == "paneLightning",
+        "Timed out waiting for prefpane paneLightning to load."
+    );
     aCallback(tab);
 }
 
 /**
  * Helper to work around a mac bug in Thunderbird's mozmill version. This can
  * likely be removed with Mozmill 2.0's new Element Object.
  *
- * @param aMenuList     The XUL menulist to select in
- * @param aValue        The value assigned to the desired menuitem
+ * @param aMenuList     The XUL menulist to select in.
+ * @param aValue        The value assigned to the desired menuitem.
  * @param aController   The mozmill controller associated to the menulist.
  */
 function menulistSelect(aMenuList, aValue, aController) {
     aController.waitForElement(aMenuList);
     let menulist = aMenuList.getNode();
     let menuitem = menulist.querySelector(`menupopup > menuitem[value='${aValue}']`);
     menulist.click();
     menuitem.click();
new file mode 100755
--- /dev/null
+++ b/calendar/test/mozmill/shared-modules/test-item-editing-helpers.js
@@ -0,0 +1,551 @@
+/* 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 MODULE_NAME = "item-editing-helpers";
+var RELATIVE_ROOT = "../shared-modules";
+var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+
+var EventUtils = {};
+ChromeUtils.import("chrome://mozmill/content/stdlib/EventUtils.js", EventUtils);
+var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
+
+var SHORT_SLEEP, TIMEOUT_MODAL_DIALOG;
+var helpersForController, menulistSelect;
+var plan_for_modal_dialog, wait_for_modal_dialog;
+
+function setupModule(module) {
+    controller = mozmill.getMail3PaneController();
+    ({
+        SHORT_SLEEP,
+        TIMEOUT_MODAL_DIALOG,
+        helpersForController,
+        menulistSelect
+    } = collector.getModule("calendar-utils"));
+    Object.assign(module, helpersForController(controller));
+
+    ({ plan_for_modal_dialog, wait_for_modal_dialog } =
+        collector.getModule("window-helpers"));
+}
+// Lookup paths and path-snippets.
+// These 5 have to be used with itemEditLookup().
+var CATEGORY_LIST = `
+    id("event-grid-category-color-row")/id("event-grid-category-box")/id("item-categories")/
+    id("item-categories-popup")
+`;
+var REPEAT_DETAILS = `
+    id("event-grid-recurrence-row")/id("event-grid-recurrence-picker-box")/id("repeat-deck")/
+    id("repeat-details")/[0]
+`;
+var EVENT_TABPANELS = `
+    id("event-grid-tabbox")/id("event-grid-tabpanels")
+`;
+var DESCRIPTION_TEXTBOX = `
+    ${EVENT_TABPANELS}/id("event-grid-tabpanel-description")/id("item-description")/
+    anon({"anonid":"moz-input-box"})/anon({"class":"textbox-textarea"})
+`;
+var ATTENDEES_ROW = `
+    ${EVENT_TABPANELS}/id("event-grid-tabpanel-attendees")/{"flex":"1"}/
+    {"flex":"1"}/id("item-attendees-box")/{"class":"item-attendees-row"}
+`;
+// Only for Tasks.
+var PERCENT_COMPLETE_INPUT = `
+    id("event-grid-todo-status-row")/id("event-grid-todo-status-picker-box")/
+    id("percent-complete-textbox")/anon({"class":"textbox-input-box numberbox-input-box"})/
+    anon({"anonid":"input"})
+`;
+
+// To be appended to the path for a date- or timepicker.
+var DATE_INPUT = `
+    anon({"class":"datepicker-box-class"})/{"class":"datepicker-text-class"}/
+    anon({"class":"menulist-editable-box textbox-input-box"})/anon({"anonid":"input"})
+`;
+var TIME_INPUT = `
+    anon({"anonid":"hbox"})/anon({"anonid":"time-picker"})/anon({"class":"timepicker-box-class"})/
+    anon({"class":"timepicker-text-class"})/anon({"flex":"1"})/anon({"anonid":"input"})
+`;
+
+// The following can be used as is.
+var REC_DLG_ACCEPT = `
+    /id("calendar-event-dialog-recurrence")/anon({"anonid":"buttons"})/{"dlgtype":"accept"}
+`;
+var REC_DLG_DAYS = `
+    /id("calendar-event-dialog-recurrence")/id("recurrence-pattern-groupbox")/
+    id("recurrence-pattern-grid")/id("recurrence-pattern-rows")/id("recurrence-pattern-period-row")/
+    id("period-deck")/id("period-deck-weekly-box")/[1]/id("daypicker-weekday")/
+    anon({"anonid":"mainbox"})
+`;
+var REC_DLG_UNTIL_INPUT = `
+    /id("calendar-event-dialog-recurrence")/id("recurrence-range-groupbox")/[1]/
+    id("recurrence-duration")/id("recurrence-range-until-box")/id("repeat-until-date")/
+    anon({"class":"datepicker-box-class"})/{"class":"datepicker-text-class"}/
+    anon({"class":"menulist-editable-box textbox-input-box"})/anon({"anonid":"input"})
+`;
+
+
+function installInto(module) {
+    // Copy constants into module.
+    module.CATEGORY_LIST = CATEGORY_LIST;
+    module.REPEAT_DETAILS = REPEAT_DETAILS;
+    module.EVENT_TABPANELS = EVENT_TABPANELS;
+    module.DESCRIPTION_TEXTBOX = DESCRIPTION_TEXTBOX;
+    module.ATTENDEES_ROW = ATTENDEES_ROW;
+    module.PERCENT_COMPLETE_INPUT = PERCENT_COMPLETE_INPUT;
+    module.DATE_INPUT = DATE_INPUT;
+    module.TIME_INPUT = TIME_INPUT;
+    module.REC_DLG_ACCEPT = REC_DLG_ACCEPT;
+    module.REC_DLG_DAYS = REC_DLG_DAYS;
+    module.REC_DLG_UNTIL_INPUT = REC_DLG_UNTIL_INPUT;
+    // Now copy helper functions.
+    module.helpersForEditUI = helpersForEditUI;
+    module.setData = setData;
+    module.setReminderMenulist = setReminderMenulist;
+    module.setCategories = setCategories;
+    module.handleAddingAttachment = handleAddingAttachment;
+    module.acceptSendingNotificationMail = acceptSendingNotificationMail;
+}
+
+function helpersForEditUI(controller) {
+    function selector(sel) {
+        return sel.trim().replace(/\n(\s*)/g, "");
+    }
+
+    let isEvent = cal.isEvent(controller.window.calendarItem);
+
+    let obj = {
+        iframeLookup: (path) => {
+            let type = isEvent ? "event" : "task";
+            return new elementslib.Lookup(controller.window.document, selector(`
+                /id("calendar-${type}-dialog-inner")/id("event-grid")/id("event-grid-rows")/
+                ${path}
+            `));
+        },
+        getDateTimePicker: (id) => {
+            let startId = isEvent ? "event-starttime" : "todo-entrydate";
+            let endId = isEvent ? "event-endtime" : "todo-duedate";
+            let path;
+            switch (id) {
+                case "STARTDATE":
+                    path = `
+                        id("event-grid-startdate-row")/id("event-grid-startdate-picker-box")/
+                        id("${startId}")/anon({"anonid":"hbox"})/anon({"anonid":"date-picker"})/
+                        ${DATE_INPUT}
+                    `;
+                    break;
+                case "ENDDATE":
+                    path = `
+                        id("event-grid-enddate-row")/[1]/id("event-grid-enddate-picker-box")/
+                        id("${endId}")/anon({"anonid":"hbox"})/anon({"anonid":"date-picker"})/
+                        ${DATE_INPUT}
+                    `;
+                    break;
+                case "STARTTIME":
+                    path = `
+                        id("event-grid-startdate-row")/id("event-grid-startdate-picker-box")/
+                        id("${startId}")/${TIME_INPUT}
+                    `;
+                    break;
+                case "ENDTIME":
+                    path = `
+                        id("event-grid-enddate-row")/[1]/id("event-grid-enddate-picker-box")/
+                        id("${endId}")/${TIME_INPUT}
+                    `;
+                    break;
+                case "UNTILDATE":
+                    path = `
+                        id("event-grid-recurrence-row")/id("event-grid-recurrence-picker-box")/
+                        id("repeat-deck")/id("repeat-untilDate")/id("repeat-until-datepicker")/
+                        ${DATE_INPUT}
+                    `;
+                    break;
+                case "COMPLETEDDATE":
+                    path = `
+                        id("event-grid-todo-status-row")/
+                        id("event-grid-todo-status-picker-box")/id("completed-date-picker")/
+                        ${DATE_INPUT}
+                    `;
+                    break;
+            }
+            return obj.iframeLookup(path);
+        }
+    };
+    return obj;
+}
+
+/**
+ * Helper function to enter event/task dialog data.
+ *
+ * @param dialog    event/task dialog controller
+ * @param iframe    event/task dialog iframe controller
+ * @param data      dataset object
+ *                      title - event/task title
+ *                      location - event/task location
+ *                      description - event/task description
+ *                      categories - array of category names
+ *                      calendar - Calendar the item should be in.
+ *                      allday - boolean value
+ *                      startdate - Date object
+ *                      starttime - Date object
+ *                      enddate - Date object
+ *                      endtime - Date object
+ *                      timezonedisplay - False for hidden, true for shown.
+ *                      repeat - reccurrence value, one of none/daily/weekly/
+ *                               every.weekday/bi.weekly/
+ *                               monthly/yearly
+ *                               (Custom is not supported.)
+ *                      repeatuntil - Date object
+ *                      reminder - none/0minutes/5minutes/15minutes/30minutes
+ *                                 1hour/2hours/12hours/1day/2days/1week
+ *                                 (Custom is not supported.)
+ *                      priority - none/low/normal/high
+ *                      privacy - public/confidential/private
+ *                      status - none/tentative/confirmed/canceled for events
+ *                               none/needs-action/in-process/completed/cancelled for tasks
+ *                      completed - Date object for tasks
+ *                      percent - percent complete for tasks
+ *                      freebusy - free/busy
+ *                      attachment.add - url to add
+ *                      attachment.remove - Label of url to remove. (without http://)
+ *                      attendees.add - eMail of attendees to add, comma separated.
+ *                      attendees.remove - eMail of attendees to remove, comma separated.
+ */
+function setData(dialog, iframe, data) {
+    let { eid, sleep, replaceText } = helpersForController(dialog);
+    let { eid: iframeid } = helpersForController(iframe);
+    let { iframeLookup, getDateTimePicker } = helpersForEditUI(iframe);
+
+    let isEvent = cal.isEvent(iframe.window.calendarItem);
+
+    let startdateInput = getDateTimePicker("STARTDATE");
+    let enddateInput = getDateTimePicker("ENDDATE");
+    let starttimeInput = getDateTimePicker("STARTTIME");
+    let endtimeInput = getDateTimePicker("ENDTIME");
+    let completeddateInput = getDateTimePicker("COMPLETEDDATE");
+    let percentCompleteInput = iframeLookup(PERCENT_COMPLETE_INPUT);
+    let untilDateInput = getDateTimePicker("UNTILDATE");
+
+    let dateFormatter = cal.getDateFormatter();
+    // Wait for input elements' values to be populated.
+    sleep();
+
+    // title
+    if (data.title != undefined) {
+        titleInput = iframeid("item-title");
+        replaceText(titleInput, data.title);
+    }
+
+    // location
+    if (data.location != undefined) {
+        locationInput = iframeid("item-location");
+        replaceText(locationInput, data.location);
+    }
+
+    // categories
+    if (data.categories != undefined) {
+        setCategories(dialog, iframe, data.categories);
+    }
+
+    // calendar
+    if (data.calendar != undefined) {
+        menulistSelect(iframeid("item-calendar"), data.calendar, dialog);
+    }
+
+    // all-day
+    if (data.allday != undefined && isEvent) {
+        dialog.check(iframeid("event-all-day"), data.allday);
+    }
+
+    // timezonedisplay
+    if (data.timezonedisplay !== undefined) {
+        let menuitem = eid("options-timezones-menuitem");
+        if (menuitem.getNode().getAttribute("checked") != data.timezonedisplay) {
+            dialog.click(menuitem);
+        }
+    }
+
+    // startdate
+    if (data.startdate != undefined && data.startdate.constructor.name == "Date") {
+        let startdate = dateFormatter.formatDateShort(
+            cal.dtz.jsDateToDateTime(data.startdate, cal.dtz.floating)
+        );
+
+        if (!isEvent) {
+            dialog.check(iframeid("todo-has-entrydate"), true);
+        }
+        replaceText(startdateInput, startdate);
+    }
+
+    // starttime
+    if (data.starttime != undefined && data.starttime.constructor.name == "Date") {
+        let starttime = dateFormatter.formatTime(
+            cal.dtz.jsDateToDateTime(data.starttime, cal.dtz.floating)
+        );
+        replaceText(starttimeInput, starttime);
+        sleep();
+    }
+
+    // enddate
+    if (data.enddate != undefined && data.enddate.constructor.name == "Date") {
+        let enddate = dateFormatter.formatDateShort(
+            cal.dtz.jsDateToDateTime(data.enddate, cal.dtz.floating)
+        );
+        if (!isEvent) {
+            dialog.check(iframeid("todo-has-duedate"), true);
+        }
+        replaceText(enddateInput, enddate);
+    }
+
+    // endtime
+    if (data.endtime != undefined && data.endtime.constructor.name == "Date") {
+        let endtime = dateFormatter.formatTime(
+            cal.dtz.jsDateToDateTime(data.endtime, cal.dtz.floating)
+        );
+        replaceText(endtimeInput, endtime);
+    }
+
+    // recurrence
+    if (data.repeat != undefined) {
+        menulistSelect(iframeid("item-repeat"), data.repeat, dialog);
+    }
+    if (data.repeatuntil != undefined && data.repeatuntil.constructor.name == "Date") {
+        // Only fill in date, when the Datepicker is visible.
+        if (iframeid("repeat-deck").getNode().selectedIndex == 0) {
+            let untildate = dateFormatter.formatDateShort(
+                cal.dtz.jsDateToDateTime(data.repeatuntil, cal.dtz.floating)
+            );
+            replaceText(untilDateInput, untildate);
+        }
+    }
+
+    // reminder
+    if (data.reminder != undefined) {
+        setReminderMenulist(dialog, iframeid("item-alarm").getNode(), data.reminder);
+    }
+
+    // priority
+    if (data.priority != undefined) {
+        dialog.mainMenu.click(`#options-priority-${data.priority}-label`);
+    }
+
+    // privacy
+    if (data.privacy != undefined) {
+        let toolbarbutton = eid("button-privacy");
+        let rect = toolbarbutton.getNode().getBoundingClientRect();
+        dialog.click(toolbarbutton, rect.width - 5, 5);
+        dialog.mainMenu.click(`#options-privacy-${data.privacy}-menuitem`);
+        // For some reason, the dialog does not close by itself.
+        dialog.click(toolbarbutton, rect.width - 5, 5);
+    }
+
+    // status
+    if (data.status != undefined) {
+        if (isEvent) {
+            dialog.mainMenu.click(`#options-status-${data.status}-menuitem`);
+        } else {
+            menulistSelect(iframeid("todo-status"), data.status.toUpperCase(), dialog);
+        }
+    }
+
+    let currentStatus = iframeid("todo-status").getNode().value;
+
+    // completed on
+    if (data.completed != undefined && data.completed.constructor.name == "Date" && !isEvent) {
+        let completeddate = dateFormatter.formatDateShort(
+            cal.dtz.jsDateToDateTime(data.completed, cal.dtz.floating)
+        );
+        if (currentStatus == "COMPLETED") {
+            replaceText(completeddateInput, completeddate);
+        }
+    }
+
+    // percent complete
+    if (data.percent != undefined &&
+        (currentStatus == "NEEDS-ACTION" ||
+         currentStatus == "IN-PROCESS" ||
+         currentStatus == "COMPLETED")) {
+        replaceText(percentCompleteInput, data.percent);
+    }
+
+    // free/busy
+    if (data.freebusy != undefined) {
+        dialog.mainMenu.click(`#options-freebusy-${data.freebusy}-menuitem`);
+    }
+
+    // description
+    if (data.description != undefined) {
+        dialog.click(iframeid("event-grid-tab-description"));
+        let descField = iframeLookup(DESCRIPTION_TEXTBOX);
+        replaceText(descField, data.description);
+    }
+
+    // attachment
+    if (data.attachment != undefined) {
+        if (data.attachment.add != undefined) {
+            handleAddingAttachment(dialog, data.attachment.add);
+        }
+        if (data.attachment.remove != undefined) {
+            dialog.click(iframeid("event-grid-tab-attachments"));
+            let attachmentBox = iframeid("attachment-link");
+            let attachments = attachmentBox.getNode().childNodes;
+            if (attachments) {
+                let attToDelete;
+                attachments.forEach((currentValue) => {
+                    if (currentValue.tooltipText.includes(data.attachment.remove)) {
+                        attToDelete = currentValue;
+                    }
+                    if (attToDelete) {
+                        dialog.click(new elementslib.Elem(attToDelete));
+                        dialog.keypress(attachmentBox, "VK_DELETE", {});
+                        attToDelete = undefined;
+                    }
+                });
+            }
+        }
+    }
+
+    // attendees
+    if (data.attendees != undefined) {
+        // Display attendees Tab.
+        dialog.click(iframeid("event-grid-tab-attendees"));
+        // Make sure no notifications are sent, since handling this dialog is
+        // not working when deleting a parent of a recurring event.
+        let attendeeCheckbox = iframeid("notify-attendees-checkbox");
+        if (!attendeeCheckbox.getNode().disabled) {
+            dialog.check(attendeeCheckbox, false);
+        }
+
+        // add
+        if (data.attendees.add != undefined) {
+            addAttendees(dialog, iframe, data.attendees.add);
+        }
+        // delete
+        if (data.attendees.remove != undefined) {
+            deleteAttendees(dialog, iframe, data.attendees.remove);
+        }
+    }
+
+    sleep(SHORT_SLEEP);
+}
+
+/**
+ * Select an item in the reminder menulist.
+ * Custom reminders are not supported.
+ *
+ * @param controller      Mozmill controller of item-Iframe:
+ * @param menulist        The reminder menulist node.
+ * @param id              Identifying string of menuitem id.
+ */
+function setReminderMenulist(controller, menulist, id) {
+    let { eid } = helpersForController(controller);
+
+    let menuitem = eid(`reminder-${id}-menuitem`);
+    menulist.click();
+    controller.click(menuitem);
+    controller.waitFor(() => {
+        return menulist.selectedItem.id == `reminder-${id}-menuitem`;
+    });
+}
+
+/**
+ * Set the categories in the event-dialog menulist-panel.
+ *
+ * @param dialog      Mozmill controller of event-dialog.
+ * @param iframe      Controller of the iframe of the dialog.
+ * @param index       Array containing the categories as strings - leave empty to clear.
+ */
+function setCategories(dialog, iframe, categories) {
+    let { eid: iframeid } = helpersForController(iframe);
+    let { iframeLookup } = helpersForEditUI(iframe);
+    let categoryMenulist = iframeid("item-categories");
+    let categoryList = iframeLookup(CATEGORY_LIST);
+    dialog.click(categoryMenulist);
+    dialog.waitFor(() => categoryMenulist.getNode().open);
+    if (categoryMenulist.itemCount > -1 && categoryMenulist.itemCount < data.categories.length) {
+        mark_failure(["more categories than supported by current calendar"]);
+    } else {
+        // Iterate over categories and check if needed.
+        let listItems = categoryList.getNode().childNodes;
+        for (let item of listItems) {
+            let set = false;
+            if (categories.includes(item.label)) {
+                set = true;
+            }
+            if (set && !item.getAttribute("checked")) {
+                item.setAttribute("checked", true);
+            } else if (!set && item.getAttribute("checked")) {
+                item.removeAttribute("checked");
+            }
+        }
+    }
+    dialog.click(categoryMenulist);
+}
+
+/**
+ * Add an attachment with url.
+ *
+ * @param controller        Mozmill window controller
+ */
+function handleAddingAttachment(controller, url) {
+    let { eid } = helpersForController(controller);
+    plan_for_modal_dialog("commonDialog", (attachment) => {
+        let { lookup: cdlglookup, eid: cdlgid } = helpersForController(attachment);
+        attachment.waitForElement(cdlgid("loginTextbox"));
+        cdlgid("loginTextbox").getNode().value = url;
+        attachment.click(cdlglookup(`
+            /id("commonDialog")/anon({"anonid":"buttons"})/{"dlgtype":"accept"}
+        `));
+    });
+    controller.click(eid("button-url"));
+
+    wait_for_modal_dialog("commonDialog", TIMEOUT_MODAL_DIALOG);
+}
+
+function addAttendees(dialog, innerFrame, attendeesString) {
+    let { eid: dlgid } = helpersForController(dialog);
+
+    let attendees = attendeesString.split(",");
+    for (var attendee of attendees) {
+        let calAttendee = innerFrame.window.attendees.find(
+            aAtt => aAtt.id == `mailto:${attendee}`
+        );
+        // Only add if not already present.
+        if (!calAttendee) {
+            plan_for_modal_dialog("Calendar:EventDialog:Attendees", (attDialog) => {
+                let { lookup: attlookup, sleep: attsleep } = helpersForController(attDialog);
+
+                let input = attlookup(`
+                    /id("calendar-event-dialog-attendees-v2")/
+                    anon({"class":"box-inherit dialog-content-box"})
+                `);
+                // As starting point is always the last entered Attendee, we have
+                // to advance to not overwrite it.
+                attDialog.keypress(input, "VK_TAB", {});
+                attsleep(SHORT_SLEEP);
+                attDialog.type(input, attendee);
+                attDialog.click(attlookup(`
+                    /id("calendar-event-dialog-attendees-v2")/anon({"anonid":"buttons"})/
+                    {"dlgtype":"accept"}
+                `));
+            });
+            dialog.click(dlgid("button-attendees"));
+            wait_for_modal_dialog("Calendar:EventDialog:Attendees", TIMEOUT_MODAL_DIALOG);
+        }
+    }
+}
+
+function deleteAttendees(event, innerFrame, attendeesString) {
+    let { iframeLookup } = helpersForEditUI(innerFrame);
+
+    // Now delete the attendees.
+    let attendees = attendeesString.split(",");
+    for (var attendee of attendees) {
+        let attendeeToDelete = iframeLookup(`${ATTENDEES_ROW}/{"attendeeid":"mailto:${attendee}"}`);
+        // Unfortunately the context menu of the attendees is not working in
+        // Mozmill tests. Thus we have to use the JS-functions.
+        let calAttendee = innerFrame.window.attendees.find(aAtt => aAtt.id == `mailto:${attendee}`);
+        if (calAttendee) {
+            innerFrame.window.removeAttendee(calAttendee);
+        }
+        event.waitForElementNotPresent(attendeeToDelete);
+    }
+}
--- a/calendar/test/mozmill/testAlarmDefaultValue.js
+++ b/calendar/test/mozmill/testAlarmDefaultValue.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * Test default alarm settings for events and tasks
  */
 
 var MODULE_NAME = "testAlarmDefaultValue";
 var RELATIVE_ROOT = "./shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "keyboard-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "content-tab-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 ChromeUtils.import("resource://gre/modules/PluralForm.jsm");
 ChromeUtils.import("resource://gre/modules/Preferences.jsm");
 
 const DEFVALUE = 43;
 
 var helpersForController, invokeEventDialog, openLightningPrefs, menulistSelect;
@@ -21,89 +21,84 @@ var helpersForController, invokeEventDia
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
         helpersForController,
         invokeEventDialog,
         openLightningPrefs,
         menulistSelect
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
+    Object.assign(module, helpersForController(controller));
+
     collector.getModule("content-tab-helpers").installInto(module);
-    Object.assign(module, helpersForController(controller));
 }
 
 function testDefaultAlarms() {
     let localeUnitString = cal.l10n.getCalString("unitDays");
     let unitString = PluralForm.get(DEFVALUE, localeUnitString).replace("#1", DEFVALUE);
     let alarmString = (...args) => cal.l10n.getString("calendar-alarms", ...args);
     let originStringEvent = alarmString("reminderCustomOriginBeginBeforeEvent");
     let originStringTask = alarmString("reminderCustomOriginBeginBeforeTask");
     let expectedEventReminder = alarmString("reminderCustomTitle", [unitString, originStringEvent]);
     let expectedTaskReminder = alarmString("reminderCustomTitle", [unitString, originStringTask]);
 
-    // Configure the lightning preferences
+    let detailPath = `
+        //*[@id="reminder-details"]/*[local-name()="label" and (not(@hidden) or @hidden="false")]
+    `;
+
+    // Configure the lightning preferences.
     openLightningPrefs(handlePrefDialog, controller);
 
-    // Create New Event
+    // Create New Event.
     controller.click(eid("newMsgButton-calendar-menuitem"));
 
-    // Set up the event dialog controller
+    // Set up the event dialog controller.
     invokeEventDialog(controller, null, (event, iframe) => {
         let { xpath: eventpath, eid: eventid } = helpersForController(event);
 
-        // Check if the "custom" item was selected
+        // Check if the "custom" item was selected.
         event.assertDOMProperty(eventid("item-alarm"), "value", "custom");
-        let reminderDetailsVisible = eventpath(`
-            //*[@id="reminder-details"]/
-            *[local-name()="label" and (not(@hidden) or @hidden="false")]
-        `);
+        let reminderDetailsVisible = eventpath(detailPath);
         event.assertDOMProperty(reminderDetailsVisible, "value", expectedEventReminder);
 
-        // Close the event dialog
+        // Close the event dialog.
         event.window.close();
     });
 
-    // Create New Task
+    // Create New Task.
     controller.click(eid("newMsgButton-task-menuitem"));
     invokeEventDialog(controller, null, (task, iframe) => {
         let { xpath: taskpath, eid: taskid } = helpersForController(task);
 
-        // Check if the "custom" item was selected
+        // Check if the "custom" item was selected.
         task.assertDOMProperty(taskid("item-alarm"), "value", "custom");
-        let reminderDetailsVisible = taskpath(`
-            //*[@id="reminder-details"]/
-            *[local-name()="label" and (not(@hidden) or @hidden="false")]
-        `);
+        let reminderDetailsVisible = taskpath(detailPath);
         task.assertDOMProperty(reminderDetailsVisible, "value", expectedTaskReminder);
 
-        // Close the task dialog
+        // Close the task dialog.
         task.window.close();
     });
 }
 
 function handlePrefDialog(tab) {
-    // Click on the alarms tab
+    // Click on the alarms tab.
     content_tab_e(tab, "calPreferencesTabAlarms").click();
 
-    // Turn on alarms for events and tasks
+    // Turn on alarms for events and tasks.
     menulistSelect(content_tab_eid(tab, "eventdefalarm"), "1", controller);
     menulistSelect(content_tab_eid(tab, "tododefalarm"), "1", controller);
 
-    // Selects "days" as a unit
+    // Selects "days" as a unit.
     menulistSelect(content_tab_eid(tab, "tododefalarmunit"), "days", controller);
     menulistSelect(content_tab_eid(tab, "eventdefalarmunit"), "days", controller);
 
-    // Sets default alarm length for events to DEFVALUE
+    // Sets default alarm length for events to DEFVALUE.
     let eventdefalarmlen = content_tab_eid(tab, "eventdefalarmlen");
-    controller.click(eventdefalarmlen);
-    controller.keypress(eventdefalarmlen, "a", { accelKey: true });
-    controller.type(eventdefalarmlen, DEFVALUE.toString());
+    replaceText(eventdefalarmlen, DEFVALUE.toString());
 
     let tododefalarmlen = content_tab_eid(tab, "tododefalarmlen");
-    controller.click(tododefalarmlen);
-    controller.keypress(tododefalarmlen, "a", { accelKey: true });
-    controller.type(tododefalarmlen, DEFVALUE.toString());
+    replaceText(tododefalarmlen, DEFVALUE.toString());
 }
 
 function teardownTest(module) {
     Preferences.resetBranch("calendar.alarms");
 }
--- a/calendar/test/mozmill/testBasicFunctionality.js
+++ b/calendar/test/mozmill/testBasicFunctionality.js
@@ -3,109 +3,93 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var MODULE_NAME = "testBasicFunctionality";
 var RELATIVE_ROOT = "./shared-modules";
 var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
+var TIMEOUT_MODAL_DIALOG, CALENDARNAME, CALENDAR_PANEL, DAY_VIEW, DAYBOX, MINIMONTH, CALENDARLIST;
+var helpersForController, switchToView, deleteCalendars, handleNewCalendarWizard;
 var plan_for_modal_dialog, wait_for_modal_dialog;
-var helpersForController, deleteCalendars, handleNewCalendarWizard;
-var TIMEOUT_MODAL_DIALOG, CALENDARNAME;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
-    ({ plan_for_modal_dialog, wait_for_modal_dialog } =
-        collector.getModule("window-helpers"));
     ({
+        TIMEOUT_MODAL_DIALOG,
+        CALENDARNAME,
+        CALENDAR_PANEL,
+        DAY_VIEW,
+        DAYBOX,
+        MINIMONTH,
+        CALENDARLIST,
         helpersForController,
+        switchToView,
         deleteCalendars,
-        handleNewCalendarWizard,
-        TIMEOUT_MODAL_DIALOG,
-        CALENDARNAME
+        handleNewCalendarWizard
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
+
+    ({ plan_for_modal_dialog, wait_for_modal_dialog } = collector.getModule("window-helpers"));
 }
 
 function testSmokeTest() {
     let dateFormatter = cal.getDateFormatter();
-    let path = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")
-    `;
 
-    // open calendar view
-    controller.click(eid("calendar-tab-button"));
-
-    // check for minimonth
+    // Check for minimonth.
     controller.waitForElement(eid("calMinimonth"));
-    // every month has a first
+    // Every month has a first.
     controller.assertNode(lookup(`
-        ${path}/id("ltnSidebar")/id("minimonth-pane")/{"align":"center"}/
-        id("calMinimonthBox")/id("calMinimonth")/
-        anon({"anonid":"minimonth-calendar"})/[3]/{"aria-label":"1"}
+        ${MINIMONTH}/anon({"anonid":"minimonth-calendar"})/[3]/{"aria-label":"1"}
     `));
 
-    // check for calendar list
+    // Check for calendar list.
     controller.assertNode(eid("calendar-list-pane"));
-    controller.assertNode(lookup(`
-        ${path}/id("ltnSidebar")/id("calendar-panel")/id("calendar-list-pane")/
-        id("calendar-listtree-pane")/id("calendar-list-tree-widget")/
-        anon({"anonid":"tree"})/anon({"anonid":"treechildren"})
-    `));
+    controller.assertNode(lookup(CALENDARLIST));
 
-    // check for event search
+    // Check for event search.
     controller.assertNode(eid("bottom-events-box"));
-    // there should be search field
+    // There should be search field.
     controller.assertNode(eid("unifinder-search-field"));
 
-    controller.click(eid("calendar-day-view-button"));
+    switchToView(controller, "day");
 
-    // default view is day view which should have 09:00 label and box
+    // Default view is day view which should have 09:00 label and box.
     let someTime = cal.createDateTime();
     someTime.resetTo(someTime.year, someTime.month, someTime.day, 9, 0, 0, someTime.timezone);
     let label = dateFormatter.formatTime(someTime);
     controller.assertNode(lookup(`
-        ${path}/id("calendarDisplayDeck")/id("calendar-view-box")/
-        id("view-deck")/id("day-view")/anon({"anonid":"mainbox"})/
-        anon({"anonid":"scrollbox"})/anon({"anonid":"timebar"})/
-        anon({"anonid":"topbox"})/[9]/
+        ${DAY_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
+        anon({"anonid":"timebar"})/anon({"anonid":"topbox"})/[9]/
         {"class":"calendar-time-bar-label","value":"${label}"}
     `));
     controller.assertNode(lookup(`
-        ${path}/id("calendarDisplayDeck")/id("calendar-view-box")/
-        id("view-deck")/id("day-view")/anon({"anonid":"mainbox"})/
-        anon({"anonid":"scrollbox"})/anon({"anonid":"daybox"})/
-        [0]/anon({"anonid":"boxstack"})/anon({"anonid":"bgbox"})/[9]
+        ${DAY_VIEW}/${DAYBOX}/[0]/anon({"anonid":"boxstack"})/anon({"anonid":"bgbox"})/[9]
     `));
 
-    // open tasks view
+    // Open tasks view.
     controller.click(eid("task-tab-button"));
-    // should be possible to filter today's tasks
+    // Should be possible to filter today's tasks.
     controller.waitForElement(eid("opt_today_filter"));
-    // check for task add button
+    // Check for task add button.
     controller.assertNode(eid("calendar-add-task-button"));
-    // check for filtered tasks list
+    // Check for filtered tasks list.
     controller.assertNode(lookup(`
-        ${path}/id("calendarDisplayDeck")/id("calendar-task-box")/[1]/
+        ${CALENDAR_PANEL}/id("calendarDisplayDeck")/id("calendar-task-box")/[1]/
         id("calendar-task-tree")/anon({"anonid":"calendar-task-tree"})/
         {"tooltip":"taskTreeTooltip"}
     `));
 
-    // create test calendar
+    // Create test calendar.
     plan_for_modal_dialog("Calendar:NewCalendarWizard", (wizard) => {
         handleNewCalendarWizard(wizard, CALENDARNAME);
     });
-    let calendarList = lookup(`
-        ${path}/id("ltnSidebar")/id("calendar-panel")/id("calendar-list-pane")/
-        id("calendar-listtree-pane")/id("calendar-list-tree-widget")/
-        anon({"anonid":"tree"})/anon({"anonid":"treechildren"})
-    `);
-    // double click on bottom left
+    let calendarList = lookup(CALENDARLIST);
+    // Double click on bottom left.
     controller.doubleClick(calendarList, 0, calendarList.getNode().boxObject.height);
     wait_for_modal_dialog("Calendar:NewCalendarWizard", TIMEOUT_MODAL_DIALOG);
 }
 
 function teardownTest(module) {
-    deleteCalendars(controller, "Mozmill");
+    deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/testLocalICS.js
+++ b/calendar/test/mozmill/testLocalICS.js
@@ -1,87 +1,87 @@
 /* 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 MODULE_NAME = "testLocalICS";
 var RELATIVE_ROOT = "./shared-modules";
-var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
+var TIMEOUT_MODAL_DIALOG, CANVAS_BOX, EVENT_BOX;
+var helpersForController, invokeEventDialog, deleteCalendars, handleNewCalendarWizard;
+var setData;
 var plan_for_modal_dialog, wait_for_modal_dialog;
-var helpersForController, invokeEventDialog, switchToView, deleteCalendars;
-var handleNewCalendarWizard, setData;
-var CANVAS_BOX, EVENT_BOX, TIMEOUT_MODAL_DIALOG;
 
 const HOUR = 8;
 var calendarName, calendarTitle, calendarFile;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
-    ({ plan_for_modal_dialog, wait_for_modal_dialog } =
-        collector.getModule("window-helpers"));
+
     ({
+        TIMEOUT_MODAL_DIALOG,
+        CANVAS_BOX,
+        EVENT_BOX,
         helpersForController,
         invokeEventDialog,
-        switchToView,
         deleteCalendars,
-        handleNewCalendarWizard,
-        setData,
-        CANVAS_BOX,
-        EVENT_BOX,
-        TIMEOUT_MODAL_DIALOG
+        handleNewCalendarWizard
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
-    // unique name needed as deleting a calendar only unsubscribes from it and
+    ({ setData } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
+    ({ plan_for_modal_dialog, wait_for_modal_dialog } = collector.getModule("window-helpers"));
+
+    // Unique name needed as deleting a calendar only unsubscribes from it and
     // if same file were used on next testrun then previously created event
-    // would show up
+    // would show up.
     calendarName = calendarTitle = (new Date()).getTime() + "";
     calendarFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
     calendarFile.append(calendarName + ".ics");
 }
 
 function testLocalICS() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
-
     plan_for_modal_dialog("Calendar:NewCalendarWizard", (wizard) => {
         handleNewCalendarWizard(wizard, calendarName, { network: { format: "ics" } });
     });
     controller.mainMenu.click("#ltnNewCalendar");
     wait_for_modal_dialog("Calendar:NewCalendarWizard", TIMEOUT_MODAL_DIALOG);
 
-    // create new event
-    let box = lookupEventBox("day", CANVAS_BOX, undefined, 1, HOUR);
+    // Create new event.
+    let box = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, box, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
         setData(event, iframe, { title: calendarTitle, calendar: calendarName });
 
         // save
         event.click(eventid("button-saveandclose"));
     });
 
-    // assert presence in view
-    let eventPath = `/{"tooltip":"itemTooltip","calendar":"${calendarName}"}`;
-    controller.waitForElement(lookupEventBox("day", EVENT_BOX, null, 1, HOUR, eventPath));
+    // Assert presence in view.
+    controller.waitForElement(lookupEventBox("day", EVENT_BOX, null, 1, null, `
+        /{"tooltip":"itemTooltip","calendar":"${calendarName.toLowerCase()}"}
+    `));
 
-    // verify in file
+    // Verify in file.
     let fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
                             .createInstance(Components.interfaces.nsIFileInputStream);
     let cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
                             .createInstance(Components.interfaces.nsIConverterInputStream);
 
-    // wait a moment until file is written
+    // Wait a moment until file is written.
     controller.waitFor(() => calendarFile.exists());
 
-    // read the calendar file and check for the summary
+    // Read the calendar file and check for the summary.
     fstream.init(calendarFile, -1, 0, 0);
     cstream.init(fstream, "UTF-8", 0, 0);
 
     let str = {};
     cstream.readString(-1, str);
     cstream.close();
 
     controller.assertJS(str.value.includes("SUMMARY:" + calendarTitle));
--- a/calendar/test/mozmill/testTimezones.js
+++ b/calendar/test/mozmill/testTimezones.js
@@ -1,18 +1,20 @@
 /* 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 MODULE_NAME = "testTimezones";
 var RELATIVE_ROOT = "./shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers", "window-helpers"];
 
-var helpersForController, invokeEventDialog, switchToView, goToDate, setData;
-var findEventsInNode, viewForward, viewBack, CANVAS_BOX, TIMEOUT_MODAL_DIALOG;
+var TIMEOUT_MODAL_DIALOG, CANVAS_BOX, DAY_VIEW;
+var helpersForController, invokeEventDialog, switchToView, goToDate;
+var findEventsInNode, viewForward, viewBack;
+var setData;
 var plan_for_modal_dialog, wait_for_modal_dialog;
 
 var DATES = [
     [2009, 1, 1], [2009, 4, 2], [2009, 4, 16], [2009, 4, 30],
     [2009, 7, 2], [2009, 10, 15], [2009, 10, 29], [2009, 11, 5]
 ];
 
 var TIMEZONES = [
@@ -20,55 +22,57 @@ var TIMEZONES = [
     "America/Argentina/Buenos_Aires", "Europe/Paris", "Asia/Kathmandu", "Australia/Adelaide"
 ];
 
 ChromeUtils.import("resource://gre/modules/Preferences.jsm");
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        TIMEOUT_MODAL_DIALOG,
+        CANVAS_BOX,
+        DAY_VIEW,
         helpersForController,
         invokeEventDialog,
         switchToView,
         goToDate,
-        setData,
         findEventsInNode,
         viewForward,
-        viewBack,
-        CANVAS_BOX,
-        TIMEOUT_MODAL_DIALOG
+        viewBack
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
-    ({ plan_for_modal_dialog, wait_for_modal_dialog } = collector.getModule("window-helpers"));
+    ({ setData } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
+    ({ plan_for_modal_dialog, wait_for_modal_dialog } =
+        collector.getModule("window-helpers"));
 }
 
 function testTimezones1_SetGMT() {
     Preferences.set("calendar.timezone.local", "Europe/London");
 }
 
 function testTimezones2_CreateEvents() {
-    controller.click(eid("calendar-tab-button"));
-    switchToView(controller, "day");
     goToDate(controller, 2009, 1, 1);
 
-    // create weekly recurring events in all TIMEZONES
+    // Create weekly recurring events in all TIMEZONES.
     let times = [[4, 30], [5, 0], [3, 0], [3, 0], [9, 0], [14, 0], [19, 45], [1, 30]];
     let time = new Date();
     for (let i = 0; i < TIMEZONES.length; i++) {
         let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, i + 11);
         invokeEventDialog(controller, eventBox, (event, iframe) => {
             time.setHours(times[i][0]);
             time.setMinutes(times[i][1]);
 
-            // set timezone
+            // Set timezone.
             setTimezone(event, TIMEZONES[i]);
 
-            // set title and repeat
+            // Set title and repeat.
             setData(event, iframe, { title: TIMEZONES[i], repeat: "weekly", starttime: time });
 
             // save
             let { eid: eventid } = helpersForController(event);
             event.click(eventid("button-saveandclose"));
         });
     }
 }
@@ -266,44 +270,38 @@ function verify(controller, dates, timez
     function* datetimes() {
         for (let idx = 0; idx < dates.length; idx++) {
             yield [dates[idx][0], dates[idx][1], dates[idx][2], times[idx]];
         }
     }
 
     let { lookup } = helpersForController(controller);
 
-    let dayView = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("day-view")
-    `;
     let dayStack = `
-        ${dayView}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
+        ${DAY_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
         anon({"anonid":"daybox"})/[0]/anon({"anonid":"boxstack"})/
         anon({"anonid":"topbox"})/{"flex":"1"}
     `;
     let timeLine = `
-        ${dayView}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
+        ${DAY_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
         anon({"anonid":"timebar"})/anon({"anonid":"topbox"})
     `;
     let allowedDifference = 3;
 
     /* Event box' time can't be deduced from it's position in                    ----------------
        xul element tree because for each event a box is laid over whole day and  |___spacer_____|
        a spacer is added to push the event to it's correct location.             |__event_box___|
        But timeline can be used to retrieve the position of a particular hour    |day continues |
        on screen and it can be compared against the position of the event.       ----------------
     */
 
     for (let [selectedYear, selectedMonth, selectedDay, selectedTime] of datetimes()) {
         goToDate(controller, selectedYear, selectedMonth, selectedDay);
 
-        // find event with timezone tz
+        // Find event with timezone tz.
         for (let tzIdx = 0; tzIdx < timezones.length; tzIdx++) {
             let [correctHour, minutes, day] = selectedTime[tzIdx];
 
             let timeNode = lookup(`${timeLine}/[${correctHour}]`).getNode();
             let timeY = timeNode.boxObject.y + timeNode.boxObject.height * (minutes / 60);
 
             let eventNodes = [];
 
--- a/calendar/test/mozmill/testTodayPane.js
+++ b/calendar/test/mozmill/testTodayPane.js
@@ -1,281 +1,180 @@
 /* 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 MODULE_NAME = "testTodayPane";
 var RELATIVE_ROOT = "./shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers"];
 
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var CALENDARNAME;
+var CALENDARNAME, CANVAS_BOX, DAY_VIEW, LABELDAYBOX, TODAY_BUTTON, TODAY_PANE, AGENDA_LISTBOX;
+var helpersForController, invokeEventDialog, viewForward, createCalendar;
+var deleteCalendars;
+var setData;
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        CANVAS_BOX,
+        DAY_VIEW,
+        LABELDAYBOX,
+        TODAY_BUTTON,
+        TODAY_PANE,
+        AGENDA_LISTBOX,
         helpersForController,
         invokeEventDialog,
+        viewForward,
         createCalendar,
-        deleteCalendars,
-        CALENDARNAME
+        deleteCalendars
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({ setData } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, CALENDARNAME);
 }
 
 function testTodayPane() {
-    // paths
-    let panels = `
-        /id("messengerWindow")/id("tabmail-container")/
-        id("tabmail")/id("tabmail-tabbox")/id("tabpanelcontainer")
-    `;
-    let miniMonth = `
-        ${panels}/id("calendarTabPanel")/id("calendarContent")/id("ltnSidebar")/
-        id("minimonth-pane")
-    `;
-    let dayView = `
-        ${panels}/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/
-        id("view-deck")/id("day-view")
-    `;
-    let dayPath = `
-        ${dayView}/anon({"anonid":"mainbox"})/anon({"anonid":"labelbox"})/
-        anon({"anonid":"labeldaybox"})/{"flex":"1"}
-    `;
-    let eventName = `
-        id("calendar-event-dialog-inner")/id("event-grid")/
-        id("event-grid-rows")/id("event-grid-title-row")/id("item-title")/
-        anon({"anonid":"moz-input-box"})/anon({"anonid":"input"})
-    `;
+    let createEvent = (hour, name) => {
+        let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, hour);
+        invokeEventDialog(controller, eventBox, (event, iframe) => {
+            let { eid: eventid } = helpersForController(event);
 
-    // open calendar view
-    controller.click(eid("calendar-tab-button"));
-    controller.waitThenClick(eid("calendar-day-view-button"));
+            setData(event, iframe, { title: name });
+            event.click(eventid("button-saveandclose"));
+        });
+    };
 
-    // go to today and verify date
-    controller.waitThenClick(lookup(`
-        ${miniMonth}/{"align":"center"}/id("calMinimonthBox")/id("calMinimonth")/
-        anon({"anonid":"minimonth-header"})/anon({"anonid":"today-button"})
-    `));
+    // Go to today and verify date.
+    let dayPath = `${DAY_VIEW}/${LABELDAYBOX}/{"flex":"1"}`;
+    controller.waitThenClick(lookup(TODAY_BUTTON));
     controller.assertJS(lookup(dayPath).getNode().mDate.icalString == getIsoDate());
 
     // Create event 6 hours from now, if this is tomorrow then at 23 today.
     // Doubleclick only triggers new event dialog on visible boxes, so scrolling
     // may be needed by default visible time is 08:00 - 17:00, box of 17th hour
-    // is out of view
+    // is out of view.
     let hour = (new Date()).getHours();
     let startHour = (hour < 18 ? hour + 6 : 23);
-    let view = lookup(dayView).getNode();
+    let view = lookup(DAY_VIEW).getNode();
 
     if (startHour < 8 || startHour > 16) {
         view.scrollToMinute(60 * startHour);
     }
 
-    invokeEventDialog(controller, lookup(`
-        ${dayView}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
-        anon({"anonid":"daybox"})/{"class":"calendar-event-column-even"}/
-        anon({"anonid":"boxstack"})/anon({"anonid":"bgbox"})/[${startHour}]
-    `), (event, iframe) => {
-        let { lookup: iframelookup } = helpersForController(iframe);
-        let { eid: eventid } = helpersForController(event);
+    createEvent(startHour, "Today's Event");
 
-        let eventNameElement = iframelookup(eventName);
-        event.waitForElement(eventNameElement);
-        event.type(eventNameElement, "Today's Event");
-        event.click(eventid("button-saveandclose"));
-    });
-
-    // reset view
+    // Reset view.
     view.scrollToMinute(60 * 8);
 
-    // go to tomorrow and add an event
-    controller.click(eid("next-view-button"));
-    invokeEventDialog(controller, lookup(`
-        ${dayView}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
-        anon({"anonid":"daybox"})/{"class":"calendar-event-column-even"}/
-        anon({"anonid":"boxstack"})/anon({"anonid":"bgbox"})/[9]
-    `), (event, iframe) => {
-        let { lookup: iframelookup } = helpersForController(iframe);
-        let { eid: eventid } = helpersForController(event);
-
-        let eventNameElement = iframelookup(eventName);
-        event.waitForElement(eventNameElement);
-        event.type(eventNameElement, "Tomorrow's Event");
-        event.click(eventid("button-saveandclose"));
-    });
+    // Go to tomorrow and add an event.
+    viewForward(controller, 1);
+    createEvent(9, "Tomorrow's Event");
 
-    // go 5 days forward and add an event
-    for (let i = 0; i < 5; i++) {
-        controller.click(eid("next-view-button"));
-    }
-    sleep();
+    // Go 5 days forward and add an event.
+    viewForward(controller, 5);
+    createEvent(9, "Future Event");
 
-    invokeEventDialog(controller, lookup(`
-        ${dayView}/anon({"anonid":"mainbox"})/anon({"anonid":"scrollbox"})/
-        anon({"anonid":"daybox"})/{"class":"calendar-event-column-even"}/
-        anon({"anonid":"boxstack"})/anon({"anonid":"bgbox"})/[9]
-    `), (event, iframe) => {
-        let { lookup: iframelookup } = helpersForController(iframe);
-        let { eid: eventid } = helpersForController(event);
-
-        let eventNameElement = iframelookup(eventName);
-        event.waitForElement(eventNameElement);
-        event.type(eventNameElement, "Future's Event");
-        event.click(eventid("button-saveandclose"));
-    });
-
-    // go to mail tab
+    // Go to mail tab.
     controller.click(lookup(`
-        /id("messengerWindow")/id("navigation-toolbox")/id("tabs-toolbar")/
-        id("tabmail-tabs")/[0]/
-        anon({"class":"tab-stack"})/{"class":"tab-background"}/
-        {"class":"tab-line"}
+        /id("messengerWindow")/id("navigation-toolbox")/id("tabs-toolbar")/id("tabmail-tabs")/[0]
     `));
     sleep();
 
-    // verify today pane open
-    controller.assertNotDOMProperty(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")
-    `), "collapsed");
+    // Verify today pane open.
+    controller.assertNotDOMProperty(lookup(TODAY_PANE), "collapsed");
 
-    // verify today pane's date
+    // Verify today pane's date.
     controller.assertValue(eid("datevalue-label"), (new Date()).getDate());
 
-    // tomorrow and soon are collapsed by default
-    controller.click(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/[3]/id("agenda-listbox")/id("tomorrow-header")/
+    let expandArrow = `
         anon({"anonid":"agenda-checkbox-widget"})/anon({"class":"checkbox-check"})
-    `));
-    controller.click(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/[3]/id("agenda-listbox")/id("nextweek-header")/
-        anon({"anonid":"agenda-checkbox-widget"})/anon({"class":"checkbox-check"})
-    `));
+    `;
+    // Tomorrow and soon are collapsed by default.
+    controller.click(lookup(`${AGENDA_LISTBOX}/id("tomorrow-header")/${expandArrow}`));
+    controller.click(lookup(`${AGENDA_LISTBOX}/id("nextweek-header")/${expandArrow}`));
     sleep();
 
-    // verify events shown in today pane
+    // Verify events shown in today pane.
     let now = new Date();
     now.setHours(startHour);
     now.setMinutes(0);
     let dtz = cal.dtz.defaultTimezone;
     let probeDate = cal.dtz.jsDateToDateTime(now, dtz);
     let dateFormatter = cal.getDateFormatter();
     let startTime = dateFormatter.formatTime(probeDate);
-    controller.assertText(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[2]/
-        anon({"anonid":"agenda-container-box"})/
-        anon({"anonid":"agenda-description"})/[0]/
-        anon({"anonid":"agenda-event-start"})/
-    `), startTime + " Today's Event");
+
+    let eventStart = `
+        anon({"anonid":"agenda-container-box"})/anon({"anonid":"agenda-description"})/[0]/
+        anon({"anonid":"agenda-event-start"})
+    `;
+    controller.assertText(lookup(
+        `${AGENDA_LISTBOX}/[2]/${eventStart}`), startTime + " Today's Event"
+    );
 
     let tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 9, 0);
     probeDate = cal.dtz.jsDateToDateTime(tomorrow, dtz);
     startTime = dateFormatter.formatTime(probeDate);
-    controller.assertText(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[4]/
-        anon({"anonid":"agenda-container-box"})/
-        anon({"anonid":"agenda-description"})/[0]/
-        anon({"anonid":"agenda-event-start"})/
-    `), startTime + " Tomorrow's Event");
+    controller.assertText(lookup(
+        `${AGENDA_LISTBOX}/[4]/${eventStart}`), startTime + " Tomorrow's Event"
+    );
 
     let future = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 6, 9, 0);
     probeDate = cal.dtz.jsDateToDateTime(future, dtz);
     startTime = dateFormatter.formatDateTime(probeDate);
 
-    // Future event's start time
-    controller.assertText(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/
-        {"flex":"1"}/id("agenda-listbox")/[6]/anon({"anonid":"agenda-container-box"})/
-        anon({"anonid":"agenda-description"})/[0]/anon({"anonid":"agenda-event-start"})
-     `), startTime);
+    // Future event's start time.
+    controller.assertText(lookup(`${AGENDA_LISTBOX}/[6]/${eventStart}`), startTime);
 
-    // Future event's title
+    // Future event's title.
     controller.assertText(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/[1]/
-        id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[6]/
-        anon({"anonid":"agenda-container-box"})/
-        anon({"anonid":"agenda-description"})/
-        anon({"anonid":"agenda-event-title"})
-    `), "Future's Event");
+        ${AGENDA_LISTBOX}/[6]/anon({"anonid":"agenda-container-box"})/
+        anon({"anonid":"agenda-description"})/anon({"anonid":"agenda-event-title"})
+    `), "Future Event");
 
-    // delete events
-    controller.click(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[2]
-    `));
+    // Delete events.
+    controller.click(lookup(`${AGENDA_LISTBOX}/[2]`));
 
     controller.keypress(eid("agenda-listbox"), "VK_DELETE", {});
-    controller.waitForElementNotPresent(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[6]
-    `));
+    controller.waitForElementNotPresent(lookup(`${AGENDA_LISTBOX}/[6]`));
 
-    controller.click(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[3]
-    `));
+    controller.click(lookup(`${AGENDA_LISTBOX}/[3]`));
     controller.keypress(eid("agenda-listbox"), "VK_DELETE", {});
-    controller.waitForElementNotPresent(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[5]
-    `));
+    controller.waitForElementNotPresent(lookup(`${AGENDA_LISTBOX}/[5]`));
 
-    controller.click(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[4]
-    `));
+    controller.click(lookup(`${AGENDA_LISTBOX}/[4]`));
     controller.keypress(eid("agenda-listbox"), "VK_DELETE", {});
-    controller.waitForElementNotPresent(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[4]
-    `));
+    controller.waitForElementNotPresent(lookup(`${AGENDA_LISTBOX}/[4]`));
 
-    // hide and verify today pane hidden
+    // Hide and verify today pane hidden.
     controller.click(eid("calendar-status-todaypane-button"));
     controller.assertNode(lookup(`
         /id("messengerWindow")/id("tabmail-container")/{"collapsed":"true"}
     `));
 
-    // reset today pane
+    // Reset today pane.
     controller.click(eid("calendar-status-todaypane-button"));
-    controller.assertNotDOMProperty(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")
-    `), "collapsed");
-    controller.click(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/[3]/id("agenda-listbox")/id("tomorrow-header")/
-        anon({"anonid":"agenda-checkbox-widget"})/anon({"class":"checkbox-check"})
-    `));
-    controller.click(lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/[3]/id("agenda-listbox")/id("nextweek-header")/
-        anon({"anonid":"agenda-checkbox-widget"})/anon({"class":"checkbox-check"})
-    `));
+    controller.assertNotDOMProperty(lookup(TODAY_PANE), "collapsed");
+    controller.click(lookup(`${AGENDA_LISTBOX}/id("tomorrow-header")/${expandArrow}`));
+    controller.click(lookup(`${AGENDA_LISTBOX}/id("nextweek-header")/${expandArrow}`));
     sleep();
 
-    // verify tomorrow and soon collapsed
+    // Verify tomorrow and soon collapsed.
     tomorrow = lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[1]/
-        anon({"class":"agenda-checkbox treenode-checkbox"})
+        ${AGENDA_LISTBOX}/[1]/anon({"class":"agenda-checkbox treenode-checkbox"})
     `).getNode();
 
     let soon = lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("today-pane-panel")/
-        [1]/id("agenda-panel")/{"flex":"1"}/id("agenda-listbox")/[2]/
-        anon({"class":"agenda-checkbox treenode-checkbox"})
+        ${AGENDA_LISTBOX}/[2]/anon({"class":"agenda-checkbox treenode-checkbox"})
     `).getNode();
 
     // TODO This is failing, which might actually be an error in our code!
     //  controller.assertJS(!tomorrow.hasAttribute("checked")
     //    || tomorrow.getAttribute("checked") != "true");
     controller.assertJS(
         !soon.hasAttribute("checked") ||
         soon.getAttribute("checked") != "true"
--- a/calendar/test/mozmill/views/testDayView.js
+++ b/calendar/test/mozmill/views/testDayView.js
@@ -1,144 +1,110 @@
 /* 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 MODULE_NAME = "testDayView";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var goToDate, setData, lookupEventBox;
-var CALENDARNAME, CANVAS_BOX, EVENT_BOX;
+var CALENDARNAME, CANVAS_BOX, EVENT_BOX, DAY_VIEW, LABELDAYBOX, EVENTPATH;
+var helpersForController, invokeEventDialog, getEventDetails, createCalendar;
+var deleteCalendars, goToDate, lookupEventBox;
+var helpersForEditUI, setData;
 
-var TITLE1 = "Day View Event";
-var TITLE2 = "Day View Event Changed";
-var DESC = "Day View Event Description";
+const TITLE1 = "Day View Event";
+const TITLE2 = "Day View Event Changed";
+const DESC = "Day View Event Description";
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        CANVAS_BOX,
+        EVENT_BOX,
+        DAY_VIEW,
+        LABELDAYBOX,
+        EVENTPATH,
         helpersForController,
         invokeEventDialog,
+        getEventDetails,
         createCalendar,
         deleteCalendars,
         goToDate,
-        setData,
-        lookupEventBox,
-        CALENDARNAME,
-        CANVAS_BOX,
-        EVENT_BOX
+        lookupEventBox
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        helpersForEditUI,
+        setData
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, CALENDARNAME);
 }
 
 function testDayView() {
     let dateFormatter = cal.getDateFormatter();
-    // paths
-    let dayView = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("day-view")
-    `;
-
-    // open day view
-    controller.click(eid("calendar-tab-button"));
-    controller.waitThenClick(eid("calendar-day-view-button"));
 
     goToDate(controller, 2009, 1, 1);
 
-    // verify date in view
-    let day = lookup(`
-        ${dayView}/anon({"anonid":"mainbox"})/anon({"anonid":"labelbox"})/
-        anon({"anonid":"labeldaybox"})/{"flex":"1"}
-    `);
+    // Verify date in view.
+    let day = lookup(`${DAY_VIEW}/${LABELDAYBOX}/{"flex":"1"}`);
     controller.waitFor(() => day.getNode().mDate.icalString == "20090101");
 
-    // create event at 8 AM
+    // Create event at 8 AM.
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, 8);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
-        let { lookup: iframeLookup } = helpersForController(iframe);
+        let { getDateTimePicker } = helpersForEditUI(iframe);
 
-        let innerFrame = '/id("calendar-event-dialog-inner")/id("event-grid")/id("event-grid-rows")/';
-        let dateInput = `
-            anon({"class":"datepicker-box-class"})/{"class":"datepicker-text-class"}/
-            anon({"class":"menulist-editable-box textbox-input-box"})/
-            anon({"anonid":"input"})
-        `;
-        let timeInput = `
-            anon({"anonid":"hbox"})/anon({"anonid":"time-picker"})/
-            anon({"class":"timepicker-box-class"})/
-            anon({"class":"timepicker-text-class"})/anon({"flex":"1"})/
-            anon({"anonid":"input"})
-        `;
-        let startId = "event-starttime";
+        let startTimeInput = getDateTimePicker("STARTTIME");
+        let startDateInput = getDateTimePicker("STARTDATE");
 
-        let startTimeInput = iframeLookup(`
-            ${innerFrame}/id("event-grid-startdate-row")/
-            id("event-grid-startdate-picker-box")/id("${startId}")/${timeInput}
-        `);
-        let startDateInput = iframeLookup(`
-            ${innerFrame}/id("event-grid-startdate-row")/
-            id("event-grid-startdate-picker-box")/id("${startId}")/
-            anon({"anonid":"hbox"})/anon({"anonid":"date-picker"})/${dateInput}
-        `);
-
-        // check that the start time is correct
+        // Check that the start time is correct.
         let someDate = cal.createDateTime();
         someDate.resetTo(2009, 0, 1, 8, 0, 0, cal.dtz.floating);
         event.waitForElement(startTimeInput);
         event.assertValue(startTimeInput, dateFormatter.formatTime(someDate));
         event.assertValue(startDateInput, dateFormatter.formatDateShort(someDate));
 
-        // fill in title, description and calendar
-        setData(event, iframe, { title: TITLE1, description: DESC, calendar: CALENDARNAME });
+        // Fill in title, description and calendar.
+        setData(event, iframe, {
+            title: TITLE1,
+            description: DESC,
+            calendar: CALENDARNAME
+        });
 
         // save
         event.click(eventid("button-saveandclose"));
     });
 
-    // if it was created successfully, it can be opened
-    eventBox = lookupEventBox(
-        "day", EVENT_BOX, null, 1, 8,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    );
+    // If it was created successfully, it can be opened.
+    eventBox = lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        // change title and save changes
+        // Change title and save changes.
         setData(event, iframe, { title: TITLE2 });
         event.click(eventid("button-saveandclose"));
     });
 
-    // check if name was saved
-    let eventName = lookupEventBox(
-        "day", EVENT_BOX, null, 1, 8,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}/
-        anon({"flex":"1"})/anon({"anonid":"event-container"})/
-        {"class":"calendar-event-selection"}/anon({"anonid":"eventbox"})/
-        {"class":"calendar-event-details"}/anon({"flex":"1"})/
-        anon({"anonid":"event-name"})`
+    // Check if name was saved.
+    let eventName = lookupEventBox("day", EVENT_BOX, null, 1, null,
+        `${EVENTPATH}/${getEventDetails("day")}/anon({"flex":"1"})/anon({"anonid":"event-name"})`
     );
     controller.waitForElement(eventName);
     controller.assertJSProperty(eventName, "textContent", TITLE2);
 
-    // delete event
-    controller.click(lookupEventBox(
-        "day", EVENT_BOX, null, 1, 8,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    ));
+    // Delete event
+    controller.click(eventBox);
     controller.keypress(eid("day-view"), "VK_DELETE", {});
-    controller.waitForElementNotPresent(lookupEventBox(
-        "day", EVENT_BOX, null, 1, 8,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    ));
+    controller.waitForElementNotPresent(eventBox);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/views/testMonthView.js
+++ b/calendar/test/mozmill/views/testMonthView.js
@@ -1,147 +1,119 @@
 /* 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 MODULE_NAME = "testMonthView";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var goToDate, setData, lookupEventBox;
-var CALENDARNAME, CANVAS_BOX, EVENT_BOX;
+var CALENDARNAME, EVENT_BOX, CANVAS_BOX, MONTH_VIEW, EVENTPATH;
+var helpersForController, switchToView, invokeEventDialog, getEventDetails, createCalendar;
+var deleteCalendars, goToDate, lookupEventBox;
+var helpersForEditUI, setData;
 
-var TITLE1 = "Month View Event";
-var TITLE2 = "Month View Event Changed";
-var DESC = "Month View Event Description";
+const TITLE1 = "Month View Event";
+const TITLE2 = "Month View Event Changed";
+const DESC = "Month View Event Description";
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        EVENT_BOX,
+        CANVAS_BOX,
+        MONTH_VIEW,
+        EVENTPATH,
         helpersForController,
+        switchToView,
         invokeEventDialog,
+        getEventDetails,
         createCalendar,
         deleteCalendars,
         goToDate,
-        setData,
-        lookupEventBox,
-        CALENDARNAME,
-        CANVAS_BOX,
-        EVENT_BOX
+        lookupEventBox
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        helpersForEditUI,
+        setData
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, CALENDARNAME);
 }
 
 function testMonthView() {
     let dateFormatter = cal.getDateFormatter();
-    // paths
-    let monthView = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("month-view")
-    `;
 
-    controller.click(eid("calendar-tab-button"));
-    controller.waitThenClick(eid("calendar-month-view-button"));
-
+    switchToView(controller, "month");
     goToDate(controller, 2009, 1, 1);
 
-    // verify date
+    // Verify date.
     let day = lookup(`
-        ${monthView}/anon({"anonid":"mainbox"})/anon({"anonid":"monthgrid"})/
+        ${MONTH_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"monthgrid"})/
         anon({"anonid":"monthgridrows"})/[0]/{"selected":"true"}
     `);
     controller.waitFor(() => day.getNode().mDate.icalString == "20090101");
 
-    // create event
-    // Thursday of 2009-01-01 should be the selected box in the first row with default settings
-    let hour = new Date().getHours(); // remember time at click
+    // Create event.
+    // Thursday of 2009-01-01 should be the selected box in the first row with default settings.
+    let hour = new Date().getHours(); // Remember time at click.
     let eventBox = lookupEventBox("month", CANVAS_BOX, 1, 5);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
-        let { lookup: iframeLookup } = helpersForController(iframe);
+        let { getDateTimePicker } = helpersForEditUI(iframe);
 
-        let innerFrame = '/id("calendar-event-dialog-inner")/id("event-grid")/id("event-grid-rows")/';
-        let dateInput = `
-            anon({"class":"datepicker-box-class"})/{"class":"datepicker-text-class"}/
-            anon({"class":"menulist-editable-box textbox-input-box"})/
-            anon({"anonid":"input"})
-        `;
-        let timeInput = `
-            anon({"anonid":"hbox"})/anon({"anonid":"time-picker"})/
-            anon({"class":"timepicker-box-class"})/
-            anon({"class":"timepicker-text-class"})/anon({"flex":"1"})/
-            anon({"anonid":"input"})
-        `;
-        let startId = "event-starttime";
+        let startTimeInput = getDateTimePicker("STARTTIME");
+        let startDateInput = getDateTimePicker("STARTDATE");
 
-        let startTimeInput = iframeLookup(`
-            ${innerFrame}/id("event-grid-startdate-row")/
-            id("event-grid-startdate-picker-box")/id("${startId}")/${timeInput}
-        `);
-        let startDateInput = iframeLookup(`
-            ${innerFrame}/id("event-grid-startdate-row")/
-            id("event-grid-startdate-picker-box")/id("${startId}")/
-            anon({"anonid":"hbox"})/anon({"anonid":"date-picker"})/${dateInput}
-        `);
-
-        // check that the start time is correct
-        // next full hour except last hour hour of the day
+        // 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, 1, nextHour, 0, 0, cal.dtz.floating);
         event.waitForElement(startTimeInput);
         event.assertValue(startTimeInput, dateFormatter.formatTime(someDate));
         event.assertValue(startDateInput, dateFormatter.formatDateShort(someDate));
 
-        // fill in title, description and calendar
-        setData(event, iframe, { title: TITLE1, description: DESC, calendar: CALENDARNAME });
+        // Fill in title, description and calendar.
+        setData(event, iframe, {
+            title: TITLE1,
+            description: DESC,
+            calendar: CALENDARNAME
+        });
 
         // save
         event.click(eventid("button-saveandclose"));
     });
 
-    // if it was created successfully, it can be opened
-    eventBox = lookupEventBox(
-        "month", EVENT_BOX, 1, 5, null,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    );
+    // If it was created successfully, it can be opened.
+    eventBox = lookupEventBox("month", EVENT_BOX, 1, 5, null, EVENTPATH);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        // change title and save changes
+        // Change title and save changes.
         setData(event, iframe, { title: TITLE2 });
         event.click(eventid("button-saveandclose"));
     });
 
-    // check if name was saved
-    let eventName = lookupEventBox(
-        "month", EVENT_BOX, 1, 5, null,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}/
-        anon({"flex":"1"})/[0]/anon({"anonid":"event-container"})/
-        {"class":"calendar-event-selection"}/anon({"anonid":"eventbox"})/
-        {"class":"calendar-event-details"}/{"flex":"1"}/anon({"anonid":"event-name"})`
+    // Check if name was saved.
+    let eventName = lookupEventBox("month", EVENT_BOX, 1, 5, null,
+        `${EVENTPATH}/${getEventDetails("month")}/anon({"flex":"1"})/anon({"anonid":"event-name"})`
     );
 
     controller.waitForElement(eventName);
     controller.assertValue(eventName, TITLE2);
 
-    // delete event
-    controller.click(lookupEventBox(
-        "month", EVENT_BOX, 1, 5, null,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    ));
+    // Delete event.
+    controller.click(eventBox);
     controller.keypress(eid("month-view"), "VK_DELETE", {});
-    controller.waitForElementNotPresent(lookupEventBox(
-        "month", EVENT_BOX, 1, 5, null,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    ));
+    controller.waitForElementNotPresent(eventBox);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/views/testMultiweekView.js
+++ b/calendar/test/mozmill/views/testMultiweekView.js
@@ -1,147 +1,120 @@
 /* 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 MODULE_NAME = "testMultiweekView";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var goToDate, setData, lookupEventBox;
-var CALENDARNAME, CANVAS_BOX, EVENT_BOX;
+var CALENDARNAME, EVENT_BOX, CANVAS_BOX, MULTIWEEK_VIEW, EVENTPATH;
+var helpersForController, switchToView, invokeEventDialog, getEventDetails, createCalendar;
+var deleteCalendars, goToDate, lookupEventBox;
+var helpersForEditUI, setData;
 
-var TITLE1 = "Multiweek View Event";
-var TITLE2 = "Multiweek View Event Changed";
-var DESC = "Multiweek View Event Description";
+const TITLE1 = "Multiweek View Event";
+const TITLE2 = "Multiweek View Event Changed";
+const DESC = "Multiweek View Event Description";
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        EVENT_BOX,
+        CANVAS_BOX,
+        MULTIWEEK_VIEW,
+        EVENTPATH,
         helpersForController,
+        switchToView,
         invokeEventDialog,
+        getEventDetails,
         createCalendar,
         deleteCalendars,
         goToDate,
-        setData,
-        lookupEventBox,
-        CALENDARNAME,
-        CANVAS_BOX,
-        EVENT_BOX
+        lookupEventBox
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        helpersForEditUI,
+        setData
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, CALENDARNAME);
 }
 
 function testMultiWeekView() {
     let dateFormatter = cal.getDateFormatter();
-    // paths
-    let multiWeekView = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("multiweek-view")/
-    `;
 
-    controller.click(eid("calendar-tab-button"));
-    controller.waitThenClick(eid("calendar-multiweek-view-button"));
-
+    switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 1);
 
-    // verify date
+    // Verify date.
     let day = lookup(`
-        ${multiWeekView}/anon({"anonid":"mainbox"})/anon({"anonid":"monthgrid"})/
+        ${MULTIWEEK_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"monthgrid"})/
         anon({"anonid":"monthgridrows"})/[0]/{"selected":"true"}
     `);
     controller.waitFor(() => day.getNode().mDate.icalString == "20090101");
 
-    // create event
-    // Thursday of 2009-01-01 should be the selected box in the first row with default settings
-    let hour = new Date().getHours(); // remember time at click
+    // Create event.
+    // Thursday of 2009-01-01 should be the selected box in the first row with default settings.
+    let hour = new Date().getHours(); // Remember time at click.
     let eventBox = lookupEventBox("multiweek", CANVAS_BOX, 1, 5);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
-        let { lookup: iframeLookup } = helpersForController(iframe);
+        let { getDateTimePicker } = helpersForEditUI(iframe);
 
-        let innerFrame = '/id("calendar-event-dialog-inner")/id("event-grid")/id("event-grid-rows")/';
-        let dateInput = `
-            anon({"class":"datepicker-box-class"})/{"class":"datepicker-text-class"}/
-            anon({"class":"menulist-editable-box textbox-input-box"})/
-            anon({"anonid":"input"})
-        `;
-        let timeInput = `
-            anon({"anonid":"hbox"})/anon({"anonid":"time-picker"})/
-            anon({"class":"timepicker-box-class"})/
-            anon({"class":"timepicker-text-class"})/anon({"flex":"1"})/
-            anon({"anonid":"input"})
-        `;
-        let startId = "event-starttime";
+        let startTimeInput = getDateTimePicker("STARTTIME");
+        let startDateInput = getDateTimePicker("STARTDATE");
 
-        let startTimeInput = iframeLookup(`
-            ${innerFrame}/id("event-grid-startdate-row")/
-            id("event-grid-startdate-picker-box")/id("${startId}")/${timeInput}
-        `);
-        let startDateInput = iframeLookup(`
-            ${innerFrame}/id("event-grid-startdate-row")/
-            id("event-grid-startdate-picker-box")/id("${startId}")/
-            anon({"anonid":"hbox"})/anon({"anonid":"date-picker"})/${dateInput}
-        `);
-
-        // check that the start time is correct
-        // next full hour except last hour hour of the day
+        // 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, 1, nextHour, 0, 0, cal.dtz.floating);
         event.waitForElement(startTimeInput);
         event.assertValue(startTimeInput, dateFormatter.formatTime(someDate));
         event.assertValue(startDateInput, dateFormatter.formatDateShort(someDate));
 
-        // fill in title, description and calendar
-        setData(event, iframe, { title: TITLE1, description: DESC, calendar: CALENDARNAME });
+        // Fill in title, description and calendar.
+        setData(event, iframe, {
+            title: TITLE1,
+            description: DESC,
+            calendar: CALENDARNAME
+        });
 
         // save
         event.click(eventid("button-saveandclose"));
     });
 
-    // if it was created successfully, it can be opened
-    eventBox = lookupEventBox(
-        "multiweek", EVENT_BOX, 1, 5, null,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    );
+    // If it was created successfully, it can be opened.
+    eventBox = lookupEventBox("multiweek", EVENT_BOX, 1, 5, null, EVENTPATH);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        // change title and save changes
+        // Change title and save changes.
         setData(event, iframe, { title: TITLE2 });
         event.click(eventid("button-saveandclose"));
     });
 
-    // check if name was saved
-    let eventName = lookupEventBox(
-        "multiweek", EVENT_BOX, 1, 5, null,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}/
-        anon({"flex":"1"})/[0]/anon({"anonid":"event-container"})/
-        {"class":"calendar-event-selection"}/anon({"anonid":"eventbox"})/
-        {"class":"calendar-event-details"}/{"flex":"1"}/anon({"anonid":"event-name"})`
+    // Check if name was saved.
+    let eventName = lookupEventBox("multiweek", EVENT_BOX, 1, 5, null,
+        `${EVENTPATH}/${getEventDetails("multiweek")}/anon({"flex":"1"})/
+        anon({"anonid":"event-name"})`
     );
 
     controller.waitForElement(eventName);
     controller.assertValue(eventName, TITLE2);
 
-    // delete event
-    controller.click(lookupEventBox(
-        "multiweek", EVENT_BOX, 1, 5, null,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    ));
+    // Delete event.
+    controller.click(eventBox);
     controller.keypress(eid("multiweek-view"), "VK_DELETE", {});
-    controller.waitForElementNotPresent(lookupEventBox(
-        "multiweek", EVENT_BOX, 1, 5, null,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    ));
+    controller.waitForElementNotPresent(eventBox);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
--- a/calendar/test/mozmill/views/testTaskView.js
+++ b/calendar/test/mozmill/views/testTaskView.js
@@ -1,157 +1,157 @@
 /* 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 MODULE_NAME = "testTaskView";
 var RELATIVE_ROOT = "../shared-modules";
 var MODULE_REQUIRES = ["calendar-utils"];
 
+var CALENDARNAME, CALENDAR_PANEL, TASK_VIEW;
 var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
 var setData;
-var CALENDARNAME;
 
-var TITLE = "Task";
-var DESCRIPTION = "1. Do A\n2. Do B";
-var percentComplete = "50";
+const TITLE = "Task";
+const DESCRIPTION = "1. Do A\n2. Do B";
+const PERCENTCOMPLETE = "50";
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        CALENDAR_PANEL,
+        TASK_VIEW,
         helpersForController,
         invokeEventDialog,
         createCalendar,
-        deleteCalendars,
-        setData,
-        CALENDARNAME
+        deleteCalendars
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({ setData } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, CALENDARNAME);
 }
 
-// mozmill doesn't support trees yet, therefore completed checkbox and line-through style are not
-// checked
+// Mozmill doesn't support trees yet, therefore completed checkbox and line-through style are not
+// checked.
 function testTaskView() {
     // paths
-    let taskView = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-task-box")/
+    let treeChildren = `
+        ${TASK_VIEW}/[1]/id("calendar-task-tree")/anon({"anonid":"calendar-task-tree"})/
+        {"tooltip":"taskTreeTooltip"}
     `;
-    let treeChildren = `
-        ${taskView}/[1]/id("calendar-task-tree")/
-        anon({"anonid":"calendar-task-tree"})/{"tooltip":"taskTreeTooltip"}
-    `;
-    let taskTree = taskView + '[1]/id("calendar-task-tree")';
+    let taskTree = TASK_VIEW + '[1]/id("calendar-task-tree")';
     let toolTip = '/id("messengerWindow")/id("calendar-popupset")/id("taskTreeTooltip")';
     let toolTipGrid = toolTip + '/{"class":"tooltipBox"}/{"class":"tooltipHeaderGrid"}/';
 
-    // open task view
+    // Open task view.
     controller.click(eid("task-tab-button"));
     sleep();
 
-    // make sure that testing calendar is selected
+    // Make sure that testing calendar is selected.
     let calendarTree = lookup(`
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("ltnSidebar")/id("calendar-panel")/id("calendar-list-pane")/
+        ${CALENDAR_PANEL}/id("ltnSidebar")/id("calendar-panel")/id("calendar-list-pane")/
         id("calendar-listtree-pane")/id("calendar-list-tree-widget")
     `).getNode();
 
     for (let i = 0; i < calendarTree.mCalendarList.length; i++) {
         if (calendarTree.mCalendarList[i].name == CALENDARNAME) {
             calendarTree.tree.view.selection.select(i);
         }
     }
 
     let taskTreeNode = lookup(taskTree).getNode();
     let countBefore = taskTreeNode.mTaskArray.length;
 
-    // add task
-    controller.type(lookup(`
-        ${taskView}/id("task-addition-box")/[0]/id("view-task-edit-field")/
+    // Add task.
+    let taskInput= lookup(`
+        ${TASK_VIEW}/id("task-addition-box")/[0]/id("view-task-edit-field")/
         anon({"anonid":"moz-input-box"})/anon({"anonid":"input"})
-    `), TITLE);
-    controller.keypress(lookup(`
-        ${taskView}/id("task-addition-box")/[0]/id("view-task-edit-field")/
-        anon({"anonid":"moz-input-box"})/anon({"anonid":"input"})
-    `), "VK_RETURN", {});
+    `);
+    controller.type(taskInput, TITLE);
+    controller.keypress(taskInput, "VK_RETURN", {});
 
-    // verify added
+    // Verify added.
     let countAfter;
     controller.waitFor(() => {
         countAfter = taskTreeNode.mTaskArray.length;
         return countBefore + 1 == countAfter;
-    });
+    }, "Added Task did not appear");
 
-    // last added task is automatically selected so verify detail window data
+    // Last added task is automatically selected so verify detail window data.
     controller.assertJSProperty(eid("calendar-task-details-title"), "textContent", TITLE);
 
-    // open added task
-    // doubleclick on completion checkbox is ignored as opening action, so don't click at immediate
-    // left where the checkbox is located
+    // Open added task
+    // Doubleclick on completion checkbox is ignored as opening action, so don't
+    // click at immediate left where the checkbox is located.
     controller.doubleClick(lookup(treeChildren), 50, 0);
     invokeEventDialog(controller, null, (task, iframe) => {
         let { eid: taskid } = helpersForController(task);
         let { eid: iframeId } = helpersForController(iframe);
 
-        // verify calendar
+        // Verify calendar.
         controller.assertValue(iframeId("item-calendar"), CALENDARNAME);
 
-        setData(task, iframe, { status: "needs-action", percent: percentComplete, description: DESCRIPTION });
+        setData(task, iframe, {
+            status: "needs-action",
+            percent: PERCENTCOMPLETE,
+            description: DESCRIPTION
+        });
 
         // save
         task.click(taskid("button-saveandclose"));
     });
 
-    // verify description and status in details pane
+    // Verify description and status in details pane.
     controller.assertValue(lookup(`
-        ${taskView}/{"flex":"1"}/id("calendar-task-details-container")/
-        id("calendar-task-details-description")/
-        anon({"anonid":"moz-input-box"})/anon({"anonid":"input"})
+        ${TASK_VIEW}/{"flex":"1"}/id("calendar-task-details-container")/
+        id("calendar-task-details-description")/anon({"anonid":"moz-input-box"})/
+        anon({"anonid":"input"})
     `), DESCRIPTION);
     controller.assertValue(eid("calendar-task-details-status"), "Needs Action");
 
     // This is a hack.
     taskTreeNode.getTaskAtRow(0).calendar.setProperty("capabilities.priority.supported", true);
 
-    // set high priority and verify it in detail pane
+    // Set high priority and verify it in detail pane.
     controller.click(eid("task-actions-priority"));
     sleep();
     controller.click(eid("priority-1-menuitem"));
     sleep();
     let priorityNode = eid("calendar-task-details-priority-high");
     controller.assertNotDOMProperty(priorityNode, "hidden");
 
-    // verify that tooltip shows status, priority and percent complete
+    // Verify that tooltip shows status, priority and percent complete.
     let toolTipNode = lookup(toolTip).getNode();
     toolTipNode.ownerGlobal.showToolTip(toolTipNode, taskTreeNode.getTaskAtRow(0));
 
     let toolTipName = lookup(toolTipGrid + "[1]/[0]/[1]");
     let toolTipCalendar = lookup(toolTipGrid + "[1]/[1]/[1]");
     let toolTipPriority = lookup(toolTipGrid + "[1]/[2]/[1]");
     let toolTipStatus = lookup(toolTipGrid + "[1]/[3]/[1]");
     let toolTipComplete = lookup(toolTipGrid + "[1]/[4]/[1]");
 
     controller.assertJSProperty(toolTipName, "textContent", TITLE);
     controller.assertJSProperty(toolTipCalendar, "textContent", CALENDARNAME);
     controller.assertJSProperty(toolTipPriority, "textContent", "High");
     controller.assertJSProperty(toolTipStatus, "textContent", "Needs Action");
-    controller.assertJSProperty(toolTipComplete, "textContent", percentComplete + "%");
+    controller.assertJSProperty(toolTipComplete, "textContent", PERCENTCOMPLETE + "%");
 
-    // mark completed, verify
+    // Mark completed, verify.
     controller.click(eid("task-actions-markcompleted"));
     sleep();
 
     toolTipNode.ownerGlobal.showToolTip(toolTipNode, taskTreeNode.getTaskAtRow(0));
     controller.assertJSProperty(toolTipStatus, "textContent", "Completed");
 
-    // delete task, verify
+    // Delete task and verify.
     controller.click(eid("task-context-menu-delete"));
     controller.click(eid("calendar-delete-task-button"));
     let countAfterDelete;
     controller.waitFor(() => {
         countAfterDelete = taskTreeNode.mTaskArray.length;
         return countAfter - 1 == countAfterDelete;
     });
 }
--- a/calendar/test/mozmill/views/testWeekView.js
+++ b/calendar/test/mozmill/views/testWeekView.js
@@ -1,144 +1,115 @@
 /* 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 MODULE_NAME = "testWeekView";
 var RELATIVE_ROOT = "../shared-modules";
-var MODULE_REQUIRES = ["calendar-utils"];
+var MODULE_REQUIRES = ["calendar-utils", "item-editing-helpers"];
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm", null);
 
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var goToDate, setData, lookupEventBox;
-var CALENDARNAME, CANVAS_BOX, EVENT_BOX;
+var CALENDARNAME, CANVAS_BOX, EVENT_BOX, WEEK_VIEW, EVENTPATH;
+var helpersForController, switchToView, invokeEventDialog, getEventDetails, createCalendar;
+var deleteCalendars, goToDate, lookupEventBox;
+var helpersForEditUI, setData;
 
 var TITLE1 = "Week View Event";
 var TITLE2 = "Week View Event Changed";
 var DESC = "Week View Event Description";
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        CANVAS_BOX,
+        EVENT_BOX,
+        WEEK_VIEW,
+        EVENTPATH,
         helpersForController,
+        switchToView,
         invokeEventDialog,
+        getEventDetails,
         createCalendar,
         deleteCalendars,
         goToDate,
-        setData,
-        lookupEventBox,
-        CALENDARNAME,
-        CANVAS_BOX,
-        EVENT_BOX
+        lookupEventBox
     } = collector.getModule("calendar-utils"));
-    collector.getModule("calendar-utils").setupModule();
+    collector.getModule("calendar-utils").setupModule(controller);
     Object.assign(module, helpersForController(controller));
 
+    ({
+        helpersForEditUI,
+        setData
+    } = collector.getModule("item-editing-helpers"));
+    collector.getModule("item-editing-helpers").setupModule(module);
+
     createCalendar(controller, CALENDARNAME);
 }
 
 function testWeekView() {
     let dateFormatter = cal.getDateFormatter();
-    // paths
-    let weekView = `
-        /id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabmail-tabbox")/
-        id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
-        id("calendarDisplayDeck")/id("calendar-view-box")/id("view-deck")/
-        id("week-view")/
-    `;
 
-    controller.click(eid("calendar-tab-button"));
-    controller.waitThenClick(eid("calendar-week-view-button"));
-
+    switchToView(controller, "week");
     goToDate(controller, 2009, 1, 1);
 
-    // verify date
+    // Verify date.
     let day = lookup(`
-        ${weekView}/anon({"anonid":"mainbox"})/anon({"anonid":"headerbox"})/
+        ${WEEK_VIEW}/anon({"anonid":"mainbox"})/anon({"anonid":"headerbox"})/
         anon({"anonid":"headerdaybox"})/{"selected":"true"}
     `);
     controller.waitFor(() => day.getNode().mDate.icalString == "20090101");
 
-    // create event at 8 AM
-    // Thursday of 2009-01-01 is 4th with default settings
+    // Create event at 8 AM.
+    // Thursday of 2009-01-01 is 4th with default settings.
     let eventBox = lookupEventBox("week", CANVAS_BOX, null, 5, 8);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
-        let { lookup: iframeLookup } = helpersForController(iframe);
+        let { getDateTimePicker } = helpersForEditUI(iframe);
 
-        let innerFrame = '/id("calendar-event-dialog-inner")/id("event-grid")/id("event-grid-rows")/';
-        let dateInput = `
-            anon({"class":"datepicker-box-class"})/{"class":"datepicker-text-class"}/
-            anon({"class":"menulist-editable-box textbox-input-box"})/
-            anon({"anonid":"input"})
-        `;
-        let timeInput = `
-            anon({"anonid":"hbox"})/anon({"anonid":"time-picker"})/
-            anon({"class":"timepicker-box-class"})/
-            anon({"class":"timepicker-text-class"})/anon({"flex":"1"})/
-            anon({"anonid":"input"})
-        `;
-        let startId = "event-starttime";
+        let startTimeInput = getDateTimePicker("STARTTIME");
+        let startDateInput = getDateTimePicker("STARTDATE");
 
-        let startTimeInput = iframeLookup(`
-            ${innerFrame}/id("event-grid-startdate-row")/
-            id("event-grid-startdate-picker-box")/id("${startId}")/${timeInput}
-        `);
-        let startDateInput = iframeLookup(`
-            ${innerFrame}/id("event-grid-startdate-row")/
-            id("event-grid-startdate-picker-box")/id("${startId}")/
-            anon({"anonid":"hbox"})/anon({"anonid":"date-picker"})/${dateInput}
-        `);
-
-        // check that the start time is correct
+        // Check that the start time is correct.
         event.waitForElement(startTimeInput);
         let someDate = cal.createDateTime();
         someDate.resetTo(2009, 0, 1, 8, 0, 0, cal.dtz.floating);
         event.assertValue(startTimeInput, dateFormatter.formatTime(someDate));
         event.assertValue(startDateInput, dateFormatter.formatDateShort(someDate));
 
-        // fill in title, description and calendar
-        setData(event, iframe, { title: TITLE1, description: DESC, calendar: CALENDARNAME });
+        // Fill in title, description and calendar.
+        setData(event, iframe, {
+            title: TITLE1,
+            description: DESC,
+            calendar: CALENDARNAME
+        });
 
         // save
         event.click(eventid("button-saveandclose"));
     });
 
-    // if it was created successfully, it can be opened
-    eventBox = lookupEventBox(
-        "week", EVENT_BOX, null, 5, 8,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    );
+    // If it was created successfully, it can be opened.
+    eventBox = lookupEventBox("week", EVENT_BOX, null, 5, null, EVENTPATH);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        // change title and save changes
+        // Change title and save changes.
         setData(event, iframe, { title: TITLE2 });
         event.click(eventid("button-saveandclose"));
     });
 
-    // check if name was saved
-    let eventName = lookupEventBox(
-        "week", EVENT_BOX, null, 5, 8,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}/
-        anon({"flex":"1"})/anon({"anonid":"event-container"})/
-        {"class":"calendar-event-selection"}/anon({"anonid":"eventbox"})/
-        {"class":"calendar-event-details"}/anon({"flex":"1"})/
-        anon({"anonid":"event-name"})`
+    // Check if name was saved.
+    let eventName = lookupEventBox("week", EVENT_BOX, null, 5, null,
+        `${EVENTPATH}/${getEventDetails("week")}/anon({"flex":"1"})/anon({"anonid":"event-name"})`
     );
     controller.waitForElement(eventName);
     controller.assertJSProperty(eventName, "textContent", TITLE2);
 
-    // delete event
-    controller.click(lookupEventBox(
-        "week", EVENT_BOX, null, 5, 8,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    ));
+    // Delete event.
+    controller.click(eventBox);
     controller.keypress(eid("week-view"), "VK_DELETE", {});
-    controller.waitForElementNotPresent(lookupEventBox(
-        "week", EVENT_BOX, null, 5, 8,
-        `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`
-    ));
+    controller.waitForElementNotPresent(eventBox);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }