mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-24 08:07:30 +09:00
moebius#92: HTML - input - datetime
+ native in moebius: Bug 1317600: https://bugzilla.mozilla.org/show_bug.cgi?id=1317600 A note - not implemented: Bug 1282768: https://bugzilla.mozilla.org/show_bug.cgi?id=1282768 *.css: filter: url("chrome://global/skin/filters.svg#fill");, fill: Bug 1283385: https://bugzilla.mozilla.org/show_bug.cgi?id=1283385 Bug 1323109: https://bugzilla.mozilla.org/show_bug.cgi?id=1323109 Bug 1314544: https://bugzilla.mozilla.org/show_bug.cgi?id=1314544 Bug 1286182: https://bugzilla.mozilla.org/show_bug.cgi?id=1286182 Bug 1325922: https://bugzilla.mozilla.org/show_bug.cgi?id=1325922 A note - not implemented: Bug 1282768: https://bugzilla.mozilla.org/show_bug.cgi?id=1282768 *.css: filter: url("chrome://global/skin/filters.svg#fill");, fill: Bug 1320225: https://bugzilla.mozilla.org/show_bug.cgi?id=1320225 Bug 1341190: https://bugzilla.mozilla.org/show_bug.cgi?id=1341190
This commit is contained in:
parent
a807f7e6c0
commit
cac5c5adc7
34 changed files with 1267 additions and 248 deletions
|
|
@ -26,6 +26,7 @@ skip-if = !e10s
|
|||
[browser_contentTitle.js]
|
||||
[browser_crash_previous_frameloader.js]
|
||||
run-if = e10s && crashreporter
|
||||
[browser_datetime_datepicker.js]
|
||||
[browser_default_image_filename.js]
|
||||
[browser_f7_caret_browsing.js]
|
||||
[browser_findbar.js]
|
||||
|
|
|
|||
222
toolkit/content/tests/browser/browser_datetime_datepicker.js
Normal file
222
toolkit/content/tests/browser/browser_datetime_datepicker.js
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const MONTH_YEAR = ".month-year",
|
||||
DAYS_VIEW = ".days-view",
|
||||
BTN_PREV_MONTH = ".prev",
|
||||
BTN_NEXT_MONTH = ".next";
|
||||
const DATE_FORMAT = new Intl.DateTimeFormat("en-US", { year: "numeric", month: "long", timeZone: "UTC" }).format;
|
||||
|
||||
// Create a list of abbreviations for calendar class names
|
||||
const W = "weekend",
|
||||
O = "outside",
|
||||
S = "selection",
|
||||
R = "out-of-range",
|
||||
T = "today",
|
||||
P = "off-step";
|
||||
|
||||
// Calendar classlist for 2016-12. Used to verify the classNames are correct.
|
||||
const calendarClasslist_201612 = [
|
||||
[W, O], [O], [O], [O], [], [], [W],
|
||||
[W], [], [], [], [], [], [W],
|
||||
[W], [], [], [], [S], [], [W],
|
||||
[W], [], [], [], [], [], [W],
|
||||
[W], [], [], [], [], [], [W],
|
||||
[W, O], [O], [O], [O], [O], [O], [W, O],
|
||||
];
|
||||
|
||||
function getCalendarText() {
|
||||
return helper.getChildren(DAYS_VIEW).map(child => child.textContent);
|
||||
}
|
||||
|
||||
function getCalendarClassList() {
|
||||
return helper.getChildren(DAYS_VIEW).map(child => Array.from(child.classList));
|
||||
}
|
||||
|
||||
function mergeArrays(a, b) {
|
||||
return a.map((classlist, index) => classlist.concat(b[index]));
|
||||
}
|
||||
|
||||
let helper = new DateTimeTestHelper();
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
helper.cleanup();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that date picker opens to today's date when input field is blank
|
||||
*/
|
||||
add_task(async function test_datepicker_today() {
|
||||
const date = new Date();
|
||||
|
||||
await helper.openPicker("data:text/html, <input type='date'>");
|
||||
|
||||
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(date));
|
||||
|
||||
await helper.tearDown();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that date picker opens to the correct month, with calendar days
|
||||
* displayed correctly, given a date value is set.
|
||||
*/
|
||||
add_task(async function test_datepicker_open() {
|
||||
const inputValue = "2016-12-15";
|
||||
|
||||
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
|
||||
|
||||
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(inputValue)));
|
||||
Assert.deepEqual(
|
||||
getCalendarText(),
|
||||
[
|
||||
"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",
|
||||
);
|
||||
Assert.deepEqual(
|
||||
getCalendarClassList(),
|
||||
calendarClasslist_201612,
|
||||
"2016-12 classNames"
|
||||
);
|
||||
|
||||
await helper.tearDown();
|
||||
});
|
||||
|
||||
/**
|
||||
* When the prev month button is clicked, calendar should display the dates for
|
||||
* the previous month.
|
||||
*/
|
||||
add_task(async function test_datepicker_prev_month_btn() {
|
||||
const inputValue = "2016-12-15";
|
||||
const prevMonth = "2016-11-01";
|
||||
|
||||
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
|
||||
helper.click(helper.getElement(BTN_PREV_MONTH));
|
||||
|
||||
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(prevMonth)));
|
||||
Assert.deepEqual(
|
||||
getCalendarText(),
|
||||
[
|
||||
"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",
|
||||
);
|
||||
|
||||
await helper.tearDown();
|
||||
});
|
||||
|
||||
/**
|
||||
* When the next month button is clicked, calendar should display the dates for
|
||||
* the next month.
|
||||
*/
|
||||
add_task(async function test_datepicker_next_month_btn() {
|
||||
const inputValue = "2016-12-15";
|
||||
const nextMonth = "2017-01-01";
|
||||
|
||||
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
|
||||
helper.click(helper.getElement(BTN_NEXT_MONTH));
|
||||
|
||||
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(nextMonth)));
|
||||
Assert.deepEqual(
|
||||
getCalendarText(),
|
||||
[
|
||||
"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",
|
||||
);
|
||||
|
||||
await helper.tearDown();
|
||||
});
|
||||
|
||||
/**
|
||||
* When a date on the calendar is clicked, date picker should close and set
|
||||
* value to the input box.
|
||||
*/
|
||||
add_task(async function test_datepicker_clicked() {
|
||||
const inputValue = "2016-12-15";
|
||||
const firstDayOnCalendar = "2016-11-27";
|
||||
|
||||
await helper.openPicker(`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]);
|
||||
await ContentTask.spawn(helper.tab.linkedBrowser, {}, async function() {
|
||||
let inputEl = content.document.querySelector("input");
|
||||
await ContentTaskUtils.waitForEvent(inputEl, "input");
|
||||
});
|
||||
|
||||
Assert.equal(content.document.querySelector("input").value, firstDayOnCalendar);
|
||||
|
||||
await helper.tearDown();
|
||||
});
|
||||
|
||||
/**
|
||||
* When min and max attributes are set, calendar should show some dates as
|
||||
* out-of-range.
|
||||
*/
|
||||
add_task(async function test_datepicker_min_max() {
|
||||
const inputValue = "2016-12-15";
|
||||
const inputMin = "2016-12-05";
|
||||
const inputMax = "2016-12-25";
|
||||
|
||||
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}" min="${inputMin}" max="${inputMax}">`);
|
||||
|
||||
Assert.deepEqual(
|
||||
getCalendarClassList(),
|
||||
mergeArrays(calendarClasslist_201612, [
|
||||
// R denotes out-of-range
|
||||
[R], [R], [R], [R], [R], [R], [R],
|
||||
[R], [], [], [], [], [], [],
|
||||
[], [], [], [], [], [], [],
|
||||
[], [], [], [], [], [], [],
|
||||
[], [R], [R], [R], [R], [R], [R],
|
||||
[R], [R], [R], [R], [R], [R], [R],
|
||||
]),
|
||||
"2016-12 with min & max",
|
||||
);
|
||||
|
||||
await helper.tearDown();
|
||||
});
|
||||
|
||||
/**
|
||||
* When step attribute is set, calendar should show some dates as off-step.
|
||||
*/
|
||||
add_task(async function test_datepicker_step() {
|
||||
const inputValue = "2016-12-15";
|
||||
const inputStep = "5";
|
||||
|
||||
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}" step="${inputStep}">`);
|
||||
|
||||
Assert.deepEqual(
|
||||
getCalendarClassList(),
|
||||
mergeArrays(calendarClasslist_201612, [
|
||||
// P denotes off-step
|
||||
[P], [P], [P], [], [P], [P], [P],
|
||||
[P], [], [P], [P], [P], [P], [],
|
||||
[P], [P], [P], [P], [], [P], [P],
|
||||
[P], [P], [], [P], [P], [P], [P],
|
||||
[], [P], [P], [P], [P], [], [P],
|
||||
[P], [P], [P], [], [P], [P], [P],
|
||||
]),
|
||||
"2016-12 with step",
|
||||
);
|
||||
|
||||
await helper.tearDown();
|
||||
});
|
||||
|
|
@ -31,3 +31,88 @@ function pushPrefs(...aPrefs) {
|
|||
SpecialPowers.pushPrefEnv({"set": aPrefs}, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for testing datetime input picker widget
|
||||
*/
|
||||
class DateTimeTestHelper {
|
||||
constructor() {
|
||||
this.panel = document.getElementById("DateTimePickerPanel");
|
||||
this.panel.setAttribute("animate", false);
|
||||
this.tab = null;
|
||||
this.frame = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new tab with the URL of the test page, and make sure the picker is
|
||||
* ready for testing.
|
||||
*
|
||||
* @param {String} pageUrl
|
||||
*/
|
||||
async openPicker(pageUrl) {
|
||||
this.tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("input", {}, gBrowser.selectedBrowser);
|
||||
// If dateTimePopupFrame doesn't exist yet, wait for the binding to be attached
|
||||
if (!this.panel.dateTimePopupFrame) {
|
||||
await BrowserTestUtils.waitForEvent(this.panel, "DateTimePickerBindingReady")
|
||||
}
|
||||
this.frame = this.panel.dateTimePopupFrame;
|
||||
await BrowserTestUtils.waitForEvent(this.frame, "load", true);
|
||||
// Wait for picker elements to be ready and open panel transition to end
|
||||
await BrowserTestUtils.waitForEvent(this.frame.contentDocument, "PickerReady");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an element on the picker.
|
||||
*
|
||||
* @param {String} selector
|
||||
* @return {DOMElement}
|
||||
*/
|
||||
getElement(selector) {
|
||||
return this.frame.contentDocument.querySelector(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the children of an element on the picker.
|
||||
*
|
||||
* @param {String} selector
|
||||
* @return {Array<DOMElement>}
|
||||
*/
|
||||
getChildren(selector) {
|
||||
return Array.from(this.getElement(selector).children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on an element
|
||||
*
|
||||
* @param {DOMElement} element
|
||||
*/
|
||||
click(element) {
|
||||
EventUtils.synthesizeMouseAtCenter(element, {}, this.frame.contentWindow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the panel and the tab
|
||||
*/
|
||||
async tearDown() {
|
||||
if (!this.panel.hidden) {
|
||||
let pickerClosePromise = new Promise(resolve => {
|
||||
this.panel.addEventListener("popuphidden", resolve, {once: true});
|
||||
});
|
||||
this.panel.closePicker();
|
||||
await pickerClosePromise;
|
||||
}
|
||||
await BrowserTestUtils.removeTab(this.tab);
|
||||
this.tab = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up after tests. Remove the frame to prevent leak.
|
||||
*/
|
||||
cleanup() {
|
||||
this.frame.remove();
|
||||
this.frame = null;
|
||||
this.panel.removeAttribute("animate");
|
||||
this.panel = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue