Fix bug 980515 - [mozmill] make recurrence tests work again.
authorMarkus Adrario <mozilla@adrario.de>
Sat, 07 Jan 2017 18:23:02 +0100
changeset 20973 eab361faf708c751aa61a8245d9bea83733a8e6e
parent 20972 2231f130a183eae79746df4da367062d0ad04a9d
child 20974 89a6693a8133d5cf38a3815ff5633dcae17b62b3
push id12721
push userMozilla@Adrario.de
push dateSat, 07 Jan 2017 17:24:42 +0000
treeherdercomm-central@eab361faf708 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs980515
Fix bug 980515 - [mozmill] make recurrence tests work again.
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/mozmilltests.list
calendar/test/mozmill/recurrence/testAnnualRecurrence.js
calendar/test/mozmill/recurrence/testBiweeklyRecurrence.js
calendar/test/mozmill/recurrence/testDailyRecurrence.js
calendar/test/mozmill/recurrence/testLastDayOfMonthRecurrence.js
calendar/test/mozmill/recurrence/testWeeklyNRecurrence.js
calendar/test/mozmill/recurrence/testWeeklyUntilRecurrence.js
calendar/test/mozmill/recurrence/testWeeklyWithExceptionRecurrence.js
calendar/test/mozmill/shared-modules/test-calendar-utils.js
calendar/test/mozmill/shared-modules/test-timezone-utils.js
calendar/test/mozmill/testTodayPane.js
mail/test/mozmill/shared-modules/test-window-helpers.js
rename from calendar/test/mozmill/recurrence/testAnnualRecurrence.js
rename to calendar/test/mozmill/cal-recurrence/testAnnualRecurrence.js
--- a/calendar/test/mozmill/recurrence/testAnnualRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testAnnualRecurrence.js
@@ -1,56 +1,57 @@
 /* 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 RELATIVE_ROOT = "../shared-modules";
 var MODULE_REQUIRES = ["calendar-utils"];
 
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var switchToView, goToDate, handleOccurrencePrompt;
-var CALENDARNAME, ALLDAY;
+var CALENDARNAME, EVENTPATH, ALLDAY;
+var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
+var invokeEventDialog, deleteCalendars, createCalendar, menulistSelect;
 
-var STARTYEAR = 1950;
-var EPOCH = 1970;
+const STARTYEAR = 1950;
+const EPOCH = 1970;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        EVENTPATH,
+        ALLDAY,
         helpersForController,
-        invokeEventDialog,
-        createCalendar,
-        deleteCalendars,
+        handleOccurrencePrompt,
         switchToView,
         goToDate,
-        handleOccurrencePrompt,
-        CALENDARNAME,
-        ALLDAY
+        invokeEventDialog,
+        deleteCalendars,
+        createCalendar,
+        menulistSelect
     } = collector.getModule("calendar-utils"));
     collector.getModule("calendar-utils").setupModule();
     Object.assign(module, helpersForController(controller));
+
     createCalendar(controller, CALENDARNAME);
 }
 
 function testAnnualRecurrence() {
-    let EVENTPATH = `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`;
     controller.click(eid("calendar-tab-button"));
     sleep();
 
     switchToView(controller, "day");
     goToDate(controller, STARTYEAR, 1, 1);
 
     // create yearly recurring all-day event
     let eventBox = lookupEventBox("day", ALLDAY, null, 1, null);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        event.select(eventid("item-repeat"), null, null, "yearly");
-
-        // save
+        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;
rename from calendar/test/mozmill/recurrence/testBiweeklyRecurrence.js
rename to calendar/test/mozmill/cal-recurrence/testBiweeklyRecurrence.js
--- a/calendar/test/mozmill/recurrence/testBiweeklyRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testBiweeklyRecurrence.js
@@ -1,114 +1,112 @@
 /* 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 RELATIVE_ROOT = "../shared-modules";
 var MODULE_REQUIRES = ["calendar-utils"];
 
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var switchToView, goToDate, handleOccurrencePrompt, viewForward;
-var CALENDARNAME, EVENT_BOX, CANVAS_BOX;
+var CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
+var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
+var invokeEventDialog, viewForward, createCalendar, deleteCalendars, menulistSelect;
 
-var HOUR = 8;
+const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        EVENTPATH,
+        EVENT_BOX,
+        CANVAS_BOX,
         helpersForController,
-        invokeEventDialog,
-        createCalendar,
-        deleteCalendars,
+        handleOccurrencePrompt,
         switchToView,
         goToDate,
-        handleOccurrencePrompt,
+        invokeEventDialog,
         viewForward,
-        CALENDARNAME,
-        EVENT_BOX,
-        CANVAS_BOX
+        deleteCalendars,
+        createCalendar,
+        menulistSelect
     } = collector.getModule("calendar-utils"));
     collector.getModule("calendar-utils").setupModule();
     Object.assign(module, helpersForController(controller));
 
     createCalendar(controller, CALENDARNAME);
 }
 
 function testBiweeklyRecurrence() {
-    let eventPath = `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`;
-
     controller.click(eid("calendar-tab-button"));
     switchToView(controller, "day");
     goToDate(controller, 2009, 1, 31);
 
     // create biweekly 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"));
-        event.select(eventid("item-repeat"), null, null, "bi.weekly");
-
-        // save
+        menulistSelect(eventid("item-repeat"), "bi.weekly", event);
         event.click(eventid("button-saveandclose"));
     });
 
     // check day view
     for (let i = 0; i < 4; i++) {
-        controller.assertNode(
-            lookupEventBox("day", EVENT_BOX, null, 1, HOUR, eventPath)
+        controller.waitForElement(
+            lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH)
         );
         viewForward(controller, 14);
     }
 
     // check week view
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 31);
 
     for (let i = 0; i < 4; i++) {
-        controller.assertNode(
-            lookupEventBox("week", EVENT_BOX, null, 7, HOUR, eventPath)
+        controller.waitForElement(
+            lookupEventBox("week", EVENT_BOX, null, 7, HOUR, EVENTPATH)
         );
         viewForward(controller, 2);
     }
 
     // check multiweek view
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 31);
 
     // always two occurrences in view, 1st and 3rd or 2nd and 4th week
     for (let i = 0; i < 5; i++) {
-        controller.assertNode(
-            lookupEventBox("multiweek", EVENT_BOX, i % 2 + 1, 7, null, eventPath)
+        controller.waitForElement(
+            lookupEventBox("multiweek", EVENT_BOX, i % 2 + 1, 7, null, EVENTPATH)
         );
         controller.assertNode(
-            lookupEventBox("multiweek", EVENT_BOX, i % 2 + 3, 7, null, eventPath)
+            lookupEventBox("multiweek", EVENT_BOX, i % 2 + 3, 7, null, EVENTPATH)
         );
         viewForward(controller, 1);
     }
 
     // check month view
     switchToView(controller, "month");
     goToDate(controller, 2009, 1, 31);
 
     // January
-    controller.assertNode(lookupEventBox("month", EVENT_BOX, 5, 7, null, eventPath));
+    controller.waitForElement(lookupEventBox("month", EVENT_BOX, 5, 7, null, EVENTPATH));
     viewForward(controller, 1);
 
     // February
-    controller.assertNode(lookupEventBox("month", EVENT_BOX, 2, 7, null, eventPath));
-    controller.assertNode(lookupEventBox("month", EVENT_BOX, 4, 7, null, eventPath));
+    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.assertNode(lookupEventBox("month", EVENT_BOX, 2, 7, null, eventPath));
-    controller.assertNode(lookupEventBox("month", EVENT_BOX, 4, 7, null, eventPath));
+    controller.waitForElement(lookupEventBox("month", EVENT_BOX, 2, 7, null, EVENTPATH));
+    controller.assertNode(lookupEventBox("month", EVENT_BOX, 4, 7, null, EVENTPATH));
 
     // delete event
-    let box = lookupEventBox("month", EVENT_BOX, 4, 7, null, eventPath);
+    let box = lookupEventBox("month", EVENT_BOX, 4, 7, null, EVENTPATH);
     controller.click(box);
     handleOccurrencePrompt(controller, eid("month-view"), "delete", true, false);
     controller.waitForElementNotPresent(box);
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
rename from calendar/test/mozmill/recurrence/testDailyRecurrence.js
rename to calendar/test/mozmill/cal-recurrence/testDailyRecurrence.js
--- a/calendar/test/mozmill/recurrence/testDailyRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testDailyRecurrence.js
@@ -1,37 +1,40 @@
 /* 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 CALENDARNAME, EVENTPATH, EVENT_BOX, CANVAS_BOX;
 var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
 var switchToView, goToDate, viewForward, viewBack, handleOccurrencePrompt;
-var CALENDARNAME, EVENT_BOX, CANVAS_BOX;
+var menulistSelect;
 
-var HOUR = 8;
-var EVENTPATH = `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`;
+const HOUR = 8;
 
 function setupModule(module) {
     controller = mozmill.getMail3PaneController();
     ({
+        CALENDARNAME,
+        EVENTPATH,
+        EVENT_BOX,
+        CANVAS_BOX,
         helpersForController,
-        invokeEventDialog,
-        createCalendar,
-        deleteCalendars,
+        handleOccurrencePrompt,
         switchToView,
         goToDate,
+        invokeEventDialog,
         viewForward,
         viewBack,
-        handleOccurrencePrompt,
-        CALENDARNAME,
-        EVENT_BOX,
-        CANVAS_BOX
+        deleteCalendars,
+        createCalendar,
+        menulistSelect
     } = collector.getModule("calendar-utils"));
     collector.getModule("calendar-utils").setupModule();
     Object.assign(module, helpersForController(controller));
 
     createCalendar(controller, CALENDARNAME);
 }
 
 function testDailyRecurrence() {
@@ -39,74 +42,71 @@ function testDailyRecurrence() {
     switchToView(controller, "day");
     goToDate(controller, 2009, 1, 1);
 
     // create daily 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"));
-        event.select(eventid("item-repeat"), null, null, "daily");
-
-        // save
+        menulistSelect(eventid("item-repeat"), "daily", event);
         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));
 
     for (let day = 1; day <= 7; day++) {
-        controller.assertNode(lookup(daybox));
+        controller.waitForElement(lookup(daybox));
         viewForward(controller, 1);
     }
 
     // check week view for 2 weeks
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 1);
 
     for (let day = 5; day <= 7; day++) {
-        controller.assertNode(
+        controller.waitForElement(
             lookupEventBox("week", EVENT_BOX, 1, day, HOUR, EVENTPATH)
         );
     }
 
     viewForward(controller, 1);
 
     for (let day = 1; day <= 7; day++) {
-        controller.assertNode(
+        controller.waitForElement(
             lookupEventBox("week", EVENT_BOX, 2, day, HOUR, EVENTPATH)
         );
     }
 
     // check multiweek view for 4 weeks
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 1);
 
     for (let day = 5; day <= 7; day++) {
-        controller.assertNode(
+        controller.waitForElement(
             lookupEventBox("multiweek", EVENT_BOX, 1, day, HOUR, EVENTPATH)
         );
     }
 
     for (let week = 2; week <= 4; week++) {
         for (let day = 1; day <= 7; day++) {
-            controller.assertNode(
+            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.assertNode(
+        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)
@@ -118,37 +118,40 @@ function testDailyRecurrence() {
     let saturday = getEventBoxPath("month", EVENT_BOX, 1, 7, null) + EVENTPATH;
     controller.click(lookup(saturday));
     handleOccurrencePrompt(controller, eid("month-view"), "delete", false, false);
 
     // verify in all views
     controller.waitForElementNotPresent(lookup(saturday));
 
     switchToView(controller, "multiweek");
-    saturday = lookupEventBox("multiweek", EVENT_BOX, 1, 7, null, EVENTPATH);
-    controller.assertNodeNotExist(saturday);
+    controller.assertNodeNotExist(
+        lookupEventBox("multiweek", EVENT_BOX, 1, 7, null, EVENTPATH)
+    );
 
     switchToView(controller, "week");
-    saturday = lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH);
-    controller.assertNodeNotExist(saturday);
+    controller.assertNodeNotExist(
+        lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH)
+    );
 
     switchToView(controller, "day");
-    saturday = getEventBoxPath("day", EVENT_BOX, null, 1, null, EVENTPATH);
-    controller.assertNodeNotExist(saturday);
+    controller.assertNodeNotExist(
+        lookupEventBox("day", EVENT_BOX, null, 1, null, EVENTPATH)
+    );
 
     // 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);
     invokeEventDialog(controller, null, (event, iframe) => {
-        let { eid: eventid } = helpersForController(event);
+        let { eid: eventid, sleep: eventsleep } = helpersForController(event);
 
-        event.waitForElement(eventid("item-repeat"));
-        event.select(eventid("item-repeat"), null, null, "every.weekday");
+        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;
     let dates = [
         [2009, 1, 3],
         [2009, 1, 4]
@@ -158,44 +161,44 @@ function testDailyRecurrence() {
         controller.assertNodeNotExist(lookup(day));
     }
 
     // check week view for 2 weeks
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 1);
 
     for (let i = 0; i <= 1; i++) {
-        controller.assertNodeNotExist(
+        controller.waitForElementNotPresent(
             lookupEventBox("week", EVENT_BOX, null, 1, null, EVENTPATH)
         );
         controller.assertNodeNotExist(
             lookupEventBox("week", EVENT_BOX, null, 7, null, EVENTPATH)
         );
         viewForward(controller, 1);
     }
 
     // check multiweek view for 4 weeks
     switchToView(controller, "multiweek");
     goToDate(controller, 2009, 1, 1);
 
     for (let i = 1; i <= 4; i++) {
-        controller.assertNodeNotExist(
+        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
     switchToView(controller, "month");
     goToDate(controller, 2009, 1, 1);
 
     for (let i = 1; i <= 5; i++) {
-        controller.assertNodeNotExist(
+        controller.waitForElementNotPresent(
             lookupEventBox("month", EVENT_BOX, i, 1, null, EVENTPATH)
         );
         controller.assertNodeNotExist(
             lookupEventBox("month", EVENT_BOX, i, 7, null, EVENTPATH)
         );
     }
 
     // delete event
rename from calendar/test/mozmill/recurrence/testLastDayOfMonthRecurrence.js
rename to calendar/test/mozmill/cal-recurrence/testLastDayOfMonthRecurrence.js
--- a/calendar/test/mozmill/recurrence/testLastDayOfMonthRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testLastDayOfMonthRecurrence.js
@@ -1,65 +1,71 @@
 /* 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"];
+var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
 
-var helpersForController, invokeEventDialog, createCalendar;
-var deleteCalendars, switchToView, goToDate, handleOccurrencePrompt;
-var CALENDARNAME, EVENT_BOX, CANVAS_BOX;
+var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
+var CANVAS_BOX, REC_DLG_ACCEPT;
+var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
+var invokeEventDialog, deleteCalendars, createCalendar, menulistSelect;
+var plan_for_modal_dialog, wait_for_modal_dialog;
 
-var modalDialog = require("../shared-modules/modal-dialog");
-
-var HOUR = 8;
+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,
-        CALENDARNAME,
-        EVENT_BOX,
-        CANVAS_BOX
+        menulistSelect
     } = collector.getModule("calendar-utils"));
     collector.getModule("calendar-utils").setupModule();
     Object.assign(module, helpersForController(controller));
 
+    ({ plan_for_modal_dialog, wait_for_modal_dialog } =
+        collector.getModule("window-helpers")
+    );
+
     createCalendar(controller, CALENDARNAME);
 }
 
 function testLastDayOfMonthRecurrence() {
-    let eventPath = `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`;
-
     controller.click(eid("calendar-tab-button"));
     switchToView(controller, "day");
     goToDate(controller, 2008, 1, 31); // start with a leap year
 
     // create monthly recurring event
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        let dialog = new modalDialog.modalDialog(event.window);
-        dialog.start(setRecurrence);
-        event.waitForElement(eventid("item-repeat"));
-        event.select(eventid("item-repeat"), null, null, "custom");
+        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"));
     });
 
-    //                   year mo day  correct row in month view
-    //                   vvvv vv vvv  v
+    // data tuple: [year, month, day, row in month view]
+    // 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],
@@ -75,68 +81,62 @@ function testLastDayOfMonthRecurrence() 
         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)
+            lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH)
         );
 
         // week view
         switchToView(controller, "week");
         controller.waitForElement(
-            lookupEventBox("week", EVENT_BOX, null, column, HOUR, eventPath)
+            lookupEventBox("week", EVENT_BOX, null, column, HOUR, EVENTPATH)
         );
 
         // multiweek view
         switchToView(controller, "multiweek");
-        controller.assertNode(
-            lookupEventBox("multiweek", EVENT_BOX, 1, column, null, eventPath)
+        controller.waitForElement(
+            lookupEventBox("multiweek", EVENT_BOX, 1, column, null, EVENTPATH)
         );
 
         // month view
         switchToView(controller, "month");
-        controller.assertNode(
-            lookupEventBox("month", EVENT_BOX, correctRow, column, null, eventPath)
+        controller.waitForElement(
+            lookupEventBox("month", EVENT_BOX, correctRow, column, null, EVENTPATH)
         );
     }
 
     // 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;
+    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));
 }
 
 function setRecurrence(recurrence) {
     let {
         sleep: recsleep,
         lookup: reclookup,
         eid: recid
     } = helpersForController(recurrence);
 
     // monthly
-    recsleep();
-    recurrence.select(recid("period-list"), null, null, "2");
+    menulistSelect(recid("period-list"), "2", recurrence);
 
     // last day of month
-    recurrence.click(recid("montly-period-relative-date-radio"));
-    recsleep();
-    recurrence.select(recid("monthly-ordinal"), null, null, "-1");
-    recsleep();
-    recurrence.select(recid("monthly-weekday"), null, null, "-1");
+    recurrence.radio(recid("montly-period-relative-date-radio"));
+    menulistSelect(recid("monthly-ordinal"), "-1", recurrence);
+    menulistSelect(recid("monthly-weekday"), "-1", recurrence);
     recsleep();
 
     // close dialog
-    recurrence.click(reclookup(`
-        /id("calendar-event-dialog-recurrence")/anon({"anonid":"buttons"})/
-        {"dlgtype":"accept"}
-    `));
+    recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
rename from calendar/test/mozmill/recurrence/testWeeklyNRecurrence.js
rename to calendar/test/mozmill/cal-recurrence/testWeeklyNRecurrence.js
--- a/calendar/test/mozmill/recurrence/testWeeklyNRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testWeeklyNRecurrence.js
@@ -1,76 +1,89 @@
 /* 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"];
+var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
+
+Cu.import("resource://calendar/modules/calUtils.jsm");
 
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var switchToView, goToDate, viewForward, handleOccurrencePrompt;
-var CALENDARNAME, EVENT_BOX, CANVAS_BOX;
+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 plan_for_modal_dialog, wait_for_modal_dialog;
 
-var modalDialog = require("../shared-modules/modal-dialog");
-var utils = require("../shared-modules/utils");
-
-var HOUR = 8;
-var EVENTPATH = `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`;
+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,
-        invokeEventDialog,
-        createCalendar,
-        deleteCalendars,
+        handleOccurrencePrompt,
         switchToView,
         goToDate,
+        invokeEventDialog,
         viewForward,
-        handleOccurrencePrompt,
-        CALENDARNAME,
-        EVENT_BOX,
-        CANVAS_BOX
+        deleteCalendars,
+        createCalendar,
+        menulistSelect
     } = collector.getModule("calendar-utils"));
     collector.getModule("calendar-utils").setupModule();
     Object.assign(module, helpersForController(controller));
 
+    ({ 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
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        let dialog = new modalDialog.modalDialog(event.window);
-        dialog.start(setRecurrence);
+        plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         event.waitForElement(eventid("item-repeat"));
-        event.select(eventid("item-repeat"), null, null, "custom");
+        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;
     // Monday, Tuesday, Wednesday, Thursday
     for (let i = 0; i < 4; i++) {
-        controller.assertNode(
-            lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH)
-        );
+        controller.waitForElement(lookup(box));
         viewForward(controller, 1);
     }
 
-    // Saturday
+    // Not Friday
+    sleep();
+    controller.assertNodeNotExist(lookup(box));
     viewForward(controller, 1);
+
+    // Not Saturday as only 4 occurrences are set.
+    sleep();
     controller.assertNodeNotExist(lookup(box));
 
     // check week view
     switchToView(controller, "week");
 
     // Monday, Tuesday, Wednesday, Thursday
     for (let i = 2; i < 6; i++) {
         controller.waitForElement(
@@ -87,77 +100,64 @@ function testWeeklyNRecurrence() {
     switchToView(controller, "multiweek");
     checkMultiWeekView("multiweek");
 
     // check month view
     switchToView(controller, "month");
     checkMultiWeekView("month");
 
     // delete event
-    let box = getEventBoxPath("month", EVENT_BOX, 2, 2, HOUR) + EVENTPATH;
+    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));
 }
 
 function setRecurrence(recurrence) {
     let {
         sleep: recsleep,
         lookup: reclookup,
-        eid: recid
+        eid: recid,
     } = helpersForController(recurrence);
 
     // weekly
     recurrence.waitForElement(recid("period-list"));
-    recurrence.select(recid("period-list"), null, null, "1");
+    menulistSelect(recid("period-list"), "1", recurrence);
     recsleep();
 
-    let mon = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.2.Mmm");
-    let tue = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.3.Mmm");
-    let wed = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.4.Mmm");
-    let thu = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.5.Mmm");
-    let sat = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.7.Mmm");
+    let mon = cal.calGetString("dateFormat", "day.2.Mmm");
+    let tue = cal.calGetString("dateFormat", "day.3.Mmm");
+    let wed = cal.calGetString("dateFormat", "day.4.Mmm");
+    let thu = cal.calGetString("dateFormat", "day.5.Mmm");
+    let sat = cal.calGetString("dateFormat", "day.7.Mmm");
 
-    let 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"})
-    `;
-
-    // starting from Monday so it should be checked
-    recurrence.assertChecked(reclookup(`${days}/{"label":"${mon}"}`));
+    // 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
-    recurrence.click(reclookup(`${days}/{"label":"${tue}"}`));
-    recurrence.click(reclookup(`${days}/{"label":"${wed}"}`));
-    recurrence.click(reclookup(`${days}/{"label":"${thu}"}`));
-    recurrence.click(reclookup(`${days}/{"label":"${sat}"}`));
+    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
     recurrence.click(recid("recurrence-range-for"));
-    let input = `
-        /id("calendar-event-dialog-recurrence")/id("recurrence-range-groupbox")/[1]/
-        id("recurrence-duration")/id("recurrence-range-count-box")/
-        id("repeat-ntimes-count")/
-        anon({"class":"textbox-input-box numberbox-input-box"})/
-        anon({"anonid":"input"})
-    `;
-    // replace previous number
-    recurrence.keypress(reclookup(input), "a", { ctrlKey: true });
-    recurrence.type(reclookup(input), "4");
+    let ntimesField = recid("repeat-ntimes-count");
+    ntimesField.getNode().value = "4";
 
     // close dialog
-    recurrence.click(reclookup(`
-        /id("calendar-event-dialog-recurrence")/anon({"anonid":"buttons"})/
-        {"dlgtype":"accept"}
-    `));
+    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
     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)
         );
rename from calendar/test/mozmill/recurrence/testWeeklyUntilRecurrence.js
rename to calendar/test/mozmill/cal-recurrence/testWeeklyUntilRecurrence.js
--- a/calendar/test/mozmill/recurrence/testWeeklyUntilRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testWeeklyUntilRecurrence.js
@@ -1,114 +1,126 @@
 /* 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"];
+var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
 
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var switchToView, goToDate, handleOccurrencePrompt;
-var CALENDARNAME, EVENT_BOX, CANVAS_BOX;
+Cu.import("resource://calendar/modules/calUtils.jsm");
 
-var modalDialog = require("../shared-modules/modal-dialog");
-var utils = require("../shared-modules/utils");
+var SHORT_SLEEP, TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
+var CANVAS_BOX, REC_DLG_DAYS, REC_DLG_ACCEPT, REC_DLG_UNTIL_INPUT;
+var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
+var invokeEventDialog, viewForward, deleteCalendars, createCalendar, menulistSelect;
+var plan_for_modal_dialog, wait_for_modal_dialog;
 
-var ENDDATE = new Date(2009, 0, 26); // last Monday in month
-
-var HOUR = 8;
-var EVENTPATH = `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`;
+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,
-        invokeEventDialog,
-        createCalendar,
-        deleteCalendars,
+        handleOccurrencePrompt,
         switchToView,
         goToDate,
-        handleOccurrencePrompt,
-        CALENDARNAME,
-        EVENT_BOX,
-        CANVAS_BOX
+        invokeEventDialog,
+        viewForward,
+        deleteCalendars,
+        createCalendar,
+        menulistSelect
     } = collector.getModule("calendar-utils"));
     collector.getModule("calendar-utils").setupModule();
     Object.assign(module, helpersForController(controller));
 
-    createCalendar(controller, calendar);
+    ({ 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
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        let dialog = new modalDialog.modalDialog(event.window);
-        dialog.start(setRecurrence);
+        plan_for_modal_dialog("Calendar:EventDialog:Recurrence", setRecurrence);
         event.waitForElement(eventid("item-repeat"));
-        event.select(eventid("item-repeat"), null, null, "custom");
+        menulistSelect(eventid("item-repeat"), "custom", event);
+        wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
-        event.click(eventid("button-save"));
+        event.click(eventid("button-saveandclose"));
     });
 
     let box = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
 
     // check day view
     for (let week = 0; week < 3; week++) {
         // Monday
-        controller.assertNode(lookup(box));
-        forward(controller, 2);
+        controller.waitForElement(lookup(box));
+        viewForward(controller, 2);
 
         // Wednesday
-        controller.assertNode(lookup(box));
-        forward(controller, 2);
+        controller.waitForElement(lookup(box));
+        viewForward(controller, 2);
 
         // Friday
-        controller.assertNode(lookup(box));
-        forward(controller, 3);
+        controller.waitForElement(lookup(box));
+        viewForward(controller, 3);
     }
 
     // Monday, last occurrence
-    controller.assertNode(lookup(box));
-    forward(controller, 2);
+    controller.waitForElement(lookup(box));
+    viewForward(controller, 2);
 
     // Wednesday
-    controller.assertNodeNotExist(lookup(box));
-    forward(controller, 2);
+    controller.waitForElementNotPresent(lookup(box));
+    viewForward(controller, 2);
 
     // check week view
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 5);
     for (let week = 0; week < 3; week++) {
         // Monday
-        controller.assertNode(
+        controller.waitForElement(
             lookupEventBox("week", EVENT_BOX, null, 2, HOUR, EVENTPATH)
         );
 
         // Wednesday
-        controller.assertNode(
+        controller.waitForElement(
             lookupEventBox("week", EVENT_BOX, null, 4, HOUR, EVENTPATH)
         );
 
         // Friday
-        controller.assertNode(
+        controller.waitForElement(
             lookupEventBox("week", EVENT_BOX, null, 6, HOUR, EVENTPATH)
         );
 
-        forward(controller, 1);
+        viewForward(controller, 1);
     }
 
     // Monday, last occurrence
-    controller.assertNode(
+    controller.waitForElement(
         lookupEventBox("week", EVENT_BOX, null, 2, HOUR, EVENTPATH)
     );
     // Wednesday
     controller.assertNodeNotExist(
         lookupEventBox("week", EVENT_BOX, null, 4, HOUR, EVENTPATH)
     );
 
     // check multiweek view
@@ -124,65 +136,59 @@ function testWeeklyUntilRecurrence() {
     // 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));
 }
 
 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"));
-    recurrence.select(recid("period-list"), null, null, "1");
-    recsleep();
+    menulistSelect(recid("period-list"), "1", recurrence);
 
-    let mon = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.2.Mmm");
-    let wed = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.4.Mmm");
-    let fri = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.6.Mmm");
+    let mon = cal.calGetString("dateFormat", "day.2.Mmm");
+    let wed = cal.calGetString("dateFormat", "day.4.Mmm");
+    let fri = cal.calGetString("dateFormat", "day.6.Mmm");
 
-    let 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"})
-    `;
-
+    // 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
-    recurrence.assertChecked(reclookup(`${days}/{"label":"${mon}"}`));
+    recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${mon}"}`));
     // check Wednesday and Friday too
-    recurrence.click(reclookup(`${days}/{"label":"${wed}"}`));
-    recurrence.click(reclookup(`${days}/{"label":"${fri}"}`));
+    recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${wed}"}`));
+    recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${fri}"}`));
 
     // set until date
-    recurrence.click(recid("recurrence-range-until"));
-    let 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"})
-    `;
+    recurrence.radio(recid("recurrence-range-until"));
+
     // delete previous date
-    recurrence.keypress(reclookup(input), "a", { ctrlKey: true });
-    recurrence.keypress(reclookup(input), "VK_DELETE", {});
+    let untilInput = reclookup(REC_DLG_UNTIL_INPUT);
+    recurrence.keypress(untilInput, "a", { accelKey: true });
+    recurrence.keypress(untilInput, "VK_DELETE", {});
 
     let dateService = Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
                        .getService(Components.interfaces.nsIScriptableDateFormat);
     let ymd = [ENDDATE.getFullYear(), ENDDATE.getMonth() + 1, ENDDATE.getDate()];
     let endDateString = dateService.FormatDate("", dateService.dateFormatShort, ...ymd);
-    recurrence.type(reclookup(input), endDateString);
+    recsleep(SHORT_SLEEP);
+    recurrence.type(untilInput, endDateString);
+
+    recsleep(SHORT_SLEEP);
+    // Move focus to ensure the date is selected
+    recurrence.keypress(untilInput, "VK_TAB", {});
 
     // close dialog
-    recurrence.click(reclookup(`
-        /id("calendar-event-dialog-recurrence")/anon({"anonid":"buttons"})/
-        {"dlgtype":"accept"}
-    `));
+    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.assertNode(
@@ -199,16 +205,16 @@ function checkMultiWeekView(view) {
     }
 
     // Monday, last occurrence
     controller.assertNode(
         lookupEventBox(view, EVENT_BOX, startWeek + 3, 2, null, EVENTPATH)
     );
 
     // Wednesday
-    controller.assertNode(
+    controller.assertNodeNotExist(
         lookupEventBox(view, EVENT_BOX, startWeek + 3, 4, null, EVENTPATH)
     );
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, CALENDARNAME);
 }
rename from calendar/test/mozmill/recurrence/testWeeklyWithExceptionRecurrence.js
rename to calendar/test/mozmill/cal-recurrence/testWeeklyWithExceptionRecurrence.js
--- a/calendar/test/mozmill/recurrence/testWeeklyWithExceptionRecurrence.js
+++ b/calendar/test/mozmill/cal-recurrence/testWeeklyWithExceptionRecurrence.js
@@ -1,200 +1,191 @@
 /* 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"];
-
-var helpersForController, invokeEventDialog, createCalendar, deleteCalendars;
-var switchToView, goToDate, viewForward, handleOccurrencePrompt;
-var CALENDARNAME, EVENT_BOX, CANVAS_BOX;
+var MODULE_REQUIRES = ["calendar-utils", "window-helpers"];
 
-var modalDialog = require("../shared-modules/modal-dialog");
-var utils = require("../shared-modules/utils");
-
+var TIMEOUT_MODAL_DIALOG, CALENDARNAME, EVENTPATH, EVENT_BOX;
+var CANVAS_BOX, REC_DLG_ACCEPT, REC_DLG_DAYS;
+var helpersForController, handleOccurrencePrompt, switchToView, goToDate;
+var invokeEventDialog, viewForward, deleteCalendars, createCalendar, setData;
+var menulistSelect;
+var plan_for_modal_dialog, wait_for_modal_dialog;
 
-var HOUR = 8;
-var startDate = new Date(2009, 0, 6);
-var EVENTPATH = `/{"tooltip":"itemTooltip","calendar":"${CALENDARNAME.toLowerCase()}"}`;
+Cu.import("resource://calendar/modules/calUtils.jsm");
+
+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,
         helpersForController,
-        invokeEventDialog,
-        createCalendar,
-        deleteCalendars,
+        handleOccurrencePrompt,
         switchToView,
         goToDate,
+        invokeEventDialog,
         viewForward,
-        handleOccurrencePrompt,
-        CALENDARNAME,
-        EVENT_BOX,
-        CANVAS_BOX
+        deleteCalendars,
+        createCalendar,
+        setData,
+        menulistSelect
     } = collector.getModule("calendar-utils"));
     collector.getModule("calendar-utils").setupModule();
     Object.assign(module, helpersForController(controller));
 
+    ({ 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
     let eventBox = lookupEventBox("day", CANVAS_BOX, null, 1, HOUR);
     invokeEventDialog(controller, eventBox, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
 
-        let dialog = new modalDialog.modalDialog(event.window);
-        dialog.start(setRecurrence);
         event.waitForElement(eventid("item-repeat"));
-        event.select(eventid("item-repeat"), null, null, "custom");
+        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);
     invokeEventDialog(controller, null, (event, iframe) => {
-        let { lookup: eventlookup, eid: eventid } = helpersForController(event);
+        let { eid: eventid } = helpersForController(event);
 
-        let startDateInput = eventlookup(`
-            /id("calendar-event-dialog")/id("event-grid")/id("event-grid-rows")/
-            id("event-grid-startdate-row")/id("event-grid-startdate-picker-box")/
-            id("event-starttime")/anon({"anonid":"hbox"})/
-            anon({"anonid":"date-picker"})/anon({"class":"datepicker-box-class"})/
-            {"class":"datepicker-text-class"}/
-            anon({"class":"menulist-editable-box textbox-input-box"})/
-            anon({"anonid":"input"})
-        `);
-        let endDateInput = eventlookup(`
-            /id("calendar-event-dialog")/id("event-grid")/id("event-grid-rows")/
-            id("event-grid-enddate-row")/[1]/id("event-grid-enddate-picker-box")/
-            id("event-endtime")/anon({"anonid":"hbox"})/
-            anon({"anonid":"date-picker"})/anon({"class":"datepicker-box-class"})/
-            {"class":"datepicker-text-class"}/
-            anon({"class":"menulist-editable-box textbox-input-box"})/
-            anon({"anonid":"input"})
-        `);
-
-        event.keypress(startDateInput, "a", { ctrlKey: true });
-        let dateService = Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
-                           .getService(Components.interfaces.nsIScriptableDateFormat);
-        let ymd = [startDate.getFullYear(), startDate.getMonth() + 1, startDate.getDate()];
-        let startDateString = dateService.FormatDate("", dateService.dateFormatShort, ...ymd);
-
-        event.type(startDateInput, startDateString);
-        // applies startdate change
-        event.click(endDateInput);
-
+        setData(event, iframe, { startdate: STARTDATE, enddate: STARTDATE });
         event.click(eventid("button-saveandclose"));
     });
 
     // change recurrence rule
     goToDate(controller, 2009, 1, 7);
     eventBox = lookupEventBox("day", EVENT_BOX, null, 1, HOUR, EVENTPATH);
     handleOccurrencePrompt(controller, eventBox, "modify", true, false);
     invokeEventDialog(controller, null, (event, iframe) => {
         let { eid: eventid } = helpersForController(event);
+        let { lookup: iframelookup } = helpersForController(iframe);
 
-        dialog = new modalDialog.modalDialog(event.window);
-        dialog.start(changeRecurrence);
         event.waitForElement(eventid("item-repeat"));
-        event.select(eventid("item-repeat"), null, null, "custom");
+        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]
+        `));
+        wait_for_modal_dialog("Calendar:EventDialog:Recurrence", TIMEOUT_MODAL_DIALOG);
 
         event.click(eventid("button-saveandclose"));
     });
 
     // check two weeks
     // day view
     switchToView(controller, "day");
     let path = getEventBoxPath("day", EVENT_BOX, null, 1, HOUR) + EVENTPATH;
 
     goToDate(controller, 2009, 1, 5);
-    controller.assertNodeNotExist(lookup(path));
+    controller.waitForElementNotPresent(lookup(path));
 
     viewForward(controller, 1);
     let tuesPath = `
         /id("messengerWindow")/id("tabmail-container")/id("tabmail")/
         id("tabpanelcontainer")/id("calendarTabPanel")/id("calendarContent")/
         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":"topbox"})/{"flex":"1"}/{"flex":"1"}/[eventIndex]
     `;
+
     // assert exactly two
-    controller.assertNode(lookup(tuesPath.replace("eventIndex", "0") + EVENTPATH));
+    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.assertNode(lookup(path));
+    controller.waitForElement(lookup(path));
     viewForward(controller, 1);
-    controller.assertNodeNotExist(lookup(path));
+    controller.waitForElementNotPresent(lookup(path));
     viewForward(controller, 1);
-    controller.assertNode(lookup(path));
+    controller.waitForElement(lookup(path));
     viewForward(controller, 1);
-    controller.assertNodeNotExist(lookup(path));
+    controller.waitForElementNotPresent(lookup(path));
     viewForward(controller, 1);
-    controller.assertNodeNotExist(lookup(path));
+    controller.waitForElementNotPresent(lookup(path));
 
     // next week
     viewForward(controller, 1);
-    controller.assertNode(lookup(path));
+    controller.waitForElement(lookup(path));
     viewForward(controller, 1);
-    controller.assertNode(lookup(path));
+    controller.waitForElement(lookup(path));
     viewForward(controller, 1);
-    controller.assertNode(lookup(path));
+    controller.waitForElement(lookup(path));
     viewForward(controller, 1);
-    controller.assertNodeNotExist(lookup(path));
+    controller.waitForElementNotPresent(lookup(path));
     viewForward(controller, 1);
-    controller.assertNode(lookup(path));
+    controller.waitForElement(lookup(path));
     viewForward(controller, 1);
-    controller.assertNodeNotExist(lookup(path));
+    controller.waitForElementNotPresent(lookup(path));
 
     // week view
     switchToView(controller, "week");
     goToDate(controller, 2009, 1, 5);
 
-    path = getEventBoxPath("week", EVENT_BOX, null, 2, HOUR) + EVENTPATH;
-    controller.assertNodeNotExist(lookup(path));
-
     tuesPath = `
         /id("messengerWindow")/id("tabmail-container")/id("tabmail")/
         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"})/
         anon({"anonid":"topbox"})/{"flex":"1"}/{"flex":"1"}/[eventIndex]
     `;
+
     // assert exactly two
-    controller.assertNode(lookup(
+    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
+    controller.assertNodeNotExist(lookup(
+        tuesPath.replace("dayIndex", "2").replace("eventIndex", "2") + EVENTPATH
     ));
 
+    // check not present node after we are sure the existing ones are displayed.
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 2, HOUR));
+
     controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 4, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 5, HOUR));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 5, HOUR));
     controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 6, HOUR));
-    controller.assertNode(lookupEventBox("week", EVENT_BOX, null, 7, HOUR));
+    controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, HOUR));
 
     viewForward(controller, 1);
+    controller.waitForElement(lookupEventBox("week", EVENT_BOX, null, 2, 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.assertNode(lookupEventBox("week", EVENT_BOX, null, 6, HOUR));
     controller.assertNodeNotExist(lookupEventBox("week", EVENT_BOX, null, 7, HOUR));
 
     // multiweek view
     switchToView(controller, "multiweek");
@@ -210,106 +201,87 @@ function testWeeklyWithExceptionRecurren
     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));
 }
 
 function setRecurrence(recurrence) {
-    let {
-        sleep: recsleep,
-        lookup: reclookup,
-        eid: recid
-    } = helpersForController(recurrence);
+    let { lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
-    recurrence.waitForElement(recid("period-list"));
-    recurrence.select(recid("period-list"), null, null, "1");
-    recsleep();
+    menulistSelect(recid("period-list"), "1", recurrence);
 
-    let mon = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.2.Mmm");
-    let wed = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.4.Mmm");
-    let fri = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.6.Mmm");
+    let mon = cal.calGetString("dateFormat", "day.2.Mmm");
+    let wed = cal.calGetString("dateFormat", "day.4.Mmm");
+    let fri = cal.calGetString("dateFormat", "day.6.Mmm");
 
-    let 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"})
-    `;
-
-    // starting from Monday so it should be checked
-    recurrence.assertChecked(reclookup(`${days}/{"label":"${mon}"}`));
+    // 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
-    recurrence.click(reclookup(`${days}/{"label":"${wed}"}`));
-    recurrence.click(reclookup(`${days}/{"label":"${fri}"}`));
+    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
-    recurrence.click(reclookup(`
-        /id("calendar-event-dialog-recurrence")/anon({"anonid":"buttons"})/
-        {"dlgtype":"accept"}
-    `));
+    recurrence.click(reclookup(REC_DLG_ACCEPT));
 }
 
 function changeRecurrence(recurrence) {
-    let {
-        sleep: recsleep,
-        lookup: reclookup,
-        eid: recid
-    } = helpersForController(recurrence);
+    let { lookup: reclookup, eid: recid } = helpersForController(recurrence);
 
     // weekly
-    recurrence.waitForElement(recid("period-list"));
-    recurrence.select(recid("period-list"), null, null, "1");
-    recsleep();
+    menulistSelect(recid("period-list"), "1", recurrence);
 
-    let mon = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.2.Mmm");
-    let tue = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.3.Mmm");
-    let wed = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.4.Mmm");
-    let fri = utils.getProperty("chrome://calendar/locale/dateFormat.properties", "day.6.Mmm");
-
-    let 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"})/
-    `;
+    let mon = cal.calGetString("dateFormat", "day.2.Mmm");
+    let tue = cal.calGetString("dateFormat", "day.3.Mmm");
+    let wed = cal.calGetString("dateFormat", "day.4.Mmm");
+    let fri = cal.calGetString("dateFormat", "day.6.Mmm");
 
     // check old rule
-    recurrence.assertChecked(reclookup(`${days}/{"label":"${mon}"}`));
-    recurrence.assertChecked(reclookup(`${days}/{"label":"${wed}"}`));
-    recurrence.assertChecked(reclookup(`${days}/{"label":"${fri}"}`));
+    // 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
-    recurrence.click(reclookup(`${days}/{"label":"${tue}"}`));
+    recurrence.click(reclookup(`${REC_DLG_DAYS}/{"label":"${tue}"}`));
+    recurrence.assertChecked(reclookup(`${REC_DLG_DAYS}/{"label":"${tue}"}`));
 
     // close dialog
-    recurrence.click(reclookup(`
-        /id("calendar-event-dialog-recurrence")/anon({"anonid":"buttons"})/
-        {"dlgtype":"accept"}
-    `));
+    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));
     };
 
-    assertNodeNotExistLookup(view, EVENT_BOX, startWeek, 2, HOUR, EVENTPATH);
+    // wait for the first items, then check te ones not to be present
     // assert exactly two
-    assertNodeLookup(view, EVENT_BOX, startWeek, 3, HOUR, "/[0]");
+    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]");
+    // 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 + 1, 1, HOUR, EVENTPATH);
     assertNodeLookup(view, EVENT_BOX, startWeek + 1, 2, HOUR, EVENTPATH);
     assertNodeLookup(view, EVENT_BOX, startWeek + 1, 3, HOUR, EVENTPATH);
--- a/calendar/test/mozmill/mozmilltests.list
+++ b/calendar/test/mozmill/mozmilltests.list
@@ -1,4 +1,5 @@
+cal-recurrence
 testAlarmDefaultValue.js
 testBasicFunctionality.js
 testLocalICS.js
 testTodayPane.js
--- a/calendar/test/mozmill/shared-modules/test-calendar-utils.js
+++ b/calendar/test/mozmill/shared-modules/test-calendar-utils.js
@@ -17,16 +17,38 @@ var MID_SLEEP = 500;
 var TIMEOUT_MODAL_DIALOG = 30000;
 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
 
+// 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"}
+`;
+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"})
+`;
+
 var plan_for_modal_dialog, wait_for_modal_dialog, open_pref_window;
 
 function setupModule() {
     ({ 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
     // loading of modules in shared modules does not setup the module correctly.
@@ -37,19 +59,23 @@ function setupModule() {
 }
 
 function installInto(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.EVENTPATH = EVENTPATH;
     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
     module.helpersForController = helpersForController;
     module.acceptSendingNotificationMail = acceptSendingNotificationMail;
     module.handleAddingAttachment = handleAddingAttachment;
     module.handleOccurrencePrompt = handleOccurrencePrompt;
     module.switchToView = switchToView;
     module.goToDate = goToDate;
     module.invokeEventDialog = invokeEventDialog;
@@ -79,16 +105,30 @@ function helpersForController(controller
         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));
         }
     };
 }
 
 /**
+ * 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.
+    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(`
@@ -151,35 +191,20 @@ function handleOccurrencePrompt(controll
  * 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 views = { day: 0, week: 1, multiweek: 2, month: 3 };
-    controller.waitForEvents.init(
-        controller.window.getViewDeck().childNodes[views[view]],
-        ["viewloaded"]
-    );
     let button = `calendar-${view}-view-button`;
-    controller.waitThenClick(eid(button));
 
-    // wait for the view to be loaded
-    try {
-        controller.waitForEvents.wait(4000);
-    } catch (err) {
-      // The event only fires, if the view reloads the displayed events.
-      // when switching from month-view to day-view, changing forward-backward
-      // some times, it may be still the same month when switching back to
-      // month-view. In this case we just have to wait for the view to be ready.
-      // Since data loading may take some time, we have to wait a decent time
-      // to give the view time to load and fire the event.
-    }
+    controller.waitThenClick(eid(button));
+    ensureViewLoaded(controller);
 }
 
 /**
  * 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
@@ -258,17 +283,17 @@ function goToDate(controller, year, mont
     let dateColumn = (positionOfFirst + day - 1) % 7;
     let dateRow = Math.floor((positionOfFirst + day - 1) / 7);
 
     // pick day
     controller.click(lookup(`
         ${miniMonth}/anon({"anonid":"minimonth-calendar"})/[${dateRow + 1}]/
         [${dateColumn + 1}]
     `));
-    sleep();
+    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.
  *
  * @param controller    Main window controller
  * @param clickBox      The box to click on, or null if no box to click on.
@@ -367,31 +392,33 @@ function getEventBoxPath(controller, vie
  */
 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
  *
  * @param controller    Mozmill window controller
  * @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
  *
  * @param controller    Mozmill window controller
  * @param name          calendar name
  */
