✨(react) restrict inputs formats in date picker components
Enforces a standardized approach for end consumers using the component's API. Consumers are now required to provide a date as an ISO string in either UTC or with a UTC offset. The support for native Date objects has been removed to ensure consistent and reliable behavior across all implementations. By adopting this uniform input format, we can simplify usage and avoid potential inconsistencies in date handling.
This commit is contained in:
committed by
aleb_the_flash
parent
8cf8e1eba2
commit
0dc46d1144
@@ -1,27 +1,21 @@
|
||||
import {
|
||||
CalendarDate,
|
||||
DateValue,
|
||||
parseAbsolute,
|
||||
parseDate,
|
||||
} from "@internationalized/date";
|
||||
import { DateValue, parseAbsolute, parseDate } from "@internationalized/date";
|
||||
import { vi } from "vitest";
|
||||
import {
|
||||
convertDateValueToString,
|
||||
parseCalendarDate,
|
||||
parseRangeCalendarDate,
|
||||
parseDateValue,
|
||||
parseRangeDateValue,
|
||||
} from ":/components/Forms/DatePicker/utils";
|
||||
import { StringOrDate } from ":/components/Forms/DatePicker/types";
|
||||
|
||||
const expectDateToBeEqual = (
|
||||
parsedDate: CalendarDate | DateValue | undefined,
|
||||
parsedDate: DateValue | undefined,
|
||||
expectedYear: number,
|
||||
expectedMonth: number,
|
||||
expectedDay: number,
|
||||
) => {
|
||||
expect(parsedDate).not.eq(undefined);
|
||||
expect(parsedDate?.year === expectedYear);
|
||||
expect(parsedDate?.month === expectedMonth);
|
||||
expect(parsedDate?.day === expectedDay);
|
||||
expect(parsedDate?.year).eq(expectedYear);
|
||||
expect(parsedDate?.month).eq(expectedMonth);
|
||||
expect(parsedDate?.day).eq(expectedDay);
|
||||
};
|
||||
|
||||
vi.mock("@internationalized/date", async () => {
|
||||
@@ -36,124 +30,46 @@ vi.mock("@internationalized/date", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
describe("parseCalendarDate", () => {
|
||||
it.each([
|
||||
[2023, 4, 12],
|
||||
[2022, 1, 1],
|
||||
[2022, 12, 31],
|
||||
[2022, 5, 2],
|
||||
])("parse an iso string date", (year: number, month: number, day: number) => {
|
||||
const d = new Date(year, month, day);
|
||||
const parsedDate = parseCalendarDate(d.toISOString());
|
||||
expectDateToBeEqual(parsedDate, year, month, day);
|
||||
describe("parseDateValue", () => {
|
||||
it("parse a 'YYYY-MM-DDThh:mm:ssZ' date", () => {
|
||||
const parsedDate = parseDateValue("2023-05-11T00:00:00.000Z");
|
||||
expectDateToBeEqual(parsedDate, 2023, 5, 11);
|
||||
expect(parsedDate?.hour).eq(0);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[2023, 4, 12],
|
||||
[2022, 1, 1],
|
||||
[2022, 12, 31],
|
||||
[2022, 5, 2],
|
||||
])(
|
||||
"parse a 'YYYY-MM-DD' date",
|
||||
(year: number, month: number, day: number) => {
|
||||
const stringDate = `${year}-${month}-${day}`;
|
||||
const parsedDate = parseCalendarDate(stringDate);
|
||||
expectDateToBeEqual(parsedDate, year, month, day);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
[2023, 4, 12],
|
||||
[2022, 1, 1],
|
||||
[2022, 12, 31],
|
||||
[2022, 5, 2],
|
||||
])("parse a datetime date", (year: number, month: number, day: number) => {
|
||||
const date = new Date(year, month, day);
|
||||
const parsedDate = parseCalendarDate(date);
|
||||
expectDateToBeEqual(parsedDate, year, month, day);
|
||||
it("parse a 'YYYY-MM-DDThh:mm:ss±hh:mm' date", () => {
|
||||
const parsedDate = parseDateValue("2023-05-11T00:00:00.000+00:00");
|
||||
expectDateToBeEqual(parsedDate, 2023, 5, 11);
|
||||
expect(parsedDate?.hour).eq(0);
|
||||
});
|
||||
|
||||
it.each([undefined, ""])("parse an empty or null date", (date) => {
|
||||
const parsedDate = parseCalendarDate(date);
|
||||
const parsedDate = parseDateValue(date);
|
||||
expect(parsedDate).eq(undefined);
|
||||
});
|
||||
|
||||
it.each([
|
||||
"35/04/2024",
|
||||
"2023-05-11",
|
||||
"11 janvier 20O2",
|
||||
"22.04.2022",
|
||||
"22-4-2022",
|
||||
"2022-04-1T00:00:00-00:00",
|
||||
"2022-04-01 T00:00:00-00:00",
|
||||
"2022-04-01T00:00:00.000",
|
||||
])("parse a wrong date", (wrongFormattedDate) => {
|
||||
expect(() => parseCalendarDate(wrongFormattedDate)).toThrow(
|
||||
expect(() => parseDateValue(wrongFormattedDate)).toThrow(
|
||||
"Invalid date format when initializing props on DatePicker component",
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[4, "2023-04-22"],
|
||||
[5, "2023-04-30"],
|
||||
[7, "2023-04-22"],
|
||||
])(
|
||||
"parse date to locale timezone, converted to day before",
|
||||
(offset: number, dateString: string) => {
|
||||
// Get the local offset
|
||||
const localOffset = new Date().getTimezoneOffset() / 60;
|
||||
const formattedOffset = offset.toLocaleString("en-US", {
|
||||
minimumIntegerDigits: 2,
|
||||
});
|
||||
|
||||
// Create an ISO string in a timezone that is the day after in local timezone
|
||||
const offsetISODate = `${dateString}T${
|
||||
24 - (offset - localOffset - 1)
|
||||
}:00:00-${formattedOffset}:00`;
|
||||
|
||||
// Parse this ISO string, that should be converted to local timezone
|
||||
const parsedDate = parseCalendarDate(offsetISODate);
|
||||
|
||||
// Make sure the ISO string have been converted to the local timezone
|
||||
const nextDay = parseDate(dateString).add({ days: 1 });
|
||||
expect(parsedDate?.compare(nextDay)).eq(0);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
[4, "2023-04-22"],
|
||||
[5, "2023-04-30"],
|
||||
[7, "2023-04-22"],
|
||||
])(
|
||||
"parse date to locale timezone, converted to same day",
|
||||
(offset: number, dateString: string) => {
|
||||
// Get the local offset
|
||||
const localOffset = new Date().getTimezoneOffset() / 60;
|
||||
const formattedOffset = offset.toLocaleString("en-US", {
|
||||
minimumIntegerDigits: 2,
|
||||
});
|
||||
|
||||
// Create an ISO string in a timezone that is the day after in local timezone
|
||||
const offsetISODate = `${dateString}T${
|
||||
24 - (offset - localOffset + 2)
|
||||
}:00:00-${formattedOffset}:00`;
|
||||
|
||||
// Parse this ISO string, that should be converted to local timezone
|
||||
const parsedDate = parseCalendarDate(offsetISODate);
|
||||
const sameDay = parseDate(dateString);
|
||||
|
||||
// Make sure the ISO string have been converted to the local timezone
|
||||
expect(parsedDate?.compare(sameDay)).eq(0);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("parseRangeCalendarDate", () => {
|
||||
it.each([
|
||||
["2023-03-22", "2023-04-22"],
|
||||
[new Date(2023, 3, 22), "2023-04-22"],
|
||||
["2023-03-22", new Date(2023, 4, 22)],
|
||||
["2022-03-22T00:00:00-00:00", "2023-04-22"],
|
||||
])("parse a date range", (start: string | Date, end: string | Date) => {
|
||||
const range = parseRangeCalendarDate([start, end]);
|
||||
describe("parseRangeDateValue", () => {
|
||||
it("parse a date range", () => {
|
||||
const range = parseRangeDateValue([
|
||||
"2023-03-22T00:00:00.000Z",
|
||||
"2023-04-22T00:00:00.000Z",
|
||||
]);
|
||||
expectDateToBeEqual(range?.start, 2023, 3, 22);
|
||||
expectDateToBeEqual(range?.end, 2023, 4, 22);
|
||||
});
|
||||
@@ -163,19 +79,22 @@ describe("parseRangeCalendarDate", () => {
|
||||
["2023-03-22", ""],
|
||||
])(
|
||||
"parse a partially null or empty date range",
|
||||
(start: StringOrDate, end: StringOrDate) => {
|
||||
expect(parseRangeCalendarDate([start, end])).eq(undefined);
|
||||
(start: string, end: string) => {
|
||||
expect(parseRangeDateValue([start, end])).eq(undefined);
|
||||
},
|
||||
);
|
||||
|
||||
it("parse an undefined date range", () => {
|
||||
expect(parseRangeCalendarDate(undefined)).eq(undefined);
|
||||
expect(parseRangeDateValue(undefined)).eq(undefined);
|
||||
});
|
||||
|
||||
it("parse an inverted date range", () => {
|
||||
// Utils function accepts start date superior to the end date
|
||||
// However, DateRangePicker will trigger an error with the parsed range.
|
||||
const range = parseRangeCalendarDate(["2023-05-22", "2023-04-22"]);
|
||||
const range = parseRangeDateValue([
|
||||
"2023-05-22T00:00:00.000Z",
|
||||
"2023-04-22T00:00:00.000Z",
|
||||
]);
|
||||
expectDateToBeEqual(range?.start, 2023, 5, 22);
|
||||
expectDateToBeEqual(range?.end, 2023, 4, 22);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user