@ministryofjustice/frontend 3.0.3 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/moj/all.jquery.min.js +3 -3
- package/moj/all.js +23 -10
- package/moj/components/_all.scss +1 -0
- package/moj/components/date-picker/date-picker.js +10 -4
- package/moj/components/date-picker/date-picker.spec.js +606 -42
- package/moj/components/header/template.njk +1 -1
- package/moj/components/interruption-card/_interruption-card.scss +35 -0
- package/moj/components/interruption-card/macro.njk +3 -0
- package/moj/components/interruption-card/template.njk +35 -0
- package/moj/components/multi-select/README.md +1 -1
- package/moj/components/multi-select/multi-select.js +11 -5
- package/moj/components/pagination/template.njk +2 -2
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @jest-environment jsdom
|
|
3
3
|
*/
|
|
4
4
|
const {
|
|
5
|
+
getAllByRole,
|
|
5
6
|
getByText,
|
|
6
7
|
getByRole,
|
|
7
8
|
queryByRole,
|
|
@@ -9,6 +10,7 @@ const {
|
|
|
9
10
|
screen,
|
|
10
11
|
} = require("@testing-library/dom");
|
|
11
12
|
const { userEvent } = require("@testing-library/user-event");
|
|
13
|
+
const dayjs = require("dayjs");
|
|
12
14
|
const { configureAxe, toHaveNoViolations } = require("jest-axe");
|
|
13
15
|
expect.extend(toHaveNoViolations);
|
|
14
16
|
|
|
@@ -23,19 +25,37 @@ const axe = configureAxe({
|
|
|
23
25
|
},
|
|
24
26
|
});
|
|
25
27
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
const kebabize = (str) => {
|
|
29
|
+
return str.replace(
|
|
30
|
+
/[A-Z]+(?![a-z])|[A-Z]/g,
|
|
31
|
+
($, ofset) => (ofset ? "-" : "") + $.toLowerCase(),
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const configToDataAttributes = (config) => {
|
|
36
|
+
let attributes = "";
|
|
37
|
+
for (let [key, value] of Object.entries(config)) {
|
|
38
|
+
attributes += `data-${kebabize(key)}="${value}" `;
|
|
39
|
+
}
|
|
40
|
+
return attributes;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const createComponent = (config = {}, html) => {
|
|
44
|
+
const dataAttributes = configToDataAttributes(config);
|
|
45
|
+
if (typeof html === "undefined") {
|
|
46
|
+
html = `
|
|
47
|
+
<div class="moj-datepicker" data-module="moj-date-picker" ${dataAttributes}>
|
|
48
|
+
<div class="govuk-form-group">
|
|
49
|
+
<label class="govuk-label" for="date">
|
|
50
|
+
Date
|
|
51
|
+
</label>
|
|
52
|
+
<div id="date-hint" class="govuk-hint">
|
|
53
|
+
For example, 17/5/2024.
|
|
54
|
+
</div>
|
|
55
|
+
<input class="govuk-input moj-js-datepicker-input " id="date" name="date" type="text" aria-describedby="date-hint" autocomplete="off">
|
|
35
56
|
</div>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
</div>`;
|
|
57
|
+
</div>`;
|
|
58
|
+
}
|
|
39
59
|
document.body.insertAdjacentHTML("afterbegin", html);
|
|
40
60
|
|
|
41
61
|
component = document.querySelector('[data-module="moj-date-picker"]');
|
|
@@ -78,6 +98,32 @@ const getLastDayOfWeek = (dateObject, lastDayOfWeekIndex) => {
|
|
|
78
98
|
return lastDayOfWeek;
|
|
79
99
|
};
|
|
80
100
|
|
|
101
|
+
const getDateInCurrentMonth = (excluding = []) => {
|
|
102
|
+
const today = dayjs().date();
|
|
103
|
+
excluding.push(today);
|
|
104
|
+
const lastDayOfMonth = dayjs().endOf("month").date();
|
|
105
|
+
const days = range(1, lastDayOfMonth).filter((x) => !excluding.includes(x));
|
|
106
|
+
|
|
107
|
+
return days[Math.floor(Math.random() * days.length)];
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const getDateRangeInCurrentMonth = (startDay, endDay) => {
|
|
111
|
+
let date = dayjs().date(startDay); // Convert the start date to a Day.js object
|
|
112
|
+
const endDate = dayjs().date(endDay + 1);
|
|
113
|
+
const dates = [];
|
|
114
|
+
|
|
115
|
+
while (date.isBefore(endDate)) {
|
|
116
|
+
dates.push(date);
|
|
117
|
+
date = date.add(1, "day");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return dates;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const range = (start, end) => {
|
|
124
|
+
return [...Array(end - start + 1).keys()].map((x) => x + start);
|
|
125
|
+
};
|
|
126
|
+
|
|
81
127
|
describe("Date picker with defaults", () => {
|
|
82
128
|
let component;
|
|
83
129
|
let calendarButton;
|
|
@@ -153,18 +199,13 @@ describe("Date picker with defaults", () => {
|
|
|
153
199
|
});
|
|
154
200
|
|
|
155
201
|
test("can navigate back in time", async () => {
|
|
156
|
-
const today =
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
const currentMonth = today.getMonth();
|
|
160
|
-
const previousMonthName = new Date(
|
|
161
|
-
today.setMonth(currentMonth - 1),
|
|
162
|
-
).toLocaleString("default", { month: "long" });
|
|
163
|
-
const previousYear = currentYear - 1;
|
|
202
|
+
const today = dayjs();
|
|
203
|
+
const previousMonth = dayjs().subtract(1, 'month')
|
|
204
|
+
const previousYear = previousMonth.subtract(1, 'year')
|
|
164
205
|
|
|
165
|
-
const currentTitle = `${
|
|
166
|
-
const previousMonthTitle = `${
|
|
167
|
-
const previousYearTitle = `${
|
|
206
|
+
const currentTitle = `${today.format('MMMM YYYY')}`;
|
|
207
|
+
const previousMonthTitle = `${previousMonth.format('MMMM YYYY')}`;
|
|
208
|
+
const previousYearTitle = `${previousYear.format('MMMM YYYY')}`;
|
|
168
209
|
|
|
169
210
|
await user.click(calendarButton);
|
|
170
211
|
let prevMonthButton = getByText(dialog, "Previous month");
|
|
@@ -178,18 +219,13 @@ describe("Date picker with defaults", () => {
|
|
|
178
219
|
});
|
|
179
220
|
|
|
180
221
|
test("can navigate forward in time", async () => {
|
|
181
|
-
const today =
|
|
182
|
-
const
|
|
183
|
-
const
|
|
184
|
-
const currentMonth = today.getMonth();
|
|
185
|
-
const nextMonthName = new Date(
|
|
186
|
-
today.setMonth(currentMonth + 1),
|
|
187
|
-
).toLocaleString("default", { month: "long" });
|
|
188
|
-
const nextYear = currentYear + 1;
|
|
222
|
+
const today = dayjs();
|
|
223
|
+
const nextMonth = dayjs().add(1, 'month')
|
|
224
|
+
const nextYear = nextMonth.add(1, 'year')
|
|
189
225
|
|
|
190
|
-
const currentTitle = `${
|
|
191
|
-
const nextMonthTitle = `${
|
|
192
|
-
const nextYearTitle = `${
|
|
226
|
+
const currentTitle = `${today.format('MMMM YYYY')}`;
|
|
227
|
+
const nextMonthTitle = `${nextMonth.format('MMMM YYYY')}`;
|
|
228
|
+
const nextYearTitle = `${nextYear.format('MMMM YYYY')}`;
|
|
193
229
|
|
|
194
230
|
await user.click(calendarButton);
|
|
195
231
|
let nextMonthButton = getByText(dialog, "Next month");
|
|
@@ -559,13 +595,541 @@ describe("Date picker with defaults", () => {
|
|
|
559
595
|
expect(await axe(document.body)).toHaveNoViolations();
|
|
560
596
|
});
|
|
561
597
|
});
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
describe("button menu JS API", () => {
|
|
601
|
+
let component;
|
|
602
|
+
|
|
603
|
+
beforeEach(() => {
|
|
604
|
+
component = createComponent();
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
afterEach(() => {
|
|
608
|
+
document.body.innerHTML = "";
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
describe("config", () => {
|
|
612
|
+
test("default config values", () => {
|
|
613
|
+
const datePicker = new MOJFrontend.DatePicker(component, {});
|
|
614
|
+
datePicker.init();
|
|
615
|
+
|
|
616
|
+
expect(datePicker.config).toStrictEqual({
|
|
617
|
+
leadingZeros: false,
|
|
618
|
+
weekStartDay: "monday",
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
test("leadingZeros", () => {
|
|
623
|
+
const config = { leadingZeros: true };
|
|
624
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
625
|
+
datePicker.init();
|
|
626
|
+
|
|
627
|
+
expect(datePicker.config.leadingZeros).toBe(true);
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
test("weekStartDay can be set to sunday", () => {
|
|
631
|
+
const config = { weekStartDay: "Sunday" };
|
|
632
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
633
|
+
datePicker.init();
|
|
634
|
+
|
|
635
|
+
expect(datePicker.config.weekStartDay).toBe("sunday");
|
|
636
|
+
expect(datePicker.dayLabels[0]).toBe("Sunday");
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
test("weekStartDay can't be set to other days", () => {
|
|
640
|
+
const config = { weekStartDay: "friday" };
|
|
641
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
642
|
+
datePicker.init();
|
|
643
|
+
|
|
644
|
+
expect(datePicker.config.weekStartDay).toBe("monday");
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
test("minDate", () => {
|
|
648
|
+
const minDate = dayjs().subtract("1", "week").startOf("day");
|
|
649
|
+
const config = { minDate: minDate.format("D/M/YYYY") };
|
|
650
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
651
|
+
datePicker.init();
|
|
652
|
+
|
|
653
|
+
expect(datePicker.minDate).toStrictEqual(minDate.toDate());
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
test("future minDate sets currentDate to minDate", () => {
|
|
657
|
+
const minDate = dayjs().add("1", "week").startOf("day");
|
|
658
|
+
const config = { minDate: minDate.format("D/M/YYYY") };
|
|
659
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
660
|
+
datePicker.init();
|
|
562
661
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
662
|
+
expect(datePicker.minDate).toStrictEqual(minDate.toDate());
|
|
663
|
+
expect(datePicker.currentDate).toStrictEqual(minDate.toDate());
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
test("maxDate", () => {
|
|
667
|
+
const maxDate = dayjs().add("1", "week").startOf("day");
|
|
668
|
+
const config = { maxDate: maxDate.format("D/M/YYYY") };
|
|
669
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
670
|
+
datePicker.init();
|
|
671
|
+
|
|
672
|
+
expect(datePicker.maxDate).toStrictEqual(maxDate.toDate());
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
test("past maxDate sets currentDate to maxDate", () => {
|
|
676
|
+
const maxDate = dayjs().subtract("1", "week").startOf("day");
|
|
677
|
+
const config = { maxDate: maxDate.format("D/M/YYYY") };
|
|
678
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
679
|
+
datePicker.init();
|
|
680
|
+
|
|
681
|
+
expect(datePicker.maxDate).toStrictEqual(maxDate.toDate());
|
|
682
|
+
expect(datePicker.currentDate).toStrictEqual(maxDate.toDate());
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
test("excludedDays", () => {
|
|
686
|
+
const config = { excludedDays: "sunday thursday" };
|
|
687
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
688
|
+
datePicker.init();
|
|
689
|
+
|
|
690
|
+
expect(datePicker.excludedDays).toEqual([0, 4]);
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
describe("excludedDates", () => {
|
|
694
|
+
test("excluding a day", () => {
|
|
695
|
+
const dateToExclude = dayjs()
|
|
696
|
+
.date(getDateInCurrentMonth())
|
|
697
|
+
.startOf("day");
|
|
698
|
+
config = { excludedDates: dateToExclude.format("D/M/YYYY") };
|
|
699
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
700
|
+
datePicker.init();
|
|
701
|
+
|
|
702
|
+
expect(datePicker.excludedDates).toStrictEqual([
|
|
703
|
+
dateToExclude.toDate(),
|
|
704
|
+
]);
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
test("excluding multiple dates", () => {
|
|
708
|
+
const firstDateToExclude = dayjs()
|
|
709
|
+
.date(getDateInCurrentMonth())
|
|
710
|
+
.startOf("day");
|
|
711
|
+
const secondDateToExclude = dayjs()
|
|
712
|
+
.date(getDateInCurrentMonth([firstDateToExclude.date()]))
|
|
713
|
+
.startOf("day");
|
|
714
|
+
config = {
|
|
715
|
+
excludedDates: `${firstDateToExclude.format("D/M/YYYY")} ${secondDateToExclude.format("D/M/YYYY")}`,
|
|
716
|
+
};
|
|
717
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
718
|
+
datePicker.init();
|
|
719
|
+
|
|
720
|
+
expect(datePicker.excludedDates.length).toEqual(2);
|
|
721
|
+
expect(datePicker.excludedDates).toStrictEqual([
|
|
722
|
+
firstDateToExclude.toDate(),
|
|
723
|
+
secondDateToExclude.toDate(),
|
|
724
|
+
]);
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
test("excluding a range of days", () => {
|
|
728
|
+
let datesToExclude;
|
|
729
|
+
if (dayjs().date() < 15) {
|
|
730
|
+
datesToExclude = getDateRangeInCurrentMonth(18, 20);
|
|
731
|
+
} else {
|
|
732
|
+
datesToExclude = getDateRangeInCurrentMonth(3, 5);
|
|
733
|
+
}
|
|
734
|
+
datesToExclude = datesToExclude.map((date) => date.startOf("day"));
|
|
735
|
+
config = {
|
|
736
|
+
excludedDates: `${datesToExclude[0].format("D/M/YYYY")}-${datesToExclude[datesToExclude.length-1].format("D/M/YYYY")}`,
|
|
737
|
+
};
|
|
738
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
739
|
+
datePicker.init();
|
|
740
|
+
|
|
741
|
+
expect(datePicker.excludedDates.length).toEqual(3);
|
|
742
|
+
expect(datePicker.excludedDates).toStrictEqual(
|
|
743
|
+
datesToExclude.map((date) => date.toDate()),
|
|
744
|
+
);
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
test("excluding individual dates and a range of days", () => {
|
|
748
|
+
let datesToExclude;
|
|
749
|
+
if (dayjs().date() < 15) {
|
|
750
|
+
datesToExclude = getDateRangeInCurrentMonth(18, 20);
|
|
751
|
+
datesToExclude.push(dayjs().date(22));
|
|
752
|
+
datesToExclude.push(dayjs().date(25));
|
|
753
|
+
} else {
|
|
754
|
+
datesToExclude = getDateRangeInCurrentMonth(3, 5);
|
|
755
|
+
datesToExclude.push(dayjs().date(7));
|
|
756
|
+
datesToExclude.push(dayjs().date(11));
|
|
757
|
+
}
|
|
758
|
+
datesToExclude = datesToExclude.map((date) => date.startOf("day"));
|
|
759
|
+
config = {
|
|
760
|
+
excludedDates: `${datesToExclude[0].format("D/M/YYYY")}-${datesToExclude[2].format("D/M/YYYY")} ${datesToExclude[3].format("D/M/YYYY")} ${datesToExclude[4].format("D/M/YYYY")} `,
|
|
761
|
+
};
|
|
762
|
+
const datePicker = new MOJFrontend.DatePicker(component, config);
|
|
763
|
+
datePicker.init();
|
|
764
|
+
|
|
765
|
+
expect(datePicker.excludedDates.length).toEqual(5);
|
|
766
|
+
expect(datePicker.excludedDates).toStrictEqual(
|
|
767
|
+
datesToExclude.map((date) => date.toDate()),
|
|
768
|
+
);
|
|
769
|
+
});
|
|
770
|
+
});
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
describe("UI", () => {
|
|
774
|
+
let calendarButton;
|
|
775
|
+
let input;
|
|
776
|
+
|
|
777
|
+
test("with leadingZeros false", async () => {
|
|
778
|
+
input = screen.getByLabelText("Date");
|
|
779
|
+
|
|
780
|
+
const config = { leadingZeros: false };
|
|
781
|
+
new MOJFrontend.DatePicker(component, config).init();
|
|
782
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
783
|
+
const dateToSelect = screen.queryByText("9")?.closest("button");
|
|
784
|
+
const selectedDate = dayjs().date(9);
|
|
785
|
+
|
|
786
|
+
await user.click(calendarButton);
|
|
787
|
+
await user.click(dateToSelect);
|
|
788
|
+
|
|
789
|
+
expect(input).toHaveValue(selectedDate.format("D/M/YYYY"));
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
test("with leadingZeros true", async () => {
|
|
793
|
+
input = screen.getByLabelText("Date");
|
|
794
|
+
|
|
795
|
+
const config = { leadingZeros: true };
|
|
796
|
+
new MOJFrontend.DatePicker(component, config).init();
|
|
797
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
798
|
+
const dateToSelect = screen.queryByText("9")?.closest("button");
|
|
799
|
+
const selectedDate = dayjs().date(9);
|
|
800
|
+
|
|
801
|
+
await user.click(calendarButton);
|
|
802
|
+
await user.click(dateToSelect);
|
|
803
|
+
|
|
804
|
+
expect(input).toHaveValue(selectedDate.format("DD/MM/YYYY"));
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
test.skip.failing("minDate", async () => {
|
|
808
|
+
const minDay = 3;
|
|
809
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
810
|
+
const minDate = dayjs().date(minDay);
|
|
811
|
+
const config = { minDate: minDate.format("DD/MM/YYYY") };
|
|
812
|
+
|
|
813
|
+
new MOJFrontend.DatePicker(component, config).init();
|
|
814
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
815
|
+
await user.click(calendarButton);
|
|
816
|
+
|
|
817
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
818
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
819
|
+
const dayButton = screen.getByTestId(testId);
|
|
820
|
+
|
|
821
|
+
if (i <= minDay) {
|
|
822
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
823
|
+
} else {
|
|
824
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
test("maxDate", async () => {
|
|
830
|
+
const maxDay = 21;
|
|
831
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
832
|
+
const maxDate = dayjs().date(maxDay);
|
|
833
|
+
const config = { maxDate: maxDate.format("DD/MM/YYYY") };
|
|
834
|
+
|
|
835
|
+
new MOJFrontend.DatePicker(component, config).init();
|
|
836
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
837
|
+
await user.click(calendarButton);
|
|
838
|
+
|
|
839
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
840
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
841
|
+
const dayButton = screen.getByTestId(testId);
|
|
842
|
+
|
|
843
|
+
if (i > maxDay) {
|
|
844
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
845
|
+
} else {
|
|
846
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
describe("excludedDates", () => {
|
|
852
|
+
test("excluding a day", async () => {
|
|
853
|
+
const dateToExclude = dayjs()
|
|
854
|
+
.date(getDateInCurrentMonth())
|
|
855
|
+
.startOf("day");
|
|
856
|
+
const excludedDay = dateToExclude.date();
|
|
857
|
+
const config = { excludedDates: dateToExclude.format("D/M/YYYY") };
|
|
858
|
+
|
|
859
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
860
|
+
|
|
861
|
+
new MOJFrontend.DatePicker(component, config).init();
|
|
862
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
863
|
+
await user.click(calendarButton);
|
|
864
|
+
|
|
865
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
866
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
867
|
+
const dayButton = screen.getByTestId(testId);
|
|
868
|
+
|
|
869
|
+
if (i == excludedDay) {
|
|
870
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
871
|
+
} else {
|
|
872
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
test("excluding a range of days", async () => {
|
|
878
|
+
let datesToExclude;
|
|
879
|
+
if (dayjs().date() < 15) {
|
|
880
|
+
datesToExclude = getDateRangeInCurrentMonth(18, 20);
|
|
881
|
+
} else {
|
|
882
|
+
datesToExclude = getDateRangeInCurrentMonth(3, 5);
|
|
883
|
+
}
|
|
884
|
+
datesToExclude = datesToExclude.map((date) => date.startOf("day"));
|
|
885
|
+
let daysToExclude = datesToExclude.map((date) => date.date());
|
|
886
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
887
|
+
config = {
|
|
888
|
+
excludedDates: `${datesToExclude[0].format("D/M/YYYY")}-${datesToExclude[datesToExclude.length-1].format("D/M/YYYY")}`,
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
datePicker = new MOJFrontend.DatePicker(component, config).init();
|
|
892
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
893
|
+
await user.click(calendarButton);
|
|
894
|
+
|
|
895
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
896
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
897
|
+
const dayButton = screen.getByTestId(testId);
|
|
898
|
+
|
|
899
|
+
if (daysToExclude.includes(i)) {
|
|
900
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
901
|
+
} else {
|
|
902
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
test("excludedDays", async () => {
|
|
909
|
+
const config = { excludedDays: "sunday" };
|
|
910
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
911
|
+
let excludedDays = [];
|
|
912
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
913
|
+
if (dayjs().date(i).day() === 0) {
|
|
914
|
+
excludedDays.push(i);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
new MOJFrontend.DatePicker(component, config).init();
|
|
918
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
919
|
+
await user.click(calendarButton);
|
|
920
|
+
|
|
921
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
922
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
923
|
+
const dayButton = screen.getByTestId(testId);
|
|
924
|
+
|
|
925
|
+
if (excludedDays.includes(i)) {
|
|
926
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
927
|
+
} else {
|
|
928
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
test("default weekStartDay", async () => {
|
|
934
|
+
new MOJFrontend.DatePicker(component, {}).init();
|
|
935
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
936
|
+
await user.click(calendarButton);
|
|
937
|
+
const headers = getAllByRole(component, "columnheader");
|
|
938
|
+
|
|
939
|
+
expect(headers[0]).toHaveAccessibleName("Monday");
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
test("weekStartDay Sunday", async () => {
|
|
943
|
+
new MOJFrontend.DatePicker(component, { weekStartDay: "sunday" }).init();
|
|
944
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
945
|
+
await user.click(calendarButton);
|
|
946
|
+
const headers = getAllByRole(component, "columnheader");
|
|
947
|
+
|
|
948
|
+
expect(headers[0]).toHaveAccessibleName("Sunday");
|
|
949
|
+
});
|
|
950
|
+
});
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
describe("Datepicker data-attributes API", () => {
|
|
954
|
+
let component;
|
|
955
|
+
let calendarButton;
|
|
956
|
+
let input;
|
|
957
|
+
|
|
958
|
+
beforeEach(() => {});
|
|
959
|
+
|
|
960
|
+
afterEach(() => {
|
|
961
|
+
document.body.innerHTML = "";
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
test("with leadingZeros false", async () => {
|
|
965
|
+
component = createComponent({ leadingZeros: "false" });
|
|
966
|
+
new MOJFrontend.DatePicker(component).init();
|
|
967
|
+
|
|
968
|
+
input = screen.getByLabelText("Date");
|
|
969
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
970
|
+
const dateToSelect = screen.queryByText("9")?.closest("button");
|
|
971
|
+
const selectedDate = dayjs().date(9);
|
|
972
|
+
|
|
973
|
+
await user.click(calendarButton);
|
|
974
|
+
await user.click(dateToSelect);
|
|
975
|
+
|
|
976
|
+
expect(input).toHaveValue(selectedDate.format("D/M/YYYY"));
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
test("with leadingZeros true", async () => {
|
|
980
|
+
const component = createComponent({ leadingZeros: "true" });
|
|
981
|
+
new MOJFrontend.DatePicker(component).init();
|
|
982
|
+
|
|
983
|
+
input = screen.getByLabelText("Date");
|
|
984
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
985
|
+
const dateToSelect = screen.queryByText("9")?.closest("button");
|
|
986
|
+
const selectedDate = dayjs().date(9);
|
|
987
|
+
|
|
988
|
+
await user.click(calendarButton);
|
|
989
|
+
await user.click(dateToSelect);
|
|
990
|
+
|
|
991
|
+
expect(input).toHaveValue(selectedDate.format("DD/MM/YYYY"));
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
test.skip.failing("minDate", async () => {
|
|
995
|
+
const minDay = 3;
|
|
996
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
997
|
+
const minDate = dayjs().date(minDay);
|
|
998
|
+
const component = createComponent({
|
|
999
|
+
minDate: minDate.format("DD/MM/YYYY"),
|
|
1000
|
+
});
|
|
1001
|
+
new MOJFrontend.DatePicker(component).init();
|
|
1002
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
1003
|
+
|
|
1004
|
+
await user.click(calendarButton);
|
|
1005
|
+
|
|
1006
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
1007
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
1008
|
+
const dayButton = screen.getByTestId(testId);
|
|
1009
|
+
|
|
1010
|
+
if (i <= minDay) {
|
|
1011
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
1012
|
+
} else {
|
|
1013
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
test("maxDate", async () => {
|
|
1019
|
+
const maxDay = 21;
|
|
1020
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
1021
|
+
const maxDate = dayjs().date(maxDay);
|
|
1022
|
+
const component = createComponent({
|
|
1023
|
+
maxDate: maxDate.format("DD/MM/YYYY"),
|
|
1024
|
+
});
|
|
1025
|
+
new MOJFrontend.DatePicker(component).init();
|
|
1026
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
1027
|
+
|
|
1028
|
+
await user.click(calendarButton);
|
|
1029
|
+
|
|
1030
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
1031
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
1032
|
+
const dayButton = screen.getByTestId(testId);
|
|
1033
|
+
|
|
1034
|
+
if (i > maxDay) {
|
|
1035
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
1036
|
+
} else {
|
|
1037
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
describe("excludedDates", () => {
|
|
1043
|
+
test("excluding a day", async () => {
|
|
1044
|
+
const dateToExclude = dayjs()
|
|
1045
|
+
.date(getDateInCurrentMonth())
|
|
1046
|
+
.startOf("day");
|
|
1047
|
+
const excludedDay = dateToExclude.date();
|
|
1048
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
1049
|
+
const component = createComponent({
|
|
1050
|
+
excludedDates: dateToExclude.format("D/M/YYYY"),
|
|
1051
|
+
});
|
|
1052
|
+
new MOJFrontend.DatePicker(component).init();
|
|
1053
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
1054
|
+
|
|
1055
|
+
await user.click(calendarButton);
|
|
1056
|
+
|
|
1057
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
1058
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
1059
|
+
const dayButton = screen.getByTestId(testId);
|
|
1060
|
+
|
|
1061
|
+
if (i == excludedDay) {
|
|
1062
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
1063
|
+
} else {
|
|
1064
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
test("excluding a range of days", async () => {
|
|
1070
|
+
let datesToExclude;
|
|
1071
|
+
if (dayjs().date() < 15) {
|
|
1072
|
+
datesToExclude = getDateRangeInCurrentMonth(18, 20);
|
|
1073
|
+
} else {
|
|
1074
|
+
datesToExclude = getDateRangeInCurrentMonth(3, 5);
|
|
1075
|
+
}
|
|
1076
|
+
datesToExclude = datesToExclude.map((date) => date.startOf("day"));
|
|
1077
|
+
let daysToExclude = datesToExclude.map((date) => date.date());
|
|
1078
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
1079
|
+
component = createComponent({
|
|
1080
|
+
excludedDates: `${datesToExclude[0].format("D/M/YYYY")}-${datesToExclude[datesToExclude.length-1].format("D/M/YYYY")}`,
|
|
1081
|
+
});
|
|
1082
|
+
datePicker = new MOJFrontend.DatePicker(component).init();
|
|
1083
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
1084
|
+
|
|
1085
|
+
await user.click(calendarButton);
|
|
1086
|
+
|
|
1087
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
1088
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
1089
|
+
const dayButton = screen.getByTestId(testId);
|
|
1090
|
+
|
|
1091
|
+
if (daysToExclude.includes(i)) {
|
|
1092
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
1093
|
+
} else {
|
|
1094
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
test("excludedDays", async () => {
|
|
1101
|
+
const component = createComponent({ excludedDays: "sunday" });
|
|
1102
|
+
const lastDayinMonth = dayjs().endOf("month").date();
|
|
1103
|
+
let excludedDays = [];
|
|
1104
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
1105
|
+
if (dayjs().date(i).day() === 0) {
|
|
1106
|
+
excludedDays.push(i);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
new MOJFrontend.DatePicker(component).init();
|
|
1110
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
1111
|
+
|
|
1112
|
+
await user.click(calendarButton);
|
|
1113
|
+
|
|
1114
|
+
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
1115
|
+
const testId = dayjs().date(i).startOf("day").format("D/M/YYYY");
|
|
1116
|
+
const dayButton = screen.getByTestId(testId);
|
|
1117
|
+
|
|
1118
|
+
if (excludedDays.includes(i)) {
|
|
1119
|
+
expect(dayButton).toHaveAttribute("aria-disabled", "true");
|
|
1120
|
+
} else {
|
|
1121
|
+
expect(dayButton).not.toHaveAttribute("aria-disabled");
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
test("weekStartDay", async () => {
|
|
1127
|
+
component = createComponent({ weekStartDay: "sunday" });
|
|
1128
|
+
new MOJFrontend.DatePicker(component).init();
|
|
1129
|
+
calendarButton = screen.getByRole("button", { name: "Choose date" });
|
|
1130
|
+
await user.click(calendarButton);
|
|
1131
|
+
const headers = getAllByRole(component, "columnheader");
|
|
1132
|
+
|
|
1133
|
+
expect(headers[0]).toHaveAccessibleName("Sunday");
|
|
1134
|
+
});
|
|
571
1135
|
});
|