@@ -685,17 +712,18 @@ function setData(dialog, iframe, data) {
             data.startdate.getMonth() + 1,
             data.startdate.getDate()
         ];
         let startdate = dateService.FormatDate("", dateService.dateFormatShort, ...ymd);
 
         if (!isEvent) {
             dialog.check(iframeId("todo-has-entrydate"), true);
         }
-        startDateInput.getNode().value = startdate;
+        dialog.keypress(startDateInput, "a", { accelKey: true });
+        dialog.type(startDateInput, startdate);
     }
 
     // starttime
     if (data.starttime != undefined && data.starttime.constructor.name == "Date") {
         let hms = [data.starttime.getHours(), data.starttime.getMinutes(), 0];
         let starttime = dateService.FormatTime("", dateService.timeFormatNoSeconds, ...hms);
         startTimeInput.getNode().value = starttime;
         sleep();
@@ -707,17 +735,18 @@ function setData(dialog, iframe, data) {
             data.enddate.getFullYear(),
             data.enddate.getMonth() + 1,
             data.enddate.getDate()
         ];
         let enddate = dateService.FormatDate("", dateService.dateFormatShort, ...ymd);
         if (!isEvent) {
             dialog.check(iframeId("todo-has-duedate"), true);
         }
-        endDateInput.getNode().value = enddate;
+        dialog.keypress(endDateInput, "a", { accelKey: true });
+        dialog.type(endDateInput, enddate);
     }
 
     // endtime
     if (data.endtime != undefined && data.endtime.constructor.name == "Date") {
         let hms = [data.endtime.getHours(), data.endtime.getMinutes(), 0];
         let endtime = dateService.FormatTime("", dateService.timeFormatNoSeconds, ...hms);
         endTimeInput.getNode().value = endtime;
     }
