Bug 535812 Mozmill test for calendar - event with no changes should not prompt to save, p=merike r=ctalbert
authorMerike Sell <merikes@gmail.com>
Thu, 28 Jan 2010 09:42:41 -0800
changeset 4776 2d3f3fe9f3f400f912fb6636513ff1165448966a
parent 4775 916b19c7290c8b12820f41160be507340cbfad01
child 4777 6bff80bb6dcdc363fd35e4f954a9cb96ca02aef4
push idunknown
push userunknown
push dateunknown
reviewersctalbert
bugs535812
Bug 535812 Mozmill test for calendar - event with no changes should not prompt to save, p=merike r=ctalbert
calendar/test/mozmill/shared-modules/testCalendarUtils.js
calendar/test/mozmill/testEventDialogModificationPrompt.js
--- a/calendar/test/mozmill/shared-modules/testCalendarUtils.js
+++ b/calendar/test/mozmill/shared-modules/testCalendarUtils.js
@@ -32,17 +32,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 const MODULE_NAME = 'CalendarUtils';
 
 const RELATIVE_ROOT = '.';
-const MODULE_REQUIRES = ['ModalDialogAPI'];
+const MODULE_REQUIRES = ['ModalDialogAPI', 'UtilsAPI'];
 
 const sleep = 500;
 const EVENT_BOX = 0; // Use when you need an event box
 const CANVAS_BOX = 1; // Use when you need a calendar canvas box
 const ALLDAY = 2; // Use when you need an allday canvas or event box
 
 /**
  *  Accept to send notification email with event to attendees
@@ -60,22 +60,21 @@ function acceptSendingNotificationMail()
 
 /**
  *  Add an attachment with url
  */
 function handleAddingAttachment(url){
   let api = collector.getModule('ModalDialogAPI');
   let md = new api.modalDialog(
     function(attachment){
-      attachment.sleep(sleep);
-      attachment.type(new elementslib.Lookup(attachment.window.document, '/id("commonDialog")/[4]/'
-        + '[1]/id("loginContainer")/id("loginTextbox")/anon({"class":"textbox-input-box"})/'
-        + 'anon({"anonid":"input"})'), url);
+      let input = new elementslib.ID(attachment.window.document, 'loginTextbox');
+      attachment.waitForElement(input);
+      input.getNode().value = url;
       attachment.click(new elementslib.Lookup(attachment.window.document, '/id("commonDialog")/'
-      + 'anon({"anonid":"buttons"})/{"dlgtype":"accept"}'));
+        + 'anon({"anonid":"buttons"})/{"dlgtype":"accept"}'));
     }
   );
   md.start();
 }
 
 /**
  *  Choose to delete just one occurrence of a repeating event
  *  @attendees whether there are attendees that can be notified or not
@@ -316,8 +315,236 @@ function createCalendar(name){
     '/id("messengerWindow")/id("tabmail-container")/id("tabmail")/id("tabpanelcontainer")/'
     + 'id("calendarTabPanel")/id("calendarContent")/id("ltnSidebar")/id("calendar-panel")/'
     + 'id("calendar-list-pane")/id("calendar-listtree-pane")/id("calendar-list-tree-widget")'))
     .getNode();
   for(i = 0; i < calendarTree.mCalendarList.length; i++)
     if(calendarTree.mCalendarList[i].id == id)
       calendarTree.tree.view.selection.select(i);
 }
+
+/**
+ *  Helper function to enter event dialog data
+ *  @param data - dataset object
+ *                  title - event title
+ *                  location - event location
+ *                  description - event description
+ *                  category - category label
+ *                  allday - boolean value
+ *                  startdate - Date object
+ *                  starttime - Date object
+ *                  enddate - Date object
+ *                  endtime - Date object
+ *                  timezone - false for local, true for set timezone
+ *                  repeat - reccurrence value, one of none/daily/weekly/every.weekday/bi.weekly/
+ *                           monthly/yearly/custom
+ *                  reminder - reminder option index
+ *                  priority - none/low/normal/high
+ *                  privacy - public/confidential/private
+ *                  status - none/tentative/confirmed/cancelled
+ *                  freebusy - free/busy
+ *                  attachment.add - url to add
+ *                  attachment.remove - label of url to remove (without http://)
+ *  @param event - event controller
+ */
+function setData(data, event) {
+  let eventDialog = '/id("calendar-event-dialog")/id("event-grid")/id("event-grid-rows")/';
+  let dateInput = '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 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 startDateInput = new elementslib.Lookup(event.window.document, eventDialog
+    + 'id("event-grid-startdate-row")/id("event-grid-startdate-picker-box")/id("event-starttime")/'
+    + dateInput);
+  let endDateInput = new elementslib.Lookup(event.window.document, eventDialog
+    + 'id("event-grid-enddate-row")/[1]/id("event-grid-enddate-picker-box")/id("event-endtime")/'
+    + dateInput);
+  let startTimeInput = new elementslib.Lookup(event.window.document, eventDialog
+    + 'id("event-grid-startdate-row")/id("event-grid-startdate-picker-box")/id("event-starttime")/'
+    + timeInput);
+  let endTimeInput = new elementslib.Lookup(event.window.document, eventDialog
+    + 'id("event-grid-enddate-row")/[1]/id("event-grid-enddate-picker-box")/id("event-endtime")/'
+    + timeInput);
+  let dateService = Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
+                              .getService(Components.interfaces.nsIScriptableDateFormat);
+  let utilsapi = collector.getModule('UtilsAPI');
+  let mac = utilsapi.appInfo.os.toLowerCase().indexOf("darwin") != -1;
+  // wait for input elements' values to be populated
+  event.sleep(sleep);
+  
+  // title
+  if (data.title != undefined) {
+    if (!mac) {
+      event.keypress(new elementslib.Lookup(event.window.document, eventDialog
+        + 'id("event-grid-title-row")/id("item-title")/anon({"class":"textbox-input-box"})/'
+        + 'anon({"anonid":"input"})'),
+        'a', {ctrlKey: true});
+      event.type(new elementslib.Lookup(event.window.document, eventDialog
+        + 'id("event-grid-title-row")/id("item-title")/anon({"class":"textbox-input-box"})/'
+        + 'anon({"anonid":"input"})'),
+        data.title);
+    } else {
+      let titleField = new elementslib.ID(event.window.document, "item-title");
+      titleField.getNode().value = data.title;
+    }
+  }
+  
+  // location
+  if (data.location != undefined) {
+    if (!mac) {
+      event.keypress(new elementslib.Lookup(event.window.document, eventDialog
+        + 'id("event-grid-location-row")/id("item-location")/anon({"class":"textbox-input-box"})/'
+        + 'anon({"anonid":"input"})'),
+        'a', {ctrlKey: true});
+      event.type(new elementslib.Lookup(event.window.document, eventDialog
+        + 'id("event-grid-location-row")/id("item-location")/anon({"class":"textbox-input-box"})/'
+        + 'anon({"anonid":"input"})'),
+        data.location);
+    } else {
+      let locationField = new elementslib.ID(event.window.document, "item-location");
+      locationField.getNode().value = data.location;
+    }
+  }
+  
+  // category
+  if (data.category != undefined) {
+    event.select(new elementslib.ID(event.window.document, "item-categories"), undefined,
+      data.category);
+    event.sleep(sleep);
+  }
+  
+  // all-day
+  if (data.allday != undefined) {
+    event.check(new elementslib.ID(event.window.document, "event-all-day"), data.allday);
+  }
+  
+  // timezone
+  if (data.timezone != undefined) {
+    let menuitem = new elementslib.Elem(event.menus["options-menu"]["options-timezone-menuitem"]);
+    menuitem.getNode().setAttribute("checked", data.timezone);
+    event.click(menuitem);
+  }
+  
+  // startdate
+  if (data.startdate != undefined && data.startdate.constructor.name == 'Date') {
+    let startdate = dateService.FormatDate("", dateService.dateFormatShort,
+      data.startdate.getFullYear(), data.startdate.getMonth() + 1, data.startdate.getDate());
+    if (utilsapi.appInfo.os.toLowerCase().indexOf("darwin") == -1) {
+      event.keypress(startDateInput, 'a', {ctrlKey: true});
+      event.type(startDateInput, startdate);
+    } else {
+      startDateInput.getNode().value = startdate;
+    }
+  }
+  
+  // starttime
+  if (data.starttime != undefined && data.starttime.constructor.name == 'Date') {
+    let starttime = dateService.FormatTime("", dateService.timeFormatNoSeconds,
+      data.starttime.getHours(), data.starttime.getMinutes(), 0);
+    if (utilsapi.appInfo.os.toLowerCase().indexOf("darwin") == -1) {
+      event.keypress(startTimeInput, 'a', {ctrlKey: true});
+      event.type(startTimeInput, starttime);
+    } else {
+      startTimeInput.getNode().value = starttime;
+      event.sleep(sleep);
+    }
+  }
+  
+  if (data.enddate != undefined && data.enddate.constructor.name == 'Date') {
+    let enddate = dateService.FormatDate("", dateService.dateFormatShort,
+      data.enddate.getFullYear(), data.enddate.getMonth() + 1, data.enddate.getDate());
+    if (utilsapi.appInfo.os.toLowerCase().indexOf("darwin") == -1) {
+      event.keypress(endDateInput, 'a', {ctrlKey: true});
+      event.type(endDateInput, enddate);
+    } else {
+      endDateInput.getNode().value = enddate;
+    }
+  }
+  
+  // endttime
+  if (data.endtime != undefined && data.endtime.constructor.name == 'Date') {
+    let endtime = dateService.FormatTime("", dateService.timeFormatNoSeconds,
+      data.endtime.getHours(), data.endtime.getMinutes(), 0);
+    if (utilsapi.appInfo.os.toLowerCase().indexOf("darwin") == -1) {
+      event.keypress(endTimeInput, 'a', {ctrlKey:true});
+      event.type(endTimeInput, endtime);
+    } else {
+      endTimeInput.getNode().value = endtime;
+      event.sleep(sleep);
+    }
+  }
+  
+  // recurrence
+  if (data.repeat != undefined) {
+    event.select(new elementslib.ID(event.window.document, "item-repeat"), undefined, undefined,
+      data.repeat);
+  }
+  
+  // reminder
+  if (data.reminder != undefined) {
+    event.select(new elementslib.ID(event.window.document, "item-alarm"), data.reminder);
+  }
+  
+  // description
+  if (data.description != undefined) {
+    if (!mac) {
+      event.keypress(new elementslib.Lookup(event.window.document, eventDialog
+        + 'id("event-grid-description-row")/id("item-description")/'
+        + 'anon({"class":"textbox-input-box"})/anon({"anonid":"input"})'),
+        'a', {ctrlKey: true});
+      event.type(new elementslib.Lookup(event.window.document, eventDialog
+        + 'id("event-grid-description-row")/id("item-description")/'
+        + 'anon({"class":"textbox-input-box"})/anon({"anonid":"input"})'),
+        data.description);
+    } else {
+      let descField = new elementslib.Lookup(event.window.document, eventDialog
+        + 'id("event-grid-description-row")/id("item-description")/'
+        + 'anon({"class":"textbox-input-box"})/anon({"anonid":"input"})');
+      descField.getNode().value = data.description;
+    }
+  }
+  
+  // priority
+  if (data.priority != undefined) {
+    event.click(new elementslib.Elem(event
+      .menus["options-menu"]["options-priority-menu"]["options-priority-" + data.priority
+      + "-label"]));
+  }
+  
+  // privacy
+  if (data.privacy != undefined) {
+    event.click(new elementslib.Elem(event
+      .menus["options-menu"]["options-privacy-menu"]["options-privacy-" + data.privacy
+      + "-menuitem"]));
+  }
+  
+  // status
+  if (data.status != undefined) {
+    event.click(new elementslib.Elem(event
+      .menus["options-menu"]["options-status-menu"]["options-status-" + data.status
+      + "-menuitem"]));
+  }
+  
+  // free/busy
+  if (data.freebusy != undefined) {
+    event.click(new elementslib.Elem(event
+      .menus["options-menu"]["options-freebusy-menu"]["options-freebusy-" + data.freebusy
+      + "-menuitem"]));
+  }
+  
+  // attachment
+  if (data.attachment != undefined) {
+    if (data.attachment.add != undefined) {
+      handleAddingAttachment(data.attachment.add);
+      event.click(new elementslib.ID(event.window.document, "button-url"));
+    }
+    if (data.attachment.delete != undefined) {
+      event.click(new elementslib.Lookup(event.window.document, eventDialog
+        + 'id("event-grid-attachment-row")/id("attachment-link")/{"label":"' +
+        data.attachment.delete + '"}'));
+      event.keypress(new elementslib.ID(event.window.document, "attachment-link"), "VK_DELETE", {});
+    }
+  }
+  
+  event.sleep(sleep);
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/calendar/test/mozmill/testEventDialogModificationPrompt.js
@@ -0,0 +1,176 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Mozmill Test Code.
+ *
+ * The Initial Developer of the Original Code is Merike Sell.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Merike Sell <merikes@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var RELATIVE_ROOT = './shared-modules';
+var MODULE_REQUIRES = ['CalendarUtils', 'ModalDialogAPI', 'PrefsAPI'];
+
+const sleep = 500;
+var calendar = "Mozmill";
+var title = "Title";
+var location = "Location";
+var description = "Description\ncontinuing";
+var pass;
+var date1 = new Date(2009, 0, 1,  8, 0);
+var date2 = new Date(2009, 0, 2,  9, 0);
+var date3 = new Date(2009, 0, 3, 10, 0);
+var data = [{title: "title1", location: "location1", description: "description1", allday: false,
+             startdate: date1, starttime: date1, enddate: date2, endtime: date2, repeat: "none",
+             reminder: 0, priority: "normal", privacy: "public", status: "confirmed", 
+             freebusy: "busy", timezone: true, attachment: {add: "http://mozilla.org"}},
+            {title: "title2", location: "location2", description: "description2", allday: true,
+             startdate: date2, starttime: date2, enddate: date3, endtime: date3, repeat: "daily",
+             reminder: 1, priority: "high", privacy: "private", status: "tentative", 
+             freebusy: "free", timezone: true, attachment: {delete: "mozilla.org"}}];
+var 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"}];
+
+var setupModule = function(module) {
+  controller = mozmill.getMail3PaneController();
+  CalendarUtils.createCalendar(calendar);
+  
+  let categories = PrefsAPI.preferences.getPref("calendar.categories.names", "string").split(',');
+  data[0].category = categories[0];
+  data[1].category = categories[1];
+}
+
+// Test that closing an event dialog with no changes does not prompt for save
+var testEventDialogModificationPrompt = function () {
+  controller.click(new elementslib.ID(controller.window.document,"calendar-tab-button"));
+  controller.sleep(sleep);
+  CalendarUtils.switchToView("day", controller);
+  CalendarUtils.goToDate(2009, 1, 1, controller);
+  
+  // create new event
+  controller.doubleClick(new elementslib.Lookup(controller.window.document,
+    CalendarUtils.getEventBoxPath("day", CalendarUtils.CANVAS_BOX, undefined, 1, 8, controller)));
+  controller.waitForEval('utils.getWindows("Calendar:EventDialog").length > 0', sleep);
+  let event = new mozmill.controller.MozMillController(mozmill.utils
+    .getWindows("Calendar:EventDialog")[0]);
+  
+  // enter first set of data
+  CalendarUtils.setData(data[0], event);
+  
+  // save
+  event.click(new elementslib.ID(event.window.document, "button-save"));
+  controller.sleep(sleep);
+  
+  // modal dialog setup
+  let md = new ModalDialogAPI.modalDialog(handleSavePrompt);
+  md.start();
+
+  // open, but change nothing
+  controller.doubleClick(new elementslib.Lookup(controller.window.document,
+    CalendarUtils.getEventBoxPath("day", CalendarUtils.EVENT_BOX, undefined, 1, 8, controller)
+    + '/{"tooltip":"itemTooltip"}'));
+  controller.waitForEval('utils.getWindows("Calendar:EventDialog").length > 0', sleep);
+  event = new mozmill.controller.MozMillController(mozmill.utils
+    .getWindows("Calendar:EventDialog")[0]);
+  
+  // escape the event window, there should be no prompt to save event
+  event.keypress(undefined, "VK_ESCAPE", {});
+  controller.sleep(sleep);
+  
+  // open
+  controller.doubleClick(new elementslib.Lookup(controller.window.document,
+    CalendarUtils.getEventBoxPath("day", CalendarUtils.EVENT_BOX, undefined, 1, 8, controller)
+    + '/{"tooltip":"itemTooltip"}'));
+  controller.waitForEval('utils.getWindows("Calendar:EventDialog").length > 0', sleep);
+  event = new mozmill.controller.MozMillController(mozmill.utils
+    .getWindows("Calendar:EventDialog")[0]);
+  
+  // change all values
+  CalendarUtils.setData(data[1], event);
+  
+  // edit all values back to original
+  CalendarUtils.setData(data[0], event);
+  
+  // escape the event window, there should be no prompt to save event
+  event.keypress(undefined, "VK_ESCAPE", {});
+  controller.sleep(sleep); 
+  // delete event
+  controller.click(new elementslib.Lookup(controller.window.document,
+    CalendarUtils.getEventBoxPath("day", CalendarUtils.EVENT_BOX, undefined, 1, 8, controller)));
+  controller.keypress(new elementslib.ID(controller.window.document, "day-view"),
+    "VK_DELETE", {});
+  
+  for(let i = 0; i < newlines.length; i++) {
+    // test set i
+    controller.doubleClick(new elementslib.Lookup(controller.window.document,
+      CalendarUtils.getEventBoxPath("day", CalendarUtils.CANVAS_BOX, undefined, 1, 8, controller)));
+    controller.waitForEval('utils.getWindows("Calendar:EventDialog").length > 0', sleep);
+    event = new mozmill.controller.MozMillController(mozmill.utils
+      .getWindows("Calendar:EventDialog")[0]);
+    CalendarUtils.setData(newlines[i], event);
+    event.click(new elementslib.ID(event.window.document, "button-save"));
+    controller.sleep(sleep);
+    
+    // open and close
+    controller.doubleClick(new elementslib.Lookup(controller.window.document,
+      CalendarUtils.getEventBoxPath("day", CalendarUtils.EVENT_BOX, undefined, 1, 8, controller)
+      + '/{"tooltip":"itemTooltip"}'));
+    controller.waitForEval('utils.getWindows("Calendar:EventDialog").length > 0', sleep);
+    event = new mozmill.controller.MozMillController(mozmill.utils
+      .getWindows("Calendar:EventDialog")[0]);
+    event.keypress(undefined, "VK_ESCAPE", {});
+    controller.sleep(sleep);
+    // delete it
+    controller.click(new elementslib.Lookup(controller.window.document,
+      CalendarUtils.getEventBoxPath("day", CalendarUtils.EVENT_BOX, undefined, 1, 8, controller)));
+    controller.keypress(new elementslib.ID(controller.window.document, "day-view"),
+      "VK_DELETE", {});
+    controller.sleep(sleep);
+  }
+}
+
+var teardownTest = function(module) {
+  CalendarUtils.deleteCalendars(calendar);
+  if (pass != undefined && pass == false) {
+    controller.assertJS('"Prompt appeared" == "Prompt didn\'t appear."');
+  }
+}
+
+function handleSavePrompt(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
+  pass = false;
+  // application close is blocked without it
+  controller.click(new elementslib.Lookup(controller.window.document,
+    '/id("commonDialog")/anon({"anonid":"buttons"})/{"dlgtype":"extra1"}'));
+}
\ No newline at end of file