@nateradebaugh/react-datetime
Version:
A lightweight but complete datetime picker React.js component
1,478 lines (1,277 loc) • 51.5 kB
JavaScript
/* global done */
import React from "react";
import utils from "./testUtils";
import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import { advanceTo as mockDateTo } from "jest-date-mock";
import format from "date-fns/format";
import parse from "date-fns/parse";
import isBefore from "date-fns/is_before";
import getDate from "date-fns/get_date";
import getMonth from "date-fns/get_month";
import getYear from "date-fns/get_year";
import nl from "date-fns/locale/nl";
import sv from "date-fns/locale/sv";
Enzyme.configure({ adapter: new Adapter() });
// Mock date to get rid of time as a factor to make tests deterministic
mockDateTo("September 2, 2018 03:24:00");
describe("DateTime", () => {
it("create component", () => {
const component = utils.createDatetime({});
expect(component).toBeDefined();
expect(component.find(".rdt > .form-control").length).toEqual(1);
expect(component.find(".rdt > .rdtPicker").length).toEqual(1);
});
it("viewMode=days: renders days, week days, month, year", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
viewMode: "days",
defaultValue: date
});
utils.openDatepicker(component);
// Month and year
expect(component.find(".rdtSwitch").text()).toEqual("January 2000");
// Week days
const expectedWeekDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
const actualWeekdays = component
.find(".rdtDays .dow")
.map(element => element.text());
expect(actualWeekdays).toEqual(expectedWeekDays);
// Dates
// "Old" dates belonging to prev month
const oldDatesIndexes = [0, 1, 2, 3, 4, 5];
oldDatesIndexes.forEach(index => {
expect(utils.getNthDay(component, index).hasClass("rdtOld")).toBeTruthy();
});
// Dates belonging to current month
for (let i = 6; i < 37; i++) {
expect(utils.getNthDay(component, i).hasClass("rdtDay")).toBeTruthy();
expect(utils.getNthDay(component, i).hasClass("rdtOld")).toBeFalsy();
expect(utils.getNthDay(component, i).hasClass("rdtNew")).toBeFalsy();
}
// "New" dates belonging to next month
const nextDatesIndexes = [37, 38, 39, 40, 41];
nextDatesIndexes.forEach(index => {
expect(utils.getNthDay(component, index).hasClass("rdtNew")).toBeTruthy();
});
});
it("switch from day view to time view and back", () => {
const component = utils.createDatetime({});
expect(utils.isDayView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtTimeToggle"));
expect(utils.isTimeView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtSwitch"));
expect(utils.isDayView(component)).toBeTruthy();
});
it("persistent valid months going monthView->yearView->monthView", () => {
const dateBefore = "2018-06-01";
const component = utils.createDatetime({
viewMode: "months",
isValidDate: current => isBefore(current, parse(dateBefore))
});
expect(utils.isMonthView(component)).toBeTruthy();
expect(utils.getNthMonth(component, 4).hasClass("rdtDisabled")).toEqual(
false
);
expect(utils.getNthMonth(component, 5).hasClass("rdtDisabled")).toEqual(
true
);
// Go to year view
utils.clickOnElement(component.find(".rdtSwitch"));
expect(utils.isYearView(component)).toBeTruthy();
expect(utils.getNthYear(component, 0).hasClass("rdtDisabled")).toEqual(
false
);
expect(utils.getNthYear(component, 10).hasClass("rdtDisabled")).toEqual(
true
);
utils.clickNthYear(component, 9);
expect(utils.getNthMonth(component, 4).hasClass("rdtDisabled")).toEqual(
false
);
expect(utils.getNthMonth(component, 5).hasClass("rdtDisabled")).toEqual(
true
);
});
it("step through views", () => {
const component = utils.createDatetime({ viewMode: "time" });
expect(utils.isTimeView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtSwitch"));
expect(utils.isDayView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtSwitch"));
expect(utils.isMonthView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtSwitch"));
expect(utils.isYearView(component)).toBeTruthy();
});
it("toggles calendar when open prop changes", () => {
const component = utils.createDatetime({ open: false });
expect(utils.isOpen(component)).toBeFalsy();
expect(component.find(".rdtOpen").length).toEqual(0);
component.setProps({ open: true });
expect(utils.isOpen(component)).toBeTruthy();
expect(component.find(".rdtOpen").length).toEqual(1);
component.setProps({ open: false });
expect(utils.isOpen(component)).toBeFalsy();
expect(component.find(".rdtOpen").length).toEqual(0);
});
it("selectYear", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
viewMode: "years",
defaultValue: date
});
expect(utils.isYearView(component)).toBeTruthy();
expect(component.find(".rdtSwitch").text()).toEqual("2000-2009");
// Click first year (1999)
utils.clickOnElement(component.find(".rdtYear").at(0));
expect(utils.isMonthView(component)).toBeTruthy();
expect(component.find(".rdtSwitch").text()).toEqual("1999");
});
it("increase decade", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
viewMode: "years",
defaultValue: date
});
expect(component.find(".rdtSwitch").text()).toEqual("2000-2009");
utils.clickOnElement(component.find(".rdtNext span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("2010-2019");
utils.clickOnElement(component.find(".rdtNext span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("2020-2029");
});
it("decrease decade", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
viewMode: "years",
defaultValue: date
});
expect(component.find(".rdtSwitch").text()).toEqual("2000-2009");
utils.clickOnElement(component.find(".rdtPrev span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("1990-1999");
utils.clickOnElement(component.find(".rdtPrev span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("1980-1989");
});
it("select month", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
viewMode: "months",
defaultValue: date
});
expect(utils.isMonthView(component)).toBeTruthy();
expect(component.find(".rdtSwitch").text()).toEqual("2000");
// Click any month to enter day view
utils.clickNthMonth(component, 1);
expect(utils.isDayView(component)).toBeTruthy();
expect(
component
.find(".rdtSwitch")
.getDOMNode()
.getAttribute("data-value")
).toEqual("1");
});
it("increase year", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
viewMode: "months",
defaultValue: date
});
expect(component.find(".rdtSwitch").text()).toEqual("2000");
utils.clickOnElement(component.find(".rdtNext span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("2001");
utils.clickOnElement(component.find(".rdtNext span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("2002");
});
it("decrease year", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
viewMode: "months",
defaultValue: date
});
expect(component.find(".rdtSwitch").text()).toEqual("2000");
utils.clickOnElement(component.find(".rdtPrev span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("1999");
utils.clickOnElement(component.find(".rdtPrev span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("1998");
});
it("increase month", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({ defaultValue: date });
expect(component.find(".rdtSwitch").text()).toEqual("January 2000");
expect(
component
.find(".rdtSwitch")
.getDOMNode()
.getAttribute("data-value")
).toEqual("0");
utils.clickOnElement(component.find(".rdtNext span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("February 2000");
expect(
component
.find(".rdtSwitch")
.getDOMNode()
.getAttribute("data-value")
).toEqual("1");
utils.clickOnElement(component.find(".rdtNext span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("March 2000");
expect(
component
.find(".rdtSwitch")
.getDOMNode()
.getAttribute("data-value")
).toEqual("2");
});
it("decrease month", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({ defaultValue: date });
expect(component.find(".rdtSwitch").text()).toEqual("January 2000");
expect(
component
.find(".rdtSwitch")
.getDOMNode()
.getAttribute("data-value")
).toEqual("0");
utils.clickOnElement(component.find(".rdtPrev span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("December 1999");
expect(
component
.find(".rdtSwitch")
.getDOMNode()
.getAttribute("data-value")
).toEqual("11");
utils.clickOnElement(component.find(".rdtPrev span").at(0));
expect(component.find(".rdtSwitch").text()).toEqual("November 1999");
expect(
component
.find(".rdtSwitch")
.getDOMNode()
.getAttribute("data-value")
).toEqual("10");
});
it("open picker", () => {
const component = utils.createDatetime();
expect(utils.isOpen(component)).toBeFalsy();
utils.openDatepicker(component);
expect(utils.isOpen(component)).toBeTruthy();
});
it("opens picker when clicking on input", () => {
const component = utils.createDatetime();
expect(utils.isOpen(component)).toBeFalsy();
component.find(".form-control").simulate("click");
expect(utils.isOpen(component)).toBeTruthy();
});
it("sets CSS class on selected item (day)", () => {
const component = utils.createDatetime({ viewMode: "days" });
utils.openDatepicker(component);
utils.clickNthDay(component, 13);
expect(utils.getNthDay(component, 13).hasClass("rdtActive")).toBeTruthy();
});
it("sets CSS class on selected item (month)", () => {
const component = utils.createDatetime({
viewMode: "months",
dateFormat: "YYYY-MM"
});
utils.openDatepicker(component);
utils.clickNthMonth(component, 4);
expect(utils.getNthMonth(component, 4).hasClass("rdtActive")).toBeTruthy();
});
it("sets CSS class on selected item (year)", () => {
const component = utils.createDatetime({
viewMode: "years",
dateFormat: "YYYY"
});
utils.openDatepicker(component);
utils.clickNthYear(component, 3);
expect(utils.getNthYear(component, 3).hasClass("rdtActive")).toBeTruthy();
});
it("sets CSS class on days outside of month", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const prevMonthDaysIndexes = [0, 1, 2, 3, 4, 5];
const nextMonthDaysIndexes = [37, 38, 39, 40, 41];
const component = utils.createDatetime({
viewMode: "days",
defaultValue: date
});
utils.openDatepicker(component);
prevMonthDaysIndexes.forEach(index => {
expect(utils.getNthDay(component, index).hasClass("rdtOld")).toBeTruthy();
});
nextMonthDaysIndexes.forEach(index => {
expect(utils.getNthDay(component, index).hasClass("rdtNew")).toBeTruthy();
});
});
it("selected day persists (in UI) when navigating to prev month", () => {
const date = new Date(2000, 0, 3, 2, 2, 2, 2);
const component = utils.createDatetime({
viewMode: "days",
defaultValue: date
});
utils.openDatepicker(component);
expect(utils.getNthDay(component, 8).hasClass("rdtActive")).toBeTruthy();
// Go to previous month
utils.clickOnElement(component.find(".rdtDays .rdtPrev span"));
expect(utils.getNthDay(component, 36).hasClass("rdtActive")).toBeTruthy();
});
it("sets CSS class on today date", () => {
const specificDate = new Date();
const component = utils.createDatetime({ defaultValue: specificDate });
utils.openDatepicker(component);
expect(component.find(".rdtDay.rdtToday").text()).toEqual(
format(specificDate, "D")
);
});
// Proof of bug [FIXED]
it("should show correct selected month when traversing view modes", () => {
const date = new Date(2000, 4, 3, 2, 2, 2, 2);
const component = utils.createDatetime({
viewMode: "days",
defaultValue: date
});
utils.openDatepicker(component);
// Go to month view
utils.clickOnElement(component.find(".rdtSwitch"));
// Here the selected month is _May_, which is correct
expect(
component
.find(".rdtMonth")
.find(".rdtActive")
.text()
).toEqual("May");
// Go to year view
utils.clickOnElement(component.find(".rdtSwitch"));
// Click the selected year (2000)
utils.clickNthYear(component, 1);
// The selected month is _May_ again
expect(
component
.find(".rdtMonth")
.find(".rdtActive")
.text()
).toEqual("May");
});
describe("with custom props", () => {
it("input=false", () => {
const component = utils.createDatetime({ input: false });
expect(component.find(".rdt > .form-control").length).toEqual(0);
expect(component.find(".rdt > .rdtPicker").length).toEqual(1);
});
it("dateFormat", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
value: date,
dateFormat: "M&D"
});
expect(utils.getInputValue(component)).toEqual(
format(date, "M&D h:mm A")
);
});
it("dateFormat=false", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
value: date,
dateFormat: false
});
expect(utils.getInputValue(component)).toEqual(format(date, "h:mm A"));
// Make sure time view is active
expect(utils.isTimeView(component)).toBeTruthy();
// Make sure the date toggle is not rendered
expect(component.find("thead").length).toEqual(0);
});
it("timeFormat", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const timeFormat = "HH:mm:ss:SSS";
const component = utils.createDatetime({
value: date,
timeFormat: timeFormat
});
expect(utils.getInputValue(component)).toEqual(
format(date, "MM/DD/YYYY " + timeFormat)
);
});
it("timeFormat=false", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
value: date,
timeFormat: false
});
expect(utils.getInputValue(component)).toEqual(
format(date, "MM/DD/YYYY")
);
// Make sure day view is active
expect(utils.isDayView(component)).toBeTruthy();
// Make sure the time toggle is not rendered
expect(component.find(".timeToggle").length).toEqual(0);
});
it("timeFormat with lowercase 'am'", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const format = "HH:mm:ss:SSS a";
const component = utils.createDatetime({
value: date,
timeFormat: format
});
expect(utils.getInputValue(component)).toEqual(
expect.stringMatching(".*am$")
);
});
it("timeFormat with uppercase 'AM'", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const format = "HH:mm:ss:SSS A";
const component = utils.createDatetime({
value: date,
timeFormat: format
});
expect(utils.getInputValue(component)).toEqual(
expect.stringMatching(".*AM$")
);
});
it("viewMode=years", () => {
const component = utils.createDatetime({ viewMode: "years" });
expect(utils.isYearView(component)).toBeTruthy();
});
it("viewMode=months", () => {
const component = utils.createDatetime({ viewMode: "months" });
expect(utils.isMonthView(component)).toBeTruthy();
});
it("viewMode=time", () => {
const component = utils.createDatetime({ viewMode: "time" });
expect(utils.isTimeView(component)).toBeTruthy();
});
it("className -> type string", () => {
const component = utils.createDatetimeShallow({
className: "custom-class"
});
expect(component.find(".custom-class").length).toEqual(1);
});
it("className -> type string array", () => {
const component = utils.createDatetime({
className: ["custom-class1", "custom-class2"]
});
expect(component.find(".custom-class1").length).toEqual(1);
expect(component.find(".custom-class2").length).toEqual(1);
});
it("inputProps", () => {
const component = utils.createDatetime({
inputProps: {
className: "custom-class",
type: "email",
placeholder: "custom-placeholder"
}
});
expect(component.find("input.custom-class").length).toEqual(1);
expect(component.find("input").getDOMNode().type).toEqual("email");
expect(component.find("input").getDOMNode().placeholder).toEqual(
"custom-placeholder"
);
});
it("renderInput", () => {
const renderInput = (props, openCalendar) => {
return (
<div>
<input {...props} />
<button className="custom-open" onClick={openCalendar}>
open calendar
</button>
</div>
);
};
const component = utils.createDatetime({ renderInput });
expect(component.find("button.custom-open").length).toEqual(1);
expect(utils.isOpen(component)).toBeFalsy();
utils.clickOnElement(component.find("button.custom-open"));
expect(utils.isOpen(component)).toBeTruthy();
});
it("renderDay", () => {
let props = {};
let currentDate = "";
let selectedDate = "";
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const renderDayFn = (fnProps, current, selected) => {
props = fnProps;
currentDate = current;
selectedDate = selected;
return <td {...fnProps}>custom-content</td>;
};
const component = utils.createDatetime({
value: date,
renderDay: renderDayFn
});
// Last day should be 5th of february
expect(getDate(currentDate)).toEqual(5);
expect(getMonth(currentDate)).toEqual(1);
// The date must be the same
expect(selectedDate).toEqual(date);
// There should be a onClick function in the props
expect(typeof props.onClick).toEqual("function");
// The cell text should match
expect(
component
.find(".rdtDay")
.at(0)
.text()
).toEqual("custom-content");
});
it("renderMonth", () => {
let props = {};
let month = "";
let year = "";
let selectedDate = "";
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const renderMonthFn = (fnProps, fnMonth, fnYear, selected) => {
props = fnProps;
month = fnMonth;
year = fnYear;
selectedDate = selected;
return <td {...fnProps}>custom-content</td>;
};
const component = utils.createDatetime({
value: date,
viewMode: "months",
renderMonth: renderMonthFn
});
expect(month).toEqual(11);
expect(year).toEqual(2000);
// The date must be the same
expect(selectedDate).toEqual(date);
// There should be a onClick function in the props
expect(typeof props.onClick).toEqual("function");
// The cell text should match
expect(
component
.find(".rdtMonth")
.at(0)
.text()
).toEqual("custom-content");
});
it("renderYear", () => {
let props = {};
let year = "";
let selectedDate = "";
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const renderYearFn = (fnProps, fnYear, selected) => {
props = fnProps;
year = fnYear;
selectedDate = selected;
return <td {...fnProps}>custom-content</td>;
};
const component = utils.createDatetime({
value: date,
viewMode: "years",
renderYear: renderYearFn
});
expect(year).toEqual(2010);
// The date must be the same
expect(selectedDate).toEqual(date);
// There should be a onClick function in the props
expect(typeof props.onClick).toEqual("function");
// The cell text should match
expect(
component
.find(".rdtYear")
.at(0)
.text()
).toEqual("custom-content");
});
it("closeOnTab=true", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({ value: date });
expect(utils.isOpen(component)).toBeFalsy();
utils.openDatepicker(component);
expect(utils.isOpen(component)).toBeTruthy();
component
.find(".form-control")
.simulate("keyDown", { key: "Tab", keyCode: 9, which: 9 });
expect(utils.isOpen(component)).toBeFalsy();
});
it("closeOnTab=false", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
component = utils.createDatetime({ value: date, closeOnTab: false });
expect(utils.isOpen(component)).toBeFalsy();
utils.openDatepicker(component);
expect(utils.isOpen(component)).toBeTruthy();
component
.find(".form-control")
.simulate("keyDown", { key: "Tab", keyCode: 9, which: 9 });
expect(utils.isOpen(component)).toBeTruthy();
});
it("disableOnClickOutside=true", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
value: date,
disableOnClickOutside: true
});
expect(utils.isOpen(component)).toBeFalsy();
utils.openDatepicker(component);
expect(utils.isOpen(component)).toBeTruthy();
document.dispatchEvent(new Event("mousedown"));
component.update();
expect(utils.isOpen(component)).toBeTruthy();
});
it("disableOnClickOutside=false", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
component = utils.createDatetime({
value: date,
disableOnClickOutside: false
});
expect(utils.isOpen(component)).toBeFalsy();
utils.openDatepicker(component);
expect(utils.isOpen(component)).toBeTruthy();
document.dispatchEvent(new Event("mousedown"));
component.update();
expect(utils.isOpen(component)).toBeFalsy();
});
it("increase time", () => {
let i = 0;
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
timeFormat: "HH:mm:ss:SSS",
viewMode: "time",
defaultValue: date,
onChange: selected => {
// TODO: Trigger onChange when increasing time
i++;
if (i > 2) {
expect(true).toEqual(false); // Proof that this is not called
expect(selected.hour()).toEqual(3);
expect(selected.minute()).toEqual(3);
expect(selected.second()).toEqual(3);
done();
}
}
});
// Check hour
expect(utils.getHours(component)).toEqual("2");
utils.increaseHour(component);
expect(utils.getHours(component)).toEqual("3");
// Check minute
expect(utils.getMinutes(component)).toEqual("02");
utils.increaseMinute(component);
expect(utils.getMinutes(component)).toEqual("03");
// Check second
expect(utils.getSeconds(component)).toEqual("02");
utils.increaseSecond(component);
expect(utils.getSeconds(component)).toEqual("03");
});
it("decrease time", () => {
let i = 0;
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
component = utils.createDatetime({
timeFormat: "HH:mm:ss:SSS",
viewMode: "time",
defaultValue: date,
onChange: selected => {
// TODO: Trigger onChange when increasing time
i++;
if (i > 2) {
expect(true).toEqual(false); // Proof that this is not called
expect(selected.hour()).toEqual(1);
expect(selected.minute()).toEqual(1);
expect(selected.second()).toEqual(1);
done();
}
}
});
// Check hour
expect(utils.getHours(component)).toEqual("2");
utils.decreaseHour(component);
expect(utils.getHours(component)).toEqual("1");
// Check minute
expect(utils.getMinutes(component)).toEqual("02");
utils.decreaseMinute(component);
expect(utils.getMinutes(component)).toEqual("01");
// Check second
expect(utils.getSeconds(component)).toEqual("02");
utils.decreaseSecond(component);
expect(utils.getSeconds(component)).toEqual("01");
});
it("long increase time", done => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
component = utils.createDatetime({
timeFormat: "HH:mm:ss:SSS",
viewMode: "time",
defaultValue: date
});
utils.increaseHour(component);
setTimeout(() => {
expect(utils.getHours(component)).not.toEqual("2");
expect(utils.getHours(component)).not.toEqual("3");
done();
}, 920);
});
it("long decrease time", done => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
component = utils.createDatetime({
timeFormat: "HH:mm:ss:SSS",
viewMode: "time",
defaultValue: date
});
utils.decreaseHour(component);
setTimeout(() => {
expect(utils.getHours(component)).not.toEqual("1");
expect(utils.getHours(component)).not.toEqual("0");
done();
}, 920);
});
it("timeConstraints -> increase time", () => {
let i = 0;
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
timeFormat: "HH:mm:ss:SSS",
viewMode: "time",
defaultValue: date,
timeConstraints: {
hours: { max: 6, step: 8 },
minutes: { step: 15 }
},
onChange: selected => {
// TODO
i++;
if (i > 2) {
expect(selected.minute()).toEqual(17);
expect(selected.second()).toEqual(3);
done();
}
}
});
utils.increaseHour(component);
expect(utils.getHours(component)).toEqual("3");
utils.increaseMinute(component);
expect(utils.getMinutes(component)).toEqual("17");
utils.increaseSecond(component);
expect(utils.getSeconds(component)).toEqual("03");
});
it("timeConstraints -> decrease time", () => {
let i = 0;
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
component = utils.createDatetime({
timeFormat: "HH:mm:ss:SSS",
viewMode: "time",
defaultValue: date,
timeConstraints: { minutes: { step: 15 } },
onChange: selected => {
// TODO
i++;
if (i > 2) {
expect(selected.minute()).toEqual(17);
expect(selected.second()).toEqual(3);
done();
}
}
});
utils.decreaseMinute(component);
expect(utils.getMinutes(component)).toEqual("47");
});
it("isValidDate -> disable months", () => {
const dateBefore = parse("2018-06-01"),
component = utils.createDatetime({
viewMode: "months",
isValidDate: current => isBefore(current, dateBefore)
});
expect(utils.getNthMonth(component, 0).hasClass("rdtDisabled")).toEqual(
false
);
expect(utils.getNthMonth(component, 4).hasClass("rdtDisabled")).toEqual(
false
);
expect(utils.getNthMonth(component, 5).hasClass("rdtDisabled")).toEqual(
true
);
expect(utils.getNthMonth(component, 11).hasClass("rdtDisabled")).toEqual(
true
);
});
it("isValidDate -> disable years", () => {
const component = utils.createDatetime({
viewMode: "years",
isValidDate: current => isBefore(current, parse("2016-01-01"))
});
expect(utils.getNthYear(component, 0).hasClass("rdtDisabled")).toEqual(
false
);
expect(utils.getNthYear(component, 6).hasClass("rdtDisabled")).toEqual(
false
);
expect(utils.getNthYear(component, 7).hasClass("rdtDisabled")).toEqual(
true
);
});
it("locale", () => {
const component = utils.createDatetime({ locale: nl });
const expectedWeekDays = ["zo", "ma", "di", "wo", "do", "vr", "za"];
const actualWeekDays = component
.find(".rdtDays .dow")
.map(element => element.text().toLowerCase());
expect(actualWeekDays).toEqual(expectedWeekDays);
});
it("locale with viewMode=months", () => {
const component = utils.createDatetime({
locale: nl,
viewMode: "months"
}),
expectedMonths = ["mar", "mei"],
actualMonths = [
utils.getNthMonth(component, 2).text(),
utils.getNthMonth(component, 4).text()
];
expect(actualMonths).toEqual(expectedMonths);
});
it("closeOnSelect=false", done => {
const component = utils.createDatetime({ closeOnSelect: false });
// A unknown race condition is causing this test to fail without this time out,
// and when the test fails it says:
// 'Timeout - Async callback was not invoked within timeout'
// Ideally it would say something else but at least we know the tests are passing now
setTimeout(() => {
expect(utils.isOpen(component)).toBeFalsy();
utils.openDatepicker(component);
expect(utils.isOpen(component)).toBeTruthy();
utils.clickNthDay(component, 2);
expect(utils.isOpen(component)).toBeTruthy();
done();
}, 0);
});
it("closeOnSelect=true", done => {
const component = utils.createDatetime({ closeOnSelect: true });
// A unknown race condition is causing this test to fail without this time out,
// and when the test fails it says:
// 'Timeout - Async callback was not invoked within timeout'
// Ideally it would say something else but at least we know the tests are passing now
setTimeout(() => {
expect(utils.isOpen(component)).toBeFalsy();
utils.openDatepicker(component);
expect(utils.isOpen(component)).toBeTruthy();
utils.clickNthDay(component, 2);
expect(utils.isOpen(component)).toBeFalsy();
done();
}, 0);
});
describe("defaultValue of type", () => {
it("date", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
strDate = format(date, "MM/DD/YYYY") + " " + format(date, "h:mm A"),
component = utils.createDatetime({ defaultValue: date });
expect(utils.getInputValue(component)).toEqual(strDate);
});
it("Date", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
strDate = format(date, "MM/DD/YYYY") + " " + format(date, "h:mm A"),
component = utils.createDatetime({ defaultValue: date });
expect(utils.getInputValue(component)).toEqual(strDate);
});
it("string", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
strDate = format(date, "MM/DD/YYYY") + " " + format(date, "h:mm A"),
component = utils.createDatetime({ defaultValue: strDate });
expect(utils.getInputValue(component)).toEqual(strDate);
});
});
describe("timeFormat with", () => {
it("milliseconds", () => {
const component = utils.createDatetime({
viewMode: "time",
timeFormat: "HH:mm:ss:SSS"
});
expect(component.find(".rdtCounter").length).toEqual(4);
// TODO: Test that you can input a value in milli seconds input
});
it("seconds", () => {
const component = utils.createDatetime({
viewMode: "time",
timeFormat: "HH:mm:ss"
});
expect(component.find(".rdtCounter").length).toEqual(3);
});
it("minutes", () => {
const component = utils.createDatetime({
viewMode: "time",
timeFormat: "HH:mm"
});
expect(component.find(".rdtCounter").length).toEqual(2);
});
it("hours", () => {
const component = utils.createDatetime({
viewMode: "time",
timeFormat: "HH"
});
expect(component.find(".rdtCounter").length).toEqual(1);
});
});
describe("being updated and should trigger update", () => {
it("dateFormat -> value should change format", done => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
component = utils.createDatetime({
dateFormat: "YYYY-MM-DD",
timeFormat: false,
defaultValue: date
});
const valueBefore = utils.getInputValue(component);
// A unknown race condition is causing this test to fail without this time out,
// and when the test fails it says:
// 'Timeout - Async callback was not invoked within timeout'
// Ideally it would say something else but at least we know the tests are passing now
setTimeout(() => {
component.setProps({ dateFormat: "DD.MM.YYYY" });
const valueAfter = utils.getInputValue(component);
expect(valueBefore).not.toEqual(valueAfter);
done();
}, 0);
});
it("UTC -> value should change format (true->false)", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
component = utils.createDatetime({ value: date, utc: true });
const valueBefore = utils.getInputValue(component);
component.setProps({ utc: false }, () => {
const valueAfter = utils.getInputValue(component);
expect(valueBefore).not.toEqual(valueAfter);
});
});
it("UTC -> value should change format (false->true)", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
component = utils.createDatetime({ value: date, utc: false });
const valueBefore = utils.getInputValue(component);
component.setProps({ utc: true }, () => {
const valueAfter = utils.getInputValue(component);
expect(valueBefore).not.toEqual(valueAfter);
});
});
it("locale -> picker should change language (viewMode=days)", () => {
const component = utils.createDatetime({
viewMode: "days",
locale: nl
}),
weekdaysBefore = component
.find(".rdtDays .dow")
.map(element => element.text());
component.setProps({ locale: sv });
const weekdaysAfter = component
.find(".rdtDays .dow")
.map(element => element.text());
expect(weekdaysBefore).not.toEqual(weekdaysAfter);
});
it("locale -> picker should change language (viewMode=months)", () => {
const component = utils.createDatetime({
viewMode: "months",
locale: nl
}),
monthsBefore = [
utils.getNthMonth(component, 2).text(),
utils.getNthMonth(component, 4).text()
];
component.setProps({ locale: sv });
const monthsAfter = [
utils.getNthMonth(component, 2).text(),
utils.getNthMonth(component, 4).text()
];
expect(monthsBefore).not.toEqual(monthsAfter);
});
});
});
describe("event listeners", () => {
describe("onBlur", () => {
it("when selecting a date", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
onBlurFn = jest.fn(),
component = utils.createDatetime({
value: date,
onBlur: onBlurFn,
closeOnSelect: true
});
utils.openDatepicker(component);
// Close component by selecting a date
utils.clickNthDay(component, 2);
expect(onBlurFn).toHaveBeenCalledTimes(1);
});
it("when selecting date (value=null and closeOnSelect=true)", () => {
const onBlurFn = jest.fn(),
component = utils.createDatetime({
value: null,
onBlur: onBlurFn,
closeOnSelect: true
});
utils.openDatepicker(component);
// Close component by selecting a date
utils.clickNthDay(component, 2);
expect(onBlurFn).toHaveBeenCalledTimes(1);
});
it("when selecting date (value=null and closeOnSelect=false)", () => {
const onBlurFn = jest.fn(),
component = utils.createDatetime({
value: null,
onBlur: onBlurFn,
closeOnSelect: false
});
utils.openDatepicker(component);
// Close component by selecting a date
utils.clickNthDay(component, 2);
expect(onBlurFn).not.toHaveBeenCalled();
});
});
it("onFocus when opening datepicker", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
onFocusFn = jest.fn(),
component = utils.createDatetime({ value: date, onFocus: onFocusFn });
utils.openDatepicker(component);
expect(onFocusFn).toHaveBeenCalledTimes(1);
});
describe("onViewModeChange", () => {
it("when switch from days to time view mode", () => {
const component = utils.createDatetime({
onViewModeChange: viewMode => {
expect(viewMode).toEqual("time");
}
});
expect(utils.isDayView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtTimeToggle"));
expect(utils.isTimeView(component)).toBeTruthy();
});
it("when switch from time to days view mode", () => {
const component = utils.createDatetime({
viewMode: "time",
onViewModeChange: viewMode => {
expect(viewMode).toEqual("days");
}
});
expect(utils.isTimeView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtSwitch"));
expect(utils.isDayView(component)).toBeTruthy();
});
it("when switch from days to months view mode", () => {
const component = utils.createDatetime({
onViewModeChange: viewMode => {
expect(viewMode).toEqual("months");
}
});
expect(utils.isDayView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtSwitch"));
expect(utils.isMonthView(component)).toBeTruthy();
});
it("when switch from months to years view mode", () => {
const component = utils.createDatetime({
viewMode: "months",
onViewModeChange: viewMode => {
expect(viewMode).toEqual("years");
}
});
expect(utils.isMonthView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtSwitch"));
expect(utils.isYearView(component)).toBeTruthy();
});
it("only when switch from years to months view mode", () => {
const component = utils.createDatetime({
viewMode: "years",
onViewModeChange: viewMode => {
expect(viewMode).toEqual("months");
}
});
expect(utils.isYearView(component)).toBeTruthy();
utils.clickOnElement(component.find(".rdtSwitch"));
expect(utils.isYearView(component)).toBeTruthy();
utils.clickNthYear(component, 2);
expect(utils.isMonthView(component)).toBeTruthy();
});
it("when switch from months to days view mode", () => {
const component = utils.createDatetime({
viewMode: "months",
onViewModeChange: viewMode => {
expect(viewMode).toEqual("days");
}
});
expect(utils.isMonthView(component)).toBeTruthy();
utils.clickNthMonth(component, 2);
expect(utils.isDayView(component)).toBeTruthy();
});
});
describe("onChange", () => {
it("trigger only when last selection type is selected", () => {
// By selection type I mean if you CAN select day, then selecting a month
// should not trigger onChange
const onChangeFn = jest.fn();
const component = utils.createDatetime({
viewMode: "years",
onChange: onChangeFn
});
utils.openDatepicker(component);
utils.clickNthYear(component, 2);
expect(onChangeFn).not.toHaveBeenCalled();
utils.clickNthMonth(component, 2);
expect(onChangeFn).not.toHaveBeenCalled();
utils.clickNthDay(component, 2);
expect(onChangeFn).toHaveBeenCalled();
});
it("when selecting date", done => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
defaultValue: date,
onChange: selected => {
expect(getDate(selected)).toEqual(2);
expect(getMonth(selected)).toEqual(getMonth(date));
expect(getYear(selected)).toEqual(getYear(date));
done();
}
});
utils.clickNthDay(component, 7);
});
it("when selecting multiple date in a row", done => {
let i = 0;
const date = new Date(2000, 0, 15, 2, 2, 2, 2);
const component = utils.createDatetime({
defaultValue: date,
onChange: selected => {
i++;
if (i > 2) {
expect(getDate(selected)).toEqual(4);
expect(getMonth(selected)).toEqual(getMonth(date));
expect(getYear(selected)).toEqual(getYear(date));
done();
}
}
});
utils.clickNthDay(component, 7);
utils.clickNthDay(component, 8);
utils.clickNthDay(component, 9);
});
it("when selecting month", () => {
const date = Date.UTC(2000, 0, 15, 2, 2, 2, 2);
const onChangeFn = jest.fn();
const component = utils.createDatetime({
defaultValue: date,
dateFormat: "YYYY-MM",
onChange: onChangeFn
});
utils.clickNthMonth(component, 2);
expect(onChangeFn).toHaveBeenCalledTimes(1);
//expect(onChangeFn.mock.calls[0][0].toJSON()).toEqual("2000-03-15T02:02:02.002Z");
});
// Passes locally but not on Travis
it("when selecting year", () => {
const date = Date.UTC(2000, 0, 15, 2, 2, 2, 2);
const onChangeFn = jest.fn();
const component = utils.createDatetime({
defaultValue: date,
dateFormat: "YYYY",
onChange: onChangeFn
});
utils.clickNthYear(component, 2);
expect(onChangeFn).toHaveBeenCalledTimes(1);
expect(onChangeFn.mock.calls[0][0].toJSON()).toEqual(
"2001-01-15T02:02:02.002Z"
);
});
it("when selecting time", () => {
// Did not manage to be able to get onChange to trigger, even though I know it does.
// The listener for the time buttons are set up differently because of having to handle both
// onMouseDown and onMouseUp. Not sure how to test it.
expect(true).toEqual(true);
});
});
});
describe("onNavigateForward", () => {
it("when moving to next month", () => {
const component = utils.createDatetime({
onNavigateForward: (amount, type) => {
expect(amount).toEqual(1);
expect(type).toEqual("months");
}
});
utils.clickOnElement(component.find(".rdtNext"));
});
it("when moving to next year", () => {
const component = utils.createDatetime({
viewMode: "months",
onNavigateForward: (amount, type) => {
expect(amount).toEqual(1);
expect(type).toEqual("years");
}
});
utils.clickOnElement(component.find(".rdtNext"));
});
it("when moving decade forward", () => {
const component = utils.createDatetime({
viewMode: "years",
onNavigateForward: (amount, type) => {
expect(amount).toEqual(10);
expect(type).toEqual("years");
}
});
utils.clickOnElement(component.find(".rdtNext"));
});
});
describe("onNavigateBack", () => {
it("when moving to previous month", () => {
const component = utils.createDatetime({
onNavigateBack: (amount, type) => {
expect(amount).toEqual(1);
expect(type).toEqual("months");
}
});
utils.clickOnElement(component.find(".rdtPrev"));
});
it("when moving to previous year", () => {
const component = utils.createDatetime({
viewMode: "months",
onNavigateBack: (amount, type) => {
expect(amount).toEqual(1);
expect(type).toEqual("years");
}
});
utils.clickOnElement(component.find(".rdtPrev"));
});
it("when moving decade back", () => {
const component = utils.createDatetime({
viewMode: "years",
onNavigateBack: (amount, type) => {
expect(amount).toEqual(10);
expect(type).toEqual("years");
}
});
utils.clickOnElement(component.find(".rdtPrev"));
});
});
describe("with set value", () => {
it("date value", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
strDate = format(date, "MM/DD/YYYY") + " " + format(date, "h:mm A"),
component = utils.createDatetime({ value: date });
expect(utils.getInputValue(component)).toEqual(strDate);
});
it("Date value", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
strDate = format(date, "MM/DD/YYYY") + " " + format(date, "h:mm A"),
component = utils.createDatetime({ value: date });
expect(utils.getInputValue(component)).toEqual(strDate);
});
it("string value", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
strDate = format(date, "MM/DD/YYYY") + " " + format(date, "h:mm A"),
component = utils.createDatetime({ value: strDate });
expect(utils.getInputValue(component)).toEqual(strDate);
});
it("UTC value from local Date", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
dateUTC = date,
strDateUTC =
format(dateUTC, "MM/DD/YYYY") + " " + format(dateUTC, "h:mm A"),
component = utils.createDatetime({ value: date, utc: true });
expect(utils.getInputValue(component)).toEqual(strDateUTC);
});
it("UTC value from UTC Date", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
dateUTC = date,
strDateUTC =
format(dateUTC, "MM/DD/YYYY") + " " + format(dateUTC, "h:mm A"),
component = utils.createDatetime({ value: dateUTC, utc: true });
expect(utils.getInputValue(component)).toEqual(strDateUTC);
});
it("UTC value from UTC string", () => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
dateUTC = date,
strDateUTC =
format(dateUTC, "MM/DD/YYYY") + " " + format(dateUTC, "h:mm A"),
component = utils.createDatetime({ value: strDateUTC, utc: true });
expect(utils.getInputValue(component)).toEqual(strDateUTC);
});
it("invalid string value", done => {
const date = new Date(2000, 0, 15, 2, 2, 2, 2),
strDate = format(date, "MM/DD/YYYY") + " " + format(date, "h:mm A"),
component = utils.createDatetime({
defaultValue: "invalid-value",
onChange: updated => {
expect(format(date, "MM/DD/YYYY h:mm A")).toEqu