@@ -820,14 +849,15 @@ function openLightningPrefs(aCallback, a
  * 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 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();
     aController.waitFor(() => { return menulist.value == aValue; });
 }
--- a/calendar/test/mozmill/shared-modules/test-timezone-utils.js
+++ b/calendar/test/mozmill/shared-modules/test-timezone-utils.js
@@ -8,18 +8,20 @@ var MODULE_REQUIRES = ["calendar-utils"]
 
 Cu.import("resource://gre/modules/Preferences.jsm");
 
 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 = ["America/St_Johns", "America/Caracas", "America/Phoenix", "America/Los_Angeles",
-                 "America/Argentina/Buenos_Aires", "Europe/Paris", "Asia/Kathmandu", "Australia/Adelaide"];
+var TIMEZONES = [
+    "America/St_Johns", "America/Caracas", "America/Phoenix", "America/Los_Angeles",
+    "America/Argentina/Buenos_Aires", "Europe/Paris", "Asia/Kathmandu", "Australia/Adelaide"
+];
 
 var helpersForController, goToDate, viewForward, viewBack, findEventsInNode;
 
 function setupModule() {
     ({ helpersForController, goToDate, viewForward, viewBack, findEventsInNode } =
         collector.getModule("calendar-utils"));
 }
 
--- a/calendar/test/mozmill/testTodayPane.js
+++ b/calendar/test/mozmill/testTodayPane.js
@@ -287,9 +287,8 @@ function getIsoDate() {
     let month = (currDate.getMonth() + 1).toString().padStart(2, "0");
     let day = currDate.getDate().toString().padStart(2, "0");
     return `${currDate.getFullYear()}${month}${day}`;
 }
 
 function teardownTest(module) {
     deleteCalendars(controller, "Mozmill");
 }
-
old mode 100644
new mode 100755