Bug 1328219 - (Part 2) Add browser-chrome test for datepicker draft
authorScott Wu <scottcwwu@gmail.com>
Thu, 26 Jan 2017 14:52:11 +0800
changeset 466626 f9862cad3ec2201f0589fe99a7c0395a56f1e1dc
parent 466625 056c82cde3a0365ae2ad5e33d64da8d956a7b096
child 543467 78f79bfd3206fe5f5e831ab5ce87d84a18d78f8c
push id42943
push userbmo:scwwu@mozilla.com
push dateThu, 26 Jan 2017 06:53:39 +0000
bugs1328219
milestone53.0a1
Bug 1328219 - (Part 2) Add browser-chrome test for datepicker MozReview-Commit-ID: JX3TIqTVvzP
toolkit/content/tests/browser/browser.ini
toolkit/content/tests/browser/browser_datetime_datepicker.js
toolkit/content/tests/browser/common/datetimePickerHelper.js
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -17,16 +17,19 @@ support-files =
 [browser_bug451286.js]
 skip-if = !e10s
 [browser_bug594509.js]
 [browser_bug982298.js]
 [browser_bug1198465.js]
 [browser_contentTitle.js]
 [browser_crash_previous_frameloader.js]
 run-if = e10s && crashreporter
+[browser_datetime_datepicker.js]
+support-files =
+  common/datetimePickerHelper.js
 [browser_default_image_filename.js]
 [browser_f7_caret_browsing.js]
 [browser_findbar.js]
 [browser_label_textlink.js]
 [browser_isSynthetic.js]
 support-files =
   empty.png
 [browser_keyevents_during_autoscrolling.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_datetime_datepicker.js
@@ -0,0 +1,186 @@
+/* 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/. */
+
+Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/datetimePickerHelper.js", this);
+
+const MONTH_YEAR = ".month-year",
+      WEEK_HEADER = ".week-header",
+      DAYS_VIEW = ".days-view",
+      BTN_PREV_MONTH = ".left",
+      BTN_NEXT_MONTH = ".right",
+      YEAR_SPINNER = "#year .spinner",
+      MONTH_SPINNER = "#month .spinner";
+
+const helper = new dateTimeTestHelper({
+  itemHeight: 25,
+  viewportSize: 5
+});
+const dateFormat = new Intl.DateTimeFormat("en-US", { year: "numeric", month: "long" }).format;
+const getCalendar = () => helper.getChildren(DAYS_VIEW, child => child.textContent);
+const getSpinnerCenter = spinner => spinner.scrollTop / ITEM_HEIGHT + (VIEWPORT_SIZE - 1) / 2;
+
+
+/**
+ * Test that date picker opens to today's date when input field is blank
+ */
+add_task(function* () {
+  const date = new Date();
+
+  yield helper.openTab("data:text/html, <input type='date'>");
+
+  Assert.equal(helper.getElement(MONTH_YEAR).textContent, dateFormat(date));
+
+  helper.tearDown();
+});
+
+/**
+ * Test that date picker opens to the correct month, with calendar days
+ * displayed correctly, given a date value is set.
+ */
+add_task(function* () {
+  const inputValue = "2016-12-01";
+
+  yield helper.openTab(`data:text/html, <input type="date" value="${inputValue}">`);
+
+  Assert.equal(helper.getElement(MONTH_YEAR).textContent, dateFormat(new Date(inputValue)));
+  Assert.deepEqual(
+    getCalendar(),
+    [
+      "27", "28", "29", "30",  "1",  "2",  "3",
+       "4",  "5",  "6",  "7",  "8",  "9", "10",
+      "11", "12", "13", "14", "15", "16", "17",
+      "18", "19", "20", "21", "22", "23", "24",
+      "25", "26", "27", "28", "29", "30", "31",
+       "1",  "2",  "3",  "4",  "5",  "6",  "7"
+    ],
+    "2016-12"
+  );
+
+  helper.tearDown();
+});
+
+/**
+ * When the prev month button is clicked, calendar should display the dates for
+ * the previous month.
+ */
+add_task(function* () {
+  const inputValue = "2016-12-01";
+  const prevMonth = "2016-11-01";
+
+  yield helper.openTab(`data:text/html, <input type="date" value="${inputValue}">`);
+  helper.click(helper.getElement(BTN_PREV_MONTH));
+
+  Assert.equal(helper.getElement(MONTH_YEAR).textContent, dateFormat(new Date(prevMonth)));
+  Assert.deepEqual(
+    getCalendar(),
+    [
+      "30", "31",  "1",  "2",  "3",  "4",  "5",
+       "6",  "7",  "8",  "9", "10", "11", "12",
+      "13", "14", "15", "16", "17", "18", "19",
+      "20", "21", "22", "23", "24", "25", "26",
+      "27", "28", "29", "30",  "1",  "2",  "3",
+       "4",  "5",  "6",  "7",  "8",  "9", "10"
+    ],
+    "2016-11"
+  );
+
+  helper.tearDown();
+});
+
+/**
+ * When the next month button is clicked, calendar should display the dates for
+ * the next month.
+ */
+add_task(function* () {
+  const inputValue = "2016-12-01";
+  const nextMonth = "2017-01-01";
+
+  yield helper.openTab(`data:text/html, <input type="date" value="${inputValue}">`);
+  helper.click(helper.getElement(BTN_NEXT_MONTH));
+
+  Assert.equal(helper.getElement(MONTH_YEAR).textContent, dateFormat(new Date(nextMonth)));
+  Assert.deepEqual(
+    getCalendar(),
+    [
+      "25", "26", "27", "28", "29", "30", "31",
+       "1",  "2",  "3",  "4",  "5",  "6",  "7",
+       "8",  "9", "10", "11", "12", "13", "14",
+      "15", "16", "17", "18", "19", "20", "21",
+      "22", "23", "24", "25", "26", "27", "28",
+      "29", "30", "31",  "1",  "2",  "3",  "4"
+    ],
+    "2017-01"
+  );
+
+  helper.tearDown();
+});
+
+/**
+ * When a date on the calendar is clicked, date picker should close and set
+ * value to the input box.
+ */
+add_task(function* () {
+  const inputValue = "2016-12-01";
+  const firstDayOnCalendar = "2016-11-27";
+
+  yield helper.openTab(`data:text/html, <input type="date" value="${inputValue}">`);
+  // Click the first item (top-left corner) of the calendar
+  helper.click(helper.getElement(DAYS_VIEW).children[0]);
+
+  yield BrowserTestUtils.waitForCondition(() => {
+    return helper.dateTimePickerPanel.hidden == true;
+  });
+  // XXX: Input box value won't be set until blur or receive keyboard events.
+  //      This should be fixed in the future.
+  content.document.querySelector("input").blur();
+
+  Assert.equal(content.document.querySelector("input").value, firstDayOnCalendar);
+
+  helper.tearDown();
+});
+
+/**
+ * The spinners should have current month and year at the center, and changing them
+ * will update the calendar accordingly.
+ */
+add_task(function* () {
+  const inputValue = "2016-12-01";
+  yield helper.openTab(`data:text/html, <input type="date" value="${inputValue}">`);
+
+  helper.click(helper.getElement(MONTH_YEAR));
+
+  Assert.equal(helper.getSpinnerElement(YEAR_SPINNER).textContent, "2016");
+  Assert.equal(helper.getSpinnerElement(MONTH_SPINNER).textContent, "Dec");
+
+  // Wait for the month-year picker to open
+  yield helper.waitForScrollStop(YEAR_SPINNER);
+  yield BrowserTestUtils.waitForCondition(() => true);
+
+  helper.click(helper.getSpinnerElement(YEAR_SPINNER, 2));
+  yield helper.waitForScrollStop(YEAR_SPINNER);
+
+  helper.click(helper.getSpinnerElement(MONTH_SPINNER, -2));
+  yield helper.waitForScrollStop(MONTH_SPINNER);
+
+  Assert.equal(helper.getSpinnerElement(YEAR_SPINNER).textContent, "2018");
+  Assert.equal(helper.getSpinnerElement(MONTH_SPINNER).textContent, "Oct");
+
+  // Close the month-year picker
+  helper.click(helper.getElement(MONTH_YEAR));
+
+  Assert.deepEqual(
+    getCalendar(),
+    [
+      "30",  "1",  "2",  "3",  "4",  "5",  "6",
+       "7",  "8",  "9", "10", "11", "12", "13",
+      "14", "15", "16", "17", "18", "19", "20",
+      "21", "22", "23", "24", "25", "26", "27",
+      "28", "29", "30", "31",  "1",  "2",  "3",
+       "4",  "5",  "6",  "7",  "8",  "9", "10"
+    ],
+    "2018-10"
+  );
+
+  helper.tearDown();
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/common/datetimePickerHelper.js
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const ITEM_HEIGHT = 25,
+      VIEWPORT_SIZE = 5,
+      VIEWPORT_COUNT = 5,
+      DAY_PERIOD_IN_HOURS = 12,
+      HOUR = "#hour",
+      MINUTE = "#minute",
+      DAY_PERIOD = "#day-period",
+      SPINNER = ".spinner",
+      UP = ".up",
+      DOWN = ".down";
+
+function dateTimeTestHelper({ itemHeight, viewportSize }) {
+  this.itemHeight = itemHeight;
+  this.viewportSize = viewportSize;
+  this.dateTimePickerPanel = document.getElementById("DateTimePickerPanel");
+  this.dateTimePopupFrame = this.dateTimePickerPanel.dateTimePopupFrame;
+}
+
+dateTimeTestHelper.prototype = {
+  *openTab(pageUrl) {
+    this.tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
+    let popupLoadedPromise = BrowserTestUtils.waitForEvent(this.dateTimePopupFrame, "load", true);
+    yield BrowserTestUtils.synthesizeMouseAtCenter("input", {}, gBrowser.selectedBrowser);
+    yield popupLoadedPromise;
+    yield BrowserTestUtils.waitForEvent(this.dateTimePopupFrame.contentDocument, "PickerReady");
+  },
+  closeTab() {
+    return BrowserTestUtils.removeTab(this.tab);
+  },
+  closePicker() {
+    this.dateTimePickerPanel.closePicker();
+  },
+  getSpinnerElement(selector, offset = 0) {
+    let spinner = this.getElement(selector);
+    let spinnerCenterIndex = this.getCenterElementIndex(spinner);
+    return spinner.childNodes[spinnerCenterIndex + offset];
+  },
+  getCenterElementIndex(spinner) {
+    return spinner.scrollTop / this.itemHeight + (this.viewportSize - 1) / 2;
+  },
+  getElement(selector) {
+    return this.dateTimePopupFrame.contentDocument.querySelector(selector);
+  },
+  getChildren(selector, cb) {
+    let childElements = this.getElement(selector).children;
+    return Array.prototype.map.call(childElements, cb);
+  },
+  click(element) {
+    EventUtils.synthesizeMouseAtCenter(element, {}, this.dateTimePopupFrame.contentWindow);
+  },
+  wheel(element, offsetX, offsetY, event) {
+    EventUtils.synthesizeWheel(element, offsetX, offsetY, event, this.dateTimePopupFrame.contentWindow);
+  },
+  waitForScrollStop(selector) {
+    return BrowserTestUtils.waitForEvent(this.getElement(selector), "ScrollStop");
+  },
+  tearDown() {
+    this.closePicker();
+    this.closeTab();
+  }
+};