@ministryofjustice/frontend 3.4.0 → 3.5.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 +7 -70
- package/moj/all.js +2856 -2865
- package/moj/components/add-another/add-another.js +135 -104
- package/moj/components/alert/alert.js +482 -247
- package/moj/components/alert/alert.spec.helper.js +30 -5
- package/moj/components/button-menu/button-menu.js +346 -319
- package/moj/components/date-picker/date-picker.js +925 -900
- package/moj/components/filter-toggle-button/filter-toggle-button.js +122 -91
- package/moj/components/form-validator/form-validator.js +399 -164
- package/moj/components/multi-file-upload/multi-file-upload.js +445 -210
- package/moj/components/multi-select/multi-select.js +106 -75
- package/moj/components/password-reveal/password-reveal.js +64 -33
- package/moj/components/rich-text-editor/rich-text-editor.js +186 -153
- package/moj/components/search-toggle/search-toggle.js +77 -46
- package/moj/components/sortable-table/sortable-table.js +167 -146
- package/moj/helpers/_links.scss +1 -1
- package/moj/helpers.js +218 -180
- package/moj/moj-frontend.min.js +7 -70
- package/moj/version.js +28 -1
- package/package.json +1 -1
- package/moj/all.spec.js +0 -24
- package/moj/components/add-another/add-another.spec.js +0 -165
- package/moj/components/alert/alert.spec.js +0 -229
- package/moj/components/button-menu/button-menu.spec.js +0 -360
- package/moj/components/date-picker/date-picker.spec.js +0 -1178
- package/moj/components/filter-toggle-button/filter-toggle-button.spec.js +0 -302
- package/moj/components/multi-file-upload/multi-file-upload.spec.js +0 -510
- package/moj/components/multi-select/multi-select.spec.js +0 -128
- package/moj/components/password-reveal/password-reveal.spec.js +0 -57
- package/moj/components/search-toggle/search-toggle.spec.js +0 -129
- package/moj/components/sortable-table/sortable-table.spec.js +0 -362
- package/moj/helpers.spec.js +0 -235
- package/moj/namespace.js +0 -2
|
@@ -1,1178 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
getAllByRole,
|
|
3
|
-
getByText,
|
|
4
|
-
getByRole,
|
|
5
|
-
queryByRole,
|
|
6
|
-
queryByText,
|
|
7
|
-
screen
|
|
8
|
-
} = require('@testing-library/dom')
|
|
9
|
-
const { userEvent } = require('@testing-library/user-event')
|
|
10
|
-
const dayjs = require('dayjs')
|
|
11
|
-
const { configureAxe } = require('jest-axe')
|
|
12
|
-
|
|
13
|
-
require('./date-picker.js')
|
|
14
|
-
|
|
15
|
-
const user = userEvent.setup()
|
|
16
|
-
const axe = configureAxe({
|
|
17
|
-
rules: {
|
|
18
|
-
// disable landmark rules when testing isolated components.
|
|
19
|
-
region: { enabled: false }
|
|
20
|
-
}
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
const kebabize = (str) => {
|
|
24
|
-
return str.replace(
|
|
25
|
-
/[A-Z]+(?![a-z])|[A-Z]/g,
|
|
26
|
-
($, ofset) => (ofset ? '-' : '') + $.toLowerCase()
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const configToDataAttributes = (config) => {
|
|
31
|
-
let attributes = ''
|
|
32
|
-
for (const [key, value] of Object.entries(config)) {
|
|
33
|
-
attributes += `data-${kebabize(key)}="${value}" `
|
|
34
|
-
}
|
|
35
|
-
return attributes
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const createComponent = (config = {}, html) => {
|
|
39
|
-
const dataAttributes = configToDataAttributes(config)
|
|
40
|
-
if (typeof html === 'undefined') {
|
|
41
|
-
html = `
|
|
42
|
-
<div class="moj-datepicker" data-module="moj-date-picker" ${dataAttributes}>
|
|
43
|
-
<div class="govuk-form-group">
|
|
44
|
-
<label class="govuk-label" for="date">
|
|
45
|
-
Date
|
|
46
|
-
</label>
|
|
47
|
-
<div id="date-hint" class="govuk-hint">
|
|
48
|
-
For example, 17/5/2024.
|
|
49
|
-
</div>
|
|
50
|
-
<input class="govuk-input moj-js-datepicker-input " id="date" name="date" type="text" aria-describedby="date-hint" autocomplete="off">
|
|
51
|
-
</div>
|
|
52
|
-
</div>`
|
|
53
|
-
}
|
|
54
|
-
document.body.insertAdjacentHTML('afterbegin', html)
|
|
55
|
-
const component = document.querySelector('[data-module="moj-date-picker"]')
|
|
56
|
-
return component
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const randomIntBetween = (min, max) => {
|
|
60
|
-
return Math.floor(Math.random() * (max - min + 1)) + min
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const getFirstDayOfWeek = (dateObject, firstDayOfWeekIndex) => {
|
|
64
|
-
const dayOfWeek = dateObject.getDay()
|
|
65
|
-
const firstDayOfWeek = new Date(dateObject)
|
|
66
|
-
const diff =
|
|
67
|
-
dayOfWeek >= firstDayOfWeekIndex
|
|
68
|
-
? dayOfWeek - firstDayOfWeekIndex
|
|
69
|
-
: 6 - dayOfWeek
|
|
70
|
-
|
|
71
|
-
firstDayOfWeek.setDate(dateObject.getDate() - diff)
|
|
72
|
-
firstDayOfWeek.setHours(0, 0, 0, 0)
|
|
73
|
-
|
|
74
|
-
return firstDayOfWeek
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const getLastDayOfWeek = (dateObject, lastDayOfWeekIndex) => {
|
|
78
|
-
const dayOfWeek = dateObject.getDay()
|
|
79
|
-
const lastDayOfWeek = new Date(dateObject)
|
|
80
|
-
const diff =
|
|
81
|
-
dayOfWeek <= lastDayOfWeekIndex
|
|
82
|
-
? lastDayOfWeekIndex - dayOfWeek
|
|
83
|
-
: 7 - dayOfWeek
|
|
84
|
-
|
|
85
|
-
lastDayOfWeek.setDate(dateObject.getDate() - diff)
|
|
86
|
-
lastDayOfWeek.setHours(0, 0, 0, 0)
|
|
87
|
-
|
|
88
|
-
return lastDayOfWeek
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const getDateFormatted = (value) => {
|
|
92
|
-
return dayjs().date(value).startOf('day').format('D/M/YYYY')
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const getDateInCurrentMonth = (excluding = []) => {
|
|
96
|
-
const today = dayjs().date()
|
|
97
|
-
excluding.push(today)
|
|
98
|
-
const lastDayOfMonth = dayjs().endOf('month').date()
|
|
99
|
-
const days = range(1, lastDayOfMonth).filter((x) => !excluding.includes(x))
|
|
100
|
-
|
|
101
|
-
return days[Math.floor(Math.random() * days.length)]
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const range = (start, end) => {
|
|
105
|
-
return [...Array(end - start + 1).keys()].map((x) => x + start)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
describe('Date picker with defaults', () => {
|
|
109
|
-
let component
|
|
110
|
-
let calendarButton
|
|
111
|
-
let dialog
|
|
112
|
-
|
|
113
|
-
beforeEach(() => {
|
|
114
|
-
component = createComponent()
|
|
115
|
-
new MOJFrontend.DatePicker(component, {}).init()
|
|
116
|
-
|
|
117
|
-
calendarButton = queryByText(component, 'Choose date')?.closest('button')
|
|
118
|
-
dialog = queryByRole(component, 'dialog', { hidden: true })
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
afterEach(() => {
|
|
122
|
-
document.body.innerHTML = ''
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
test('initialises calendar calendarButton and dialog', () => {
|
|
126
|
-
expect(calendarButton).not.toBeNull()
|
|
127
|
-
expect(dialog).not.toBeNull()
|
|
128
|
-
expect(component).toContainElement(calendarButton)
|
|
129
|
-
expect(component).toContainElement(dialog)
|
|
130
|
-
expect(dialog).not.toBeVisible()
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
test('calendar button toggles dialog', async () => {
|
|
134
|
-
await user.click(calendarButton)
|
|
135
|
-
expect(dialog).toBeVisible()
|
|
136
|
-
|
|
137
|
-
await user.click(calendarButton)
|
|
138
|
-
expect(dialog).not.toBeVisible()
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
test('dialog has required buttons', async () => {
|
|
142
|
-
await user.click(calendarButton)
|
|
143
|
-
const selectButton = queryByText(dialog, 'Select')
|
|
144
|
-
const closeButton = queryByText(dialog, 'Close')
|
|
145
|
-
const prevMonthButton = queryByText(dialog, 'Previous month')
|
|
146
|
-
const prevYearButton = queryByText(dialog, 'Previous year')
|
|
147
|
-
const nextMonthButton = queryByText(dialog, 'Next month')
|
|
148
|
-
const nextYearButton = queryByText(dialog, 'Next year')
|
|
149
|
-
|
|
150
|
-
expect(selectButton).toBeInTheDocument()
|
|
151
|
-
expect(closeButton).toBeInTheDocument()
|
|
152
|
-
expect(prevMonthButton).toBeInTheDocument()
|
|
153
|
-
expect(prevYearButton).toBeInTheDocument()
|
|
154
|
-
expect(nextMonthButton).toBeInTheDocument()
|
|
155
|
-
expect(nextYearButton).toBeInTheDocument()
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
test('calendar opens with current month and year', async () => {
|
|
159
|
-
await user.click(calendarButton)
|
|
160
|
-
const today = new Date()
|
|
161
|
-
const currentMonthName = today.toLocaleString('default', { month: 'long' })
|
|
162
|
-
const currentYear = today.getFullYear()
|
|
163
|
-
const dialogTitle = `${currentMonthName} ${currentYear}`
|
|
164
|
-
|
|
165
|
-
expect(dialog).toContainElement(screen.getByText(dialogTitle))
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
test('today is selected', async () => {
|
|
169
|
-
await user.click(calendarButton)
|
|
170
|
-
const today = new Date()
|
|
171
|
-
const todayButton = getByRole(dialog, 'button', { current: 'date' })
|
|
172
|
-
|
|
173
|
-
expect(todayButton).toHaveFocus()
|
|
174
|
-
expect(todayButton).toHaveClass(
|
|
175
|
-
'moj-datepicker__button--selected',
|
|
176
|
-
'moj-datepicker__button--current',
|
|
177
|
-
'moj-datepicker__button--today'
|
|
178
|
-
)
|
|
179
|
-
expect(todayButton).toHaveTextContent(new RegExp(`${today.getDate()}`))
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
test('can navigate back in time', async () => {
|
|
183
|
-
const today = dayjs()
|
|
184
|
-
const previousMonth = dayjs().subtract(1, 'month')
|
|
185
|
-
const previousYear = previousMonth.subtract(1, 'year')
|
|
186
|
-
|
|
187
|
-
const currentTitle = `${today.format('MMMM YYYY')}`
|
|
188
|
-
const previousMonthTitle = `${previousMonth.format('MMMM YYYY')}`
|
|
189
|
-
const previousYearTitle = `${previousYear.format('MMMM YYYY')}`
|
|
190
|
-
|
|
191
|
-
await user.click(calendarButton)
|
|
192
|
-
const prevMonthButton = getByText(dialog, 'Previous month')
|
|
193
|
-
const prevYearButton = getByText(dialog, 'Previous year')
|
|
194
|
-
|
|
195
|
-
expect(dialog).toContainElement(screen.getByText(currentTitle))
|
|
196
|
-
await user.click(prevMonthButton)
|
|
197
|
-
expect(dialog).toContainElement(screen.getByText(previousMonthTitle))
|
|
198
|
-
await user.click(prevYearButton)
|
|
199
|
-
expect(dialog).toContainElement(screen.getByText(previousYearTitle))
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
test('can navigate forward in time', async () => {
|
|
203
|
-
const today = dayjs()
|
|
204
|
-
const nextMonth = dayjs().add(1, 'month')
|
|
205
|
-
const nextYear = nextMonth.add(1, 'year')
|
|
206
|
-
|
|
207
|
-
const currentTitle = `${today.format('MMMM YYYY')}`
|
|
208
|
-
const nextMonthTitle = `${nextMonth.format('MMMM YYYY')}`
|
|
209
|
-
const nextYearTitle = `${nextYear.format('MMMM YYYY')}`
|
|
210
|
-
|
|
211
|
-
await user.click(calendarButton)
|
|
212
|
-
const nextMonthButton = getByText(dialog, 'Next month')
|
|
213
|
-
const nextYearButton = getByText(dialog, 'Next year')
|
|
214
|
-
|
|
215
|
-
expect(dialog).toContainElement(screen.getByText(currentTitle))
|
|
216
|
-
await user.click(nextMonthButton)
|
|
217
|
-
expect(dialog).toContainElement(screen.getByText(nextMonthTitle))
|
|
218
|
-
await user.click(nextYearButton)
|
|
219
|
-
expect(dialog).toContainElement(screen.getByText(nextYearTitle))
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
test('close button closes the calendar popup', async () => {
|
|
223
|
-
await user.click(calendarButton)
|
|
224
|
-
const closeButton = queryByText(dialog, 'Close')
|
|
225
|
-
|
|
226
|
-
expect(dialog).toBeVisible()
|
|
227
|
-
await user.click(closeButton)
|
|
228
|
-
expect(dialog).not.toBeVisible()
|
|
229
|
-
expect(calendarButton).toHaveFocus()
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
test('clicking outside closes the calendar popup', async () => {
|
|
233
|
-
const hint = screen.getByText('For example, 17/5/2024.')
|
|
234
|
-
|
|
235
|
-
await user.click(calendarButton)
|
|
236
|
-
expect(dialog).toBeVisible()
|
|
237
|
-
await user.click(hint)
|
|
238
|
-
expect(dialog).not.toBeVisible()
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
describe('date picker with initial value', () => {
|
|
242
|
-
let inputString
|
|
243
|
-
let dateString
|
|
244
|
-
let input
|
|
245
|
-
let selectedDate
|
|
246
|
-
let newDate
|
|
247
|
-
|
|
248
|
-
beforeEach(async () => {
|
|
249
|
-
inputString = '19/05/2024'
|
|
250
|
-
dateString = '2024-05-19'
|
|
251
|
-
input = screen.getByLabelText('Date')
|
|
252
|
-
selectedDate = new Date(dateString)
|
|
253
|
-
|
|
254
|
-
while (newDate !== selectedDate.getDate()) {
|
|
255
|
-
newDate = randomIntBetween(7, 21) // outside this we could have duplicate hidden buttons from prev/next month
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
await user.type(input, inputString)
|
|
259
|
-
await user.click(calendarButton)
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
test('opens to date in input field', async () => {
|
|
263
|
-
const selectedDateButton = getByRole(dialog, 'button', {
|
|
264
|
-
current: 'date'
|
|
265
|
-
})
|
|
266
|
-
|
|
267
|
-
expect(selectedDateButton).toHaveFocus()
|
|
268
|
-
expect(selectedDateButton).toHaveClass(
|
|
269
|
-
'moj-datepicker__button--selected',
|
|
270
|
-
'moj-datepicker__button--current'
|
|
271
|
-
)
|
|
272
|
-
expect(selectedDateButton).not.toHaveClass(
|
|
273
|
-
'moj-datepicker__button--today'
|
|
274
|
-
)
|
|
275
|
-
expect(selectedDateButton).toHaveTextContent(
|
|
276
|
-
new RegExp(`${selectedDate.getDate()}`)
|
|
277
|
-
)
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
test('clicking a date selects it, closes dialog, and populates input', async () => {
|
|
281
|
-
const newDateButton = queryByText(dialog, newDate)?.closest('button')
|
|
282
|
-
|
|
283
|
-
await user.click(newDateButton)
|
|
284
|
-
|
|
285
|
-
expect(dialog).not.toBeVisible()
|
|
286
|
-
expect(input).toHaveValue(`${newDate}/5/2024`)
|
|
287
|
-
expect(calendarButton).toHaveFocus()
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
test('clicking select, closes dialog and populates input', async () => {
|
|
291
|
-
const selectButton = getByText(dialog, 'Select')
|
|
292
|
-
|
|
293
|
-
await user.keyboard('ArrowRight')
|
|
294
|
-
await user.click(selectButton)
|
|
295
|
-
|
|
296
|
-
expect(dialog).not.toBeVisible()
|
|
297
|
-
expect(input).toHaveValue(`${newDate}/5/2024`)
|
|
298
|
-
expect(calendarButton).toHaveFocus()
|
|
299
|
-
})
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
describe('keyboard interaction', () => {
|
|
303
|
-
let inputString
|
|
304
|
-
let dateString
|
|
305
|
-
let input
|
|
306
|
-
let initialDate
|
|
307
|
-
|
|
308
|
-
beforeEach(async () => {
|
|
309
|
-
inputString = '19/5/2024'
|
|
310
|
-
dateString = '2024-05-19'
|
|
311
|
-
input = screen.getByLabelText('Date')
|
|
312
|
-
initialDate = new Date(dateString)
|
|
313
|
-
|
|
314
|
-
await user.type(input, inputString)
|
|
315
|
-
})
|
|
316
|
-
|
|
317
|
-
test('esc closes calendar dialog', async () => {
|
|
318
|
-
await user.tab()
|
|
319
|
-
expect(calendarButton).toHaveFocus()
|
|
320
|
-
await user.keyboard('{enter}')
|
|
321
|
-
expect(dialog).toBeVisible()
|
|
322
|
-
await user.keyboard('{escape}')
|
|
323
|
-
expect(dialog).not.toBeVisible()
|
|
324
|
-
expect(calendarButton).toHaveFocus()
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
test('calendar dialog is a focus trap', async () => {
|
|
328
|
-
await user.click(calendarButton)
|
|
329
|
-
const selectedDateButton = getByRole(dialog, 'button', {
|
|
330
|
-
current: 'date'
|
|
331
|
-
})
|
|
332
|
-
const selectButton = queryByText(dialog, 'Select')
|
|
333
|
-
const closeButton = queryByText(dialog, 'Close')
|
|
334
|
-
const prevMonthButton = getByRole(dialog, 'button', {
|
|
335
|
-
name: 'Previous month'
|
|
336
|
-
})
|
|
337
|
-
const prevYearButton = getByRole(dialog, 'button', {
|
|
338
|
-
name: 'Previous year'
|
|
339
|
-
})
|
|
340
|
-
const nextMonthButton = getByRole(dialog, 'button', {
|
|
341
|
-
name: 'Next month'
|
|
342
|
-
})
|
|
343
|
-
const nextYearButton = getByRole(dialog, 'button', { name: 'Next year' })
|
|
344
|
-
|
|
345
|
-
expect(selectedDateButton).toHaveFocus()
|
|
346
|
-
await user.tab()
|
|
347
|
-
expect(selectButton).toHaveFocus()
|
|
348
|
-
await user.tab()
|
|
349
|
-
expect(closeButton).toHaveFocus()
|
|
350
|
-
await user.tab()
|
|
351
|
-
expect(prevYearButton).toHaveFocus()
|
|
352
|
-
await user.tab()
|
|
353
|
-
expect(prevMonthButton).toHaveFocus()
|
|
354
|
-
await user.tab()
|
|
355
|
-
expect(nextMonthButton).toHaveFocus()
|
|
356
|
-
await user.tab()
|
|
357
|
-
expect(nextYearButton).toHaveFocus()
|
|
358
|
-
await user.tab()
|
|
359
|
-
expect(selectedDateButton).toHaveFocus()
|
|
360
|
-
})
|
|
361
|
-
|
|
362
|
-
test('rigth arrow navigates to next day', async () => {
|
|
363
|
-
await user.click(calendarButton)
|
|
364
|
-
const initialDateButton = getByRole(dialog, 'button', {
|
|
365
|
-
current: 'date'
|
|
366
|
-
})
|
|
367
|
-
|
|
368
|
-
expect(initialDateButton).toHaveFocus()
|
|
369
|
-
|
|
370
|
-
await user.keyboard('[ArrowRight]')
|
|
371
|
-
const labelRegex = new RegExp(` ${initialDate.getDate() + 1} `)
|
|
372
|
-
const selectedDateButton = getByRole(dialog, 'button', {
|
|
373
|
-
name: labelRegex
|
|
374
|
-
})
|
|
375
|
-
expect(selectedDateButton).toHaveClass('moj-datepicker__button--selected')
|
|
376
|
-
expect(selectedDateButton).toHaveFocus()
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
test('left arrow navigates to next day', async () => {
|
|
380
|
-
await user.click(calendarButton)
|
|
381
|
-
const initialDateButton = getByRole(dialog, 'button', {
|
|
382
|
-
current: 'date'
|
|
383
|
-
})
|
|
384
|
-
|
|
385
|
-
expect(initialDateButton).toHaveFocus()
|
|
386
|
-
|
|
387
|
-
await user.keyboard('[ArrowLeft]')
|
|
388
|
-
const labelRegex = new RegExp(` ${initialDate.getDate() - 1} `)
|
|
389
|
-
const selectedDateButton = getByRole(dialog, 'button', {
|
|
390
|
-
name: labelRegex
|
|
391
|
-
})
|
|
392
|
-
expect(selectedDateButton).toHaveClass('moj-datepicker__button--selected')
|
|
393
|
-
expect(selectedDateButton).toHaveFocus()
|
|
394
|
-
})
|
|
395
|
-
|
|
396
|
-
test('up arrow navigates to next day', async () => {
|
|
397
|
-
await user.click(calendarButton)
|
|
398
|
-
const initialDateButton = getByRole(dialog, 'button', {
|
|
399
|
-
current: 'date'
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
expect(initialDateButton).toHaveFocus()
|
|
403
|
-
|
|
404
|
-
await user.keyboard('[ArrowUp]')
|
|
405
|
-
const labelRegex = new RegExp(` ${initialDate.getDate() - 7} `)
|
|
406
|
-
const selectedDateButton = getByRole(dialog, 'button', {
|
|
407
|
-
name: labelRegex
|
|
408
|
-
})
|
|
409
|
-
expect(selectedDateButton).toHaveClass('moj-datepicker__button--selected')
|
|
410
|
-
expect(selectedDateButton).toHaveFocus()
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
test('down arrow navigates to next day', async () => {
|
|
414
|
-
await user.click(calendarButton)
|
|
415
|
-
const initialDateButton = getByRole(dialog, 'button', {
|
|
416
|
-
current: 'date'
|
|
417
|
-
})
|
|
418
|
-
|
|
419
|
-
expect(initialDateButton).toHaveFocus()
|
|
420
|
-
|
|
421
|
-
await user.keyboard('[ArrowDown]')
|
|
422
|
-
const labelRegex = new RegExp(` ${initialDate.getDate() + 7} `)
|
|
423
|
-
const selectedDateButton = getByRole(dialog, 'button', {
|
|
424
|
-
name: labelRegex
|
|
425
|
-
})
|
|
426
|
-
expect(selectedDateButton).toHaveClass('moj-datepicker__button--selected')
|
|
427
|
-
expect(selectedDateButton).toHaveFocus()
|
|
428
|
-
})
|
|
429
|
-
|
|
430
|
-
test('home key focuses first day of the week', async () => {
|
|
431
|
-
await user.click(calendarButton)
|
|
432
|
-
const initialDateButton = getByRole(dialog, 'button', {
|
|
433
|
-
current: 'date'
|
|
434
|
-
})
|
|
435
|
-
const firstDayOfWeek = getFirstDayOfWeek(initialDate, 1)
|
|
436
|
-
const labelRegex = new RegExp(` ${firstDayOfWeek.getDate()} `)
|
|
437
|
-
const selectedDateButton = getByRole(dialog, 'button', {
|
|
438
|
-
name: labelRegex
|
|
439
|
-
})
|
|
440
|
-
|
|
441
|
-
expect(initialDateButton).toHaveFocus()
|
|
442
|
-
await user.keyboard('[Home]')
|
|
443
|
-
expect(selectedDateButton).toHaveClass('moj-datepicker__button--selected')
|
|
444
|
-
expect(selectedDateButton).toHaveFocus()
|
|
445
|
-
})
|
|
446
|
-
|
|
447
|
-
test('end key focuses last day of the week', async () => {
|
|
448
|
-
await user.click(calendarButton)
|
|
449
|
-
const initialDateButton = getByRole(dialog, 'button', {
|
|
450
|
-
current: 'date'
|
|
451
|
-
})
|
|
452
|
-
const lastDayOfWeek = getLastDayOfWeek(initialDate, 0)
|
|
453
|
-
const labelRegex = new RegExp(` ${lastDayOfWeek.getDate()} `)
|
|
454
|
-
const selectedDateButton = getByRole(dialog, 'button', {
|
|
455
|
-
name: labelRegex
|
|
456
|
-
})
|
|
457
|
-
|
|
458
|
-
expect(initialDateButton).toHaveFocus()
|
|
459
|
-
await user.keyboard('[End]')
|
|
460
|
-
expect(selectedDateButton).toHaveClass('moj-datepicker__button--selected')
|
|
461
|
-
expect(selectedDateButton).toHaveFocus()
|
|
462
|
-
})
|
|
463
|
-
|
|
464
|
-
test('pageup focuses previous month and year', async () => {
|
|
465
|
-
await user.click(calendarButton)
|
|
466
|
-
const currentMonthName = initialDate.toLocaleString('default', {
|
|
467
|
-
month: 'long'
|
|
468
|
-
})
|
|
469
|
-
const currentYear = initialDate.getFullYear()
|
|
470
|
-
const previousMonthName = new Date(
|
|
471
|
-
new Date(initialDate).setMonth(initialDate.getMonth() - 1, 1)
|
|
472
|
-
).toLocaleString('default', { month: 'long' })
|
|
473
|
-
const previousYear = new Date(
|
|
474
|
-
new Date(initialDate).setFullYear(initialDate.getFullYear() - 1)
|
|
475
|
-
).getFullYear()
|
|
476
|
-
const currentTitle = `${currentMonthName} ${currentYear}`
|
|
477
|
-
const previousMonthTitle = `${previousMonthName} ${currentYear}`
|
|
478
|
-
const previousYearTitle = `${previousMonthName} ${previousYear}`
|
|
479
|
-
const dialogTitle = getByRole(dialog, 'heading', { level: 2 })
|
|
480
|
-
|
|
481
|
-
expect(dialogTitle).toHaveTextContent(currentTitle)
|
|
482
|
-
|
|
483
|
-
await user.keyboard('{PageUp}')
|
|
484
|
-
expect(dialogTitle).toHaveTextContent(previousMonthTitle)
|
|
485
|
-
|
|
486
|
-
await user.keyboard('{Shift>}{PageUp}')
|
|
487
|
-
expect(dialogTitle).toHaveTextContent(previousYearTitle)
|
|
488
|
-
})
|
|
489
|
-
|
|
490
|
-
test('pagedown focuses next month and year', async () => {
|
|
491
|
-
await user.click(calendarButton)
|
|
492
|
-
const currentMonthName = initialDate.toLocaleString('default', {
|
|
493
|
-
month: 'long'
|
|
494
|
-
})
|
|
495
|
-
const currentYear = initialDate.getFullYear()
|
|
496
|
-
const nextMonthName = new Date(
|
|
497
|
-
new Date(initialDate).setMonth(initialDate.getMonth() + 1, 1)
|
|
498
|
-
).toLocaleString('default', { month: 'long' })
|
|
499
|
-
const nextYear = new Date(
|
|
500
|
-
new Date(initialDate).setFullYear(initialDate.getFullYear() + 1)
|
|
501
|
-
).getFullYear()
|
|
502
|
-
const currentTitle = `${currentMonthName} ${currentYear}`
|
|
503
|
-
const nextMonthTitle = `${nextMonthName} ${currentYear}`
|
|
504
|
-
const nextYearTitle = `${nextMonthName} ${nextYear}`
|
|
505
|
-
const dialogTitle = getByRole(dialog, 'heading', { level: 2 })
|
|
506
|
-
|
|
507
|
-
expect(dialogTitle).toHaveTextContent(currentTitle)
|
|
508
|
-
|
|
509
|
-
await user.keyboard('{PageDown}')
|
|
510
|
-
expect(dialogTitle).toHaveTextContent(nextMonthTitle)
|
|
511
|
-
|
|
512
|
-
await user.keyboard('{Shift>}{PageDown}')
|
|
513
|
-
expect(dialogTitle).toHaveTextContent(nextYearTitle)
|
|
514
|
-
})
|
|
515
|
-
|
|
516
|
-
test('enter selects date and closes dialog', async () => {
|
|
517
|
-
await user.click(calendarButton)
|
|
518
|
-
await user.keyboard('[ArrowRight]')
|
|
519
|
-
await user.keyboard('[Enter]')
|
|
520
|
-
|
|
521
|
-
expect(dialog).not.toBeVisible()
|
|
522
|
-
expect(input).toHaveValue(`20/5/2024`)
|
|
523
|
-
expect(calendarButton).toHaveFocus()
|
|
524
|
-
})
|
|
525
|
-
|
|
526
|
-
test('space selects date and closes dialog', async () => {
|
|
527
|
-
await user.click(calendarButton)
|
|
528
|
-
await user.keyboard('[ArrowRight]')
|
|
529
|
-
await user.keyboard('[Space]')
|
|
530
|
-
|
|
531
|
-
expect(dialog).not.toBeVisible()
|
|
532
|
-
expect(input).toHaveValue(`20/5/2024`)
|
|
533
|
-
expect(calendarButton).toHaveFocus()
|
|
534
|
-
})
|
|
535
|
-
|
|
536
|
-
test('select button selects date and closes dialog', async () => {
|
|
537
|
-
await user.click(calendarButton)
|
|
538
|
-
await user.keyboard('[ArrowRight]')
|
|
539
|
-
await user.tab()
|
|
540
|
-
await user.keyboard('[Enter]')
|
|
541
|
-
|
|
542
|
-
expect(dialog).not.toBeVisible()
|
|
543
|
-
expect(input).toHaveValue(`20/5/2024`)
|
|
544
|
-
expect(calendarButton).toHaveFocus()
|
|
545
|
-
})
|
|
546
|
-
|
|
547
|
-
test('close button, closes dialog', async () => {
|
|
548
|
-
await user.click(calendarButton)
|
|
549
|
-
await user.keyboard('[ArrowRight]')
|
|
550
|
-
await user.tab()
|
|
551
|
-
await user.tab()
|
|
552
|
-
await user.keyboard('[Enter]')
|
|
553
|
-
|
|
554
|
-
expect(dialog).not.toBeVisible()
|
|
555
|
-
expect(input).toHaveValue(`19/5/2024`)
|
|
556
|
-
expect(calendarButton).toHaveFocus()
|
|
557
|
-
})
|
|
558
|
-
})
|
|
559
|
-
|
|
560
|
-
describe('accessibility', () => {
|
|
561
|
-
test('component has no wcag violations', async () => {
|
|
562
|
-
expect(await axe(document.body)).toHaveNoViolations()
|
|
563
|
-
await user.click(calendarButton)
|
|
564
|
-
expect(await axe(document.body)).toHaveNoViolations()
|
|
565
|
-
})
|
|
566
|
-
})
|
|
567
|
-
})
|
|
568
|
-
|
|
569
|
-
describe('button menu JS API', () => {
|
|
570
|
-
let component
|
|
571
|
-
|
|
572
|
-
beforeEach(() => {
|
|
573
|
-
component = createComponent()
|
|
574
|
-
})
|
|
575
|
-
|
|
576
|
-
afterEach(() => {
|
|
577
|
-
document.body.innerHTML = ''
|
|
578
|
-
})
|
|
579
|
-
|
|
580
|
-
describe('config', () => {
|
|
581
|
-
test('default config values', () => {
|
|
582
|
-
const datePicker = new MOJFrontend.DatePicker(component, {})
|
|
583
|
-
datePicker.init()
|
|
584
|
-
|
|
585
|
-
expect(datePicker.config).toStrictEqual({
|
|
586
|
-
leadingZeros: false,
|
|
587
|
-
weekStartDay: 'monday'
|
|
588
|
-
})
|
|
589
|
-
})
|
|
590
|
-
|
|
591
|
-
test('leadingZeros', () => {
|
|
592
|
-
const config = { leadingZeros: true }
|
|
593
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
594
|
-
datePicker.init()
|
|
595
|
-
|
|
596
|
-
expect(datePicker.config.leadingZeros).toBe(true)
|
|
597
|
-
})
|
|
598
|
-
|
|
599
|
-
test('weekStartDay can be set to sunday', () => {
|
|
600
|
-
const config = { weekStartDay: 'Sunday' }
|
|
601
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
602
|
-
datePicker.init()
|
|
603
|
-
|
|
604
|
-
expect(datePicker.config.weekStartDay).toBe('sunday')
|
|
605
|
-
expect(datePicker.dayLabels[0]).toBe('Sunday')
|
|
606
|
-
})
|
|
607
|
-
|
|
608
|
-
test("weekStartDay can't be set to other days", () => {
|
|
609
|
-
const config = { weekStartDay: 'friday' }
|
|
610
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
611
|
-
datePicker.init()
|
|
612
|
-
|
|
613
|
-
expect(datePicker.config.weekStartDay).toBe('monday')
|
|
614
|
-
})
|
|
615
|
-
|
|
616
|
-
test('minDate', () => {
|
|
617
|
-
const minDate = dayjs().subtract('1', 'week').startOf('day')
|
|
618
|
-
const config = { minDate: minDate.format('D/M/YYYY') }
|
|
619
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
620
|
-
datePicker.init()
|
|
621
|
-
|
|
622
|
-
expect(datePicker.minDate).toStrictEqual(minDate.toDate())
|
|
623
|
-
})
|
|
624
|
-
|
|
625
|
-
test('future minDate sets currentDate to minDate', () => {
|
|
626
|
-
const minDate = dayjs().add('1', 'week').startOf('day')
|
|
627
|
-
const config = { minDate: minDate.format('D/M/YYYY') }
|
|
628
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
629
|
-
datePicker.init()
|
|
630
|
-
|
|
631
|
-
expect(datePicker.minDate).toStrictEqual(minDate.toDate())
|
|
632
|
-
expect(datePicker.currentDate).toStrictEqual(minDate.toDate())
|
|
633
|
-
})
|
|
634
|
-
|
|
635
|
-
test('maxDate', () => {
|
|
636
|
-
const maxDate = dayjs().add('1', 'week').startOf('day')
|
|
637
|
-
const config = { maxDate: maxDate.format('D/M/YYYY') }
|
|
638
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
639
|
-
datePicker.init()
|
|
640
|
-
|
|
641
|
-
expect(datePicker.maxDate).toStrictEqual(maxDate.toDate())
|
|
642
|
-
})
|
|
643
|
-
|
|
644
|
-
test('past maxDate sets currentDate to maxDate', () => {
|
|
645
|
-
const maxDate = dayjs().subtract('1', 'week').startOf('day')
|
|
646
|
-
const config = { maxDate: maxDate.format('D/M/YYYY') }
|
|
647
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
648
|
-
datePicker.init()
|
|
649
|
-
|
|
650
|
-
expect(datePicker.maxDate).toStrictEqual(maxDate.toDate())
|
|
651
|
-
expect(datePicker.currentDate).toStrictEqual(maxDate.toDate())
|
|
652
|
-
})
|
|
653
|
-
|
|
654
|
-
test('excludedDays', () => {
|
|
655
|
-
const config = { excludedDays: 'sunday thursday' }
|
|
656
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
657
|
-
datePicker.init()
|
|
658
|
-
|
|
659
|
-
expect(datePicker.excludedDays).toEqual([0, 4])
|
|
660
|
-
})
|
|
661
|
-
|
|
662
|
-
describe('excludedDates', () => {
|
|
663
|
-
test('excluding a day', () => {
|
|
664
|
-
const dateToExclude = dayjs()
|
|
665
|
-
.date(getDateInCurrentMonth())
|
|
666
|
-
.startOf('day')
|
|
667
|
-
const config = { excludedDates: dateToExclude.format('D/M/YYYY') }
|
|
668
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
669
|
-
datePicker.init()
|
|
670
|
-
|
|
671
|
-
expect(datePicker.excludedDates).toStrictEqual([dateToExclude.toDate()])
|
|
672
|
-
})
|
|
673
|
-
|
|
674
|
-
test('excluding multiple dates', () => {
|
|
675
|
-
const firstDateToExclude = dayjs()
|
|
676
|
-
.date(getDateInCurrentMonth())
|
|
677
|
-
.startOf('day')
|
|
678
|
-
const secondDateToExclude = dayjs()
|
|
679
|
-
.date(getDateInCurrentMonth([firstDateToExclude.date()]))
|
|
680
|
-
.startOf('day')
|
|
681
|
-
const config = {
|
|
682
|
-
excludedDates: `${firstDateToExclude.format('D/M/YYYY')} ${secondDateToExclude.format('D/M/YYYY')}`
|
|
683
|
-
}
|
|
684
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
685
|
-
datePicker.init()
|
|
686
|
-
|
|
687
|
-
expect(datePicker.excludedDates).toHaveLength(2)
|
|
688
|
-
expect(datePicker.excludedDates).toStrictEqual([
|
|
689
|
-
firstDateToExclude.toDate(),
|
|
690
|
-
secondDateToExclude.toDate()
|
|
691
|
-
])
|
|
692
|
-
})
|
|
693
|
-
|
|
694
|
-
test('excluding a range of days', () => {
|
|
695
|
-
let datesToExclude = []
|
|
696
|
-
if (dayjs().date() < 15) {
|
|
697
|
-
datesToExclude.push(dayjs().date(18))
|
|
698
|
-
datesToExclude.push(dayjs().date(19))
|
|
699
|
-
datesToExclude.push(dayjs().date(20))
|
|
700
|
-
} else {
|
|
701
|
-
datesToExclude.push(dayjs().date(3))
|
|
702
|
-
datesToExclude.push(dayjs().date(4))
|
|
703
|
-
datesToExclude.push(dayjs().date(5))
|
|
704
|
-
}
|
|
705
|
-
datesToExclude = datesToExclude.map((date) => date.startOf('day'))
|
|
706
|
-
|
|
707
|
-
const config = {
|
|
708
|
-
excludedDates: `${datesToExclude[0].format('D/M/YYYY')}-${datesToExclude[datesToExclude.length - 1].format('D/M/YYYY')}`
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
712
|
-
datePicker.init()
|
|
713
|
-
|
|
714
|
-
// expect(datePicker.excludedDates.length).toEqual(3);
|
|
715
|
-
expect(datePicker.excludedDates).toStrictEqual(
|
|
716
|
-
datesToExclude.map((date) => date.toDate())
|
|
717
|
-
)
|
|
718
|
-
})
|
|
719
|
-
|
|
720
|
-
test('excluding individual dates and a range of days', () => {
|
|
721
|
-
let datesToExclude = []
|
|
722
|
-
if (dayjs().date() < 15) {
|
|
723
|
-
datesToExclude.push(dayjs().date(18))
|
|
724
|
-
datesToExclude.push(dayjs().date(19))
|
|
725
|
-
datesToExclude.push(dayjs().date(20))
|
|
726
|
-
datesToExclude.push(dayjs().date(22))
|
|
727
|
-
datesToExclude.push(dayjs().date(25))
|
|
728
|
-
} else {
|
|
729
|
-
datesToExclude.push(dayjs().date(3))
|
|
730
|
-
datesToExclude.push(dayjs().date(4))
|
|
731
|
-
datesToExclude.push(dayjs().date(5))
|
|
732
|
-
datesToExclude.push(dayjs().date(7))
|
|
733
|
-
datesToExclude.push(dayjs().date(11))
|
|
734
|
-
}
|
|
735
|
-
datesToExclude = datesToExclude.map((date) => date.startOf('day'))
|
|
736
|
-
const config = {
|
|
737
|
-
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')}`
|
|
738
|
-
}
|
|
739
|
-
const datePicker = new MOJFrontend.DatePicker(component, config)
|
|
740
|
-
datePicker.init()
|
|
741
|
-
|
|
742
|
-
expect(datePicker.excludedDates).toStrictEqual(
|
|
743
|
-
datesToExclude.map((date) => date.toDate())
|
|
744
|
-
)
|
|
745
|
-
})
|
|
746
|
-
})
|
|
747
|
-
})
|
|
748
|
-
|
|
749
|
-
describe('UI', () => {
|
|
750
|
-
let calendarButton
|
|
751
|
-
let input
|
|
752
|
-
|
|
753
|
-
test('with leadingZeros false', async () => {
|
|
754
|
-
input = screen.getByLabelText('Date')
|
|
755
|
-
|
|
756
|
-
const config = { leadingZeros: false }
|
|
757
|
-
new MOJFrontend.DatePicker(component, config).init()
|
|
758
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
759
|
-
const dateToSelect = dayjs().date(9)
|
|
760
|
-
const dateButton = screen.getByTestId(dateToSelect.format('D/M/YYYY'))
|
|
761
|
-
|
|
762
|
-
await user.click(calendarButton)
|
|
763
|
-
await user.click(dateButton)
|
|
764
|
-
|
|
765
|
-
expect(input).toHaveValue(dateToSelect.format('D/M/YYYY'))
|
|
766
|
-
})
|
|
767
|
-
|
|
768
|
-
test('with leadingZeros true', async () => {
|
|
769
|
-
input = screen.getByLabelText('Date')
|
|
770
|
-
|
|
771
|
-
const config = { leadingZeros: true }
|
|
772
|
-
new MOJFrontend.DatePicker(component, config).init()
|
|
773
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
774
|
-
const dateToSelect = dayjs().date(9)
|
|
775
|
-
const dateButton = screen.getByTestId(dateToSelect.format('DD/MM/YYYY'))
|
|
776
|
-
|
|
777
|
-
await user.click(calendarButton)
|
|
778
|
-
await user.click(dateButton)
|
|
779
|
-
|
|
780
|
-
expect(input).toHaveValue(dateToSelect.format('DD/MM/YYYY'))
|
|
781
|
-
})
|
|
782
|
-
|
|
783
|
-
test('minDate', async () => {
|
|
784
|
-
const minDay = 3
|
|
785
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
786
|
-
const minDate = dayjs().date(minDay)
|
|
787
|
-
const config = { minDate: minDate.format('DD/MM/YYYY') }
|
|
788
|
-
|
|
789
|
-
new MOJFrontend.DatePicker(component, config).init()
|
|
790
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
791
|
-
|
|
792
|
-
await user.click(calendarButton)
|
|
793
|
-
|
|
794
|
-
const dayButtonsDisabled = range(1, minDay - 1)
|
|
795
|
-
.map(getDateFormatted)
|
|
796
|
-
.map(screen.getByTestId)
|
|
797
|
-
|
|
798
|
-
const dayButtonsEnabled = range(minDay, lastDayinMonth)
|
|
799
|
-
.map(getDateFormatted)
|
|
800
|
-
.map(screen.getByTestId)
|
|
801
|
-
|
|
802
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
803
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
807
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
808
|
-
}
|
|
809
|
-
})
|
|
810
|
-
|
|
811
|
-
test('maxDate', async () => {
|
|
812
|
-
const maxDay = 21
|
|
813
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
814
|
-
const maxDate = dayjs().date(maxDay)
|
|
815
|
-
const config = { maxDate: maxDate.format('DD/MM/YYYY') }
|
|
816
|
-
|
|
817
|
-
new MOJFrontend.DatePicker(component, config).init()
|
|
818
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
819
|
-
|
|
820
|
-
await user.click(calendarButton)
|
|
821
|
-
|
|
822
|
-
const dayButtonsDisabled = range(maxDay + 1, lastDayinMonth)
|
|
823
|
-
.map(getDateFormatted)
|
|
824
|
-
.map(screen.getByTestId)
|
|
825
|
-
|
|
826
|
-
const dayButtonsEnabled = range(1, maxDay)
|
|
827
|
-
.map(getDateFormatted)
|
|
828
|
-
.map(screen.getByTestId)
|
|
829
|
-
|
|
830
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
831
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
835
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
836
|
-
}
|
|
837
|
-
})
|
|
838
|
-
|
|
839
|
-
describe('excludedDates', () => {
|
|
840
|
-
test('excluding a day', async () => {
|
|
841
|
-
const dateToExclude = dayjs()
|
|
842
|
-
.date(getDateInCurrentMonth())
|
|
843
|
-
.startOf('day')
|
|
844
|
-
const excludedDay = dateToExclude.date()
|
|
845
|
-
const config = { excludedDates: dateToExclude.format('D/M/YYYY') }
|
|
846
|
-
|
|
847
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
848
|
-
|
|
849
|
-
new MOJFrontend.DatePicker(component, config).init()
|
|
850
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
851
|
-
|
|
852
|
-
await user.click(calendarButton)
|
|
853
|
-
|
|
854
|
-
const dayButtonsDisabled = [excludedDay]
|
|
855
|
-
.map(getDateFormatted)
|
|
856
|
-
.map(screen.getByTestId)
|
|
857
|
-
|
|
858
|
-
const dayButtonsEnabled = range(1, lastDayinMonth)
|
|
859
|
-
.filter((day) => day !== excludedDay)
|
|
860
|
-
.map(getDateFormatted)
|
|
861
|
-
.map(screen.getByTestId)
|
|
862
|
-
|
|
863
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
864
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
868
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
869
|
-
}
|
|
870
|
-
})
|
|
871
|
-
|
|
872
|
-
test('excluding a range of days', async () => {
|
|
873
|
-
let datesToExclude = []
|
|
874
|
-
if (dayjs().date() < 15) {
|
|
875
|
-
datesToExclude.push(dayjs().date(18))
|
|
876
|
-
datesToExclude.push(dayjs().date(19))
|
|
877
|
-
datesToExclude.push(dayjs().date(20))
|
|
878
|
-
} else {
|
|
879
|
-
datesToExclude.push(dayjs().date(3))
|
|
880
|
-
datesToExclude.push(dayjs().date(4))
|
|
881
|
-
datesToExclude.push(dayjs().date(5))
|
|
882
|
-
}
|
|
883
|
-
datesToExclude = datesToExclude.map((date) => date.startOf('day'))
|
|
884
|
-
const daysToExclude = datesToExclude.map((date) => date.date())
|
|
885
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
886
|
-
const config = {
|
|
887
|
-
excludedDates: `${datesToExclude[0].format('D/M/YYYY')}-${datesToExclude[datesToExclude.length - 1].format('D/M/YYYY')}`
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
new MOJFrontend.DatePicker(component, config).init()
|
|
891
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
892
|
-
|
|
893
|
-
await user.click(calendarButton)
|
|
894
|
-
|
|
895
|
-
const dayButtonsDisabled = daysToExclude
|
|
896
|
-
.map(getDateFormatted)
|
|
897
|
-
.map(screen.getByTestId)
|
|
898
|
-
|
|
899
|
-
const dayButtonsEnabled = range(1, lastDayinMonth)
|
|
900
|
-
.filter((day) => !daysToExclude.includes(day))
|
|
901
|
-
.map(getDateFormatted)
|
|
902
|
-
.map(screen.getByTestId)
|
|
903
|
-
|
|
904
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
905
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
909
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
910
|
-
}
|
|
911
|
-
})
|
|
912
|
-
})
|
|
913
|
-
|
|
914
|
-
test('excludedDays', async () => {
|
|
915
|
-
const config = { excludedDays: 'sunday' }
|
|
916
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
917
|
-
const excludedDays = []
|
|
918
|
-
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
919
|
-
if (dayjs().date(i).day() === 0) {
|
|
920
|
-
excludedDays.push(i)
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
new MOJFrontend.DatePicker(component, config).init()
|
|
924
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
925
|
-
|
|
926
|
-
await user.click(calendarButton)
|
|
927
|
-
|
|
928
|
-
const dayButtonsDisabled = excludedDays
|
|
929
|
-
.map(getDateFormatted)
|
|
930
|
-
.map(screen.getByTestId)
|
|
931
|
-
|
|
932
|
-
const dayButtonsEnabled = range(1, lastDayinMonth)
|
|
933
|
-
.filter((day) => !excludedDays.includes(day))
|
|
934
|
-
.map(getDateFormatted)
|
|
935
|
-
.map(screen.getByTestId)
|
|
936
|
-
|
|
937
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
938
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
942
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
943
|
-
}
|
|
944
|
-
})
|
|
945
|
-
|
|
946
|
-
test('default weekStartDay', async () => {
|
|
947
|
-
new MOJFrontend.DatePicker(component, {}).init()
|
|
948
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
949
|
-
await user.click(calendarButton)
|
|
950
|
-
const headers = getAllByRole(component, 'columnheader')
|
|
951
|
-
|
|
952
|
-
expect(headers[0]).toHaveAccessibleName('Monday')
|
|
953
|
-
})
|
|
954
|
-
|
|
955
|
-
test('weekStartDay Sunday', async () => {
|
|
956
|
-
new MOJFrontend.DatePicker(component, { weekStartDay: 'sunday' }).init()
|
|
957
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
958
|
-
await user.click(calendarButton)
|
|
959
|
-
const headers = getAllByRole(component, 'columnheader')
|
|
960
|
-
|
|
961
|
-
expect(headers[0]).toHaveAccessibleName('Sunday')
|
|
962
|
-
})
|
|
963
|
-
})
|
|
964
|
-
})
|
|
965
|
-
|
|
966
|
-
describe('Datepicker data-attributes API', () => {
|
|
967
|
-
let component
|
|
968
|
-
let calendarButton
|
|
969
|
-
let input
|
|
970
|
-
|
|
971
|
-
beforeEach(() => {})
|
|
972
|
-
|
|
973
|
-
afterEach(() => {
|
|
974
|
-
document.body.innerHTML = ''
|
|
975
|
-
})
|
|
976
|
-
|
|
977
|
-
test('with leadingZeros false', async () => {
|
|
978
|
-
component = createComponent({ leadingZeros: 'false' })
|
|
979
|
-
new MOJFrontend.DatePicker(component).init()
|
|
980
|
-
|
|
981
|
-
input = screen.getByLabelText('Date')
|
|
982
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
983
|
-
const dateToSelect = dayjs().date(9)
|
|
984
|
-
const dateButton = screen.getByTestId(dateToSelect.format('D/M/YYYY'))
|
|
985
|
-
|
|
986
|
-
await user.click(calendarButton)
|
|
987
|
-
await user.click(dateButton)
|
|
988
|
-
|
|
989
|
-
expect(input).toHaveValue(dateToSelect.format('D/M/YYYY'))
|
|
990
|
-
})
|
|
991
|
-
|
|
992
|
-
test('with leadingZeros true', async () => {
|
|
993
|
-
const component = createComponent({ leadingZeros: 'true' })
|
|
994
|
-
new MOJFrontend.DatePicker(component).init()
|
|
995
|
-
|
|
996
|
-
input = screen.getByLabelText('Date')
|
|
997
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
998
|
-
const dateToSelect = dayjs().date(9)
|
|
999
|
-
const dateButton = screen.getByTestId(dateToSelect.format('DD/MM/YYYY'))
|
|
1000
|
-
|
|
1001
|
-
await user.click(calendarButton)
|
|
1002
|
-
await user.click(dateButton)
|
|
1003
|
-
|
|
1004
|
-
expect(input).toHaveValue(dateToSelect.format('DD/MM/YYYY'))
|
|
1005
|
-
})
|
|
1006
|
-
|
|
1007
|
-
test('minDate', async () => {
|
|
1008
|
-
const minDay = 3
|
|
1009
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
1010
|
-
const minDate = dayjs().date(minDay)
|
|
1011
|
-
const component = createComponent({
|
|
1012
|
-
minDate: minDate.format('DD/MM/YYYY')
|
|
1013
|
-
})
|
|
1014
|
-
new MOJFrontend.DatePicker(component).init()
|
|
1015
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
1016
|
-
|
|
1017
|
-
await user.click(calendarButton)
|
|
1018
|
-
|
|
1019
|
-
const dayButtonsDisabled = range(1, minDay - 1)
|
|
1020
|
-
.map(getDateFormatted)
|
|
1021
|
-
.map(screen.getByTestId)
|
|
1022
|
-
|
|
1023
|
-
const dayButtonsEnabled = range(minDay, lastDayinMonth)
|
|
1024
|
-
.map(getDateFormatted)
|
|
1025
|
-
.map(screen.getByTestId)
|
|
1026
|
-
|
|
1027
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
1028
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
1032
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
1033
|
-
}
|
|
1034
|
-
})
|
|
1035
|
-
|
|
1036
|
-
test('maxDate', async () => {
|
|
1037
|
-
const maxDay = 21
|
|
1038
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
1039
|
-
const maxDate = dayjs().date(maxDay)
|
|
1040
|
-
const component = createComponent({
|
|
1041
|
-
maxDate: maxDate.format('DD/MM/YYYY')
|
|
1042
|
-
})
|
|
1043
|
-
new MOJFrontend.DatePicker(component).init()
|
|
1044
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
1045
|
-
|
|
1046
|
-
await user.click(calendarButton)
|
|
1047
|
-
|
|
1048
|
-
const dayButtonsDisabled = range(maxDay + 1, lastDayinMonth)
|
|
1049
|
-
.map(getDateFormatted)
|
|
1050
|
-
.map(screen.getByTestId)
|
|
1051
|
-
|
|
1052
|
-
const dayButtonsEnabled = range(1, maxDay)
|
|
1053
|
-
.map(getDateFormatted)
|
|
1054
|
-
.map(screen.getByTestId)
|
|
1055
|
-
|
|
1056
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
1057
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
1061
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
1062
|
-
}
|
|
1063
|
-
})
|
|
1064
|
-
|
|
1065
|
-
describe('excludedDates', () => {
|
|
1066
|
-
test('excluding a day', async () => {
|
|
1067
|
-
const dateToExclude = dayjs().date(getDateInCurrentMonth()).startOf('day')
|
|
1068
|
-
const excludedDay = dateToExclude.date()
|
|
1069
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
1070
|
-
const component = createComponent({
|
|
1071
|
-
excludedDates: dateToExclude.format('D/M/YYYY')
|
|
1072
|
-
})
|
|
1073
|
-
new MOJFrontend.DatePicker(component).init()
|
|
1074
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
1075
|
-
|
|
1076
|
-
await user.click(calendarButton)
|
|
1077
|
-
|
|
1078
|
-
const dayButtonsDisabled = [excludedDay]
|
|
1079
|
-
.map(getDateFormatted)
|
|
1080
|
-
.map(screen.getByTestId)
|
|
1081
|
-
|
|
1082
|
-
const dayButtonsEnabled = range(1, lastDayinMonth)
|
|
1083
|
-
.filter((day) => day !== excludedDay)
|
|
1084
|
-
.map(getDateFormatted)
|
|
1085
|
-
.map(screen.getByTestId)
|
|
1086
|
-
|
|
1087
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
1088
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
1092
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
1093
|
-
}
|
|
1094
|
-
})
|
|
1095
|
-
|
|
1096
|
-
test('excluding a range of days', async () => {
|
|
1097
|
-
let datesToExclude = []
|
|
1098
|
-
if (dayjs().date() < 15) {
|
|
1099
|
-
datesToExclude.push(dayjs().date(18))
|
|
1100
|
-
datesToExclude.push(dayjs().date(19))
|
|
1101
|
-
datesToExclude.push(dayjs().date(20))
|
|
1102
|
-
} else {
|
|
1103
|
-
datesToExclude.push(dayjs().date(3))
|
|
1104
|
-
datesToExclude.push(dayjs().date(4))
|
|
1105
|
-
datesToExclude.push(dayjs().date(5))
|
|
1106
|
-
}
|
|
1107
|
-
datesToExclude = datesToExclude.map((date) => date.startOf('day'))
|
|
1108
|
-
const daysToExclude = datesToExclude.map((date) => date.date())
|
|
1109
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
1110
|
-
component = createComponent({
|
|
1111
|
-
excludedDates: `${datesToExclude[0].format('D/M/YYYY')}-${datesToExclude[datesToExclude.length - 1].format('D/M/YYYY')}`
|
|
1112
|
-
})
|
|
1113
|
-
new MOJFrontend.DatePicker(component).init()
|
|
1114
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
1115
|
-
|
|
1116
|
-
await user.click(calendarButton)
|
|
1117
|
-
|
|
1118
|
-
const dayButtonsDisabled = daysToExclude
|
|
1119
|
-
.map(getDateFormatted)
|
|
1120
|
-
.map(screen.getByTestId)
|
|
1121
|
-
|
|
1122
|
-
const dayButtonsEnabled = range(1, lastDayinMonth)
|
|
1123
|
-
.filter((day) => !daysToExclude.includes(day))
|
|
1124
|
-
.map(getDateFormatted)
|
|
1125
|
-
.map(screen.getByTestId)
|
|
1126
|
-
|
|
1127
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
1128
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
1132
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
1133
|
-
}
|
|
1134
|
-
})
|
|
1135
|
-
})
|
|
1136
|
-
|
|
1137
|
-
test('excludedDays', async () => {
|
|
1138
|
-
const component = createComponent({ excludedDays: 'sunday' })
|
|
1139
|
-
const lastDayinMonth = dayjs().endOf('month').date()
|
|
1140
|
-
const excludedDays = []
|
|
1141
|
-
for (let i = 1; i <= lastDayinMonth; i++) {
|
|
1142
|
-
if (dayjs().date(i).day() === 0) {
|
|
1143
|
-
excludedDays.push(i)
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
new MOJFrontend.DatePicker(component).init()
|
|
1147
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
1148
|
-
|
|
1149
|
-
await user.click(calendarButton)
|
|
1150
|
-
|
|
1151
|
-
const dayButtonsDisabled = excludedDays
|
|
1152
|
-
.map(getDateFormatted)
|
|
1153
|
-
.map(screen.getByTestId)
|
|
1154
|
-
|
|
1155
|
-
const dayButtonsEnabled = range(1, lastDayinMonth)
|
|
1156
|
-
.filter((day) => !excludedDays.includes(day))
|
|
1157
|
-
.map(getDateFormatted)
|
|
1158
|
-
.map(screen.getByTestId)
|
|
1159
|
-
|
|
1160
|
-
for (const dayButton of dayButtonsDisabled) {
|
|
1161
|
-
expect(dayButton).toHaveAttribute('aria-disabled', 'true')
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
for (const dayButton of dayButtonsEnabled) {
|
|
1165
|
-
expect(dayButton).not.toHaveAttribute('aria-disabled')
|
|
1166
|
-
}
|
|
1167
|
-
})
|
|
1168
|
-
|
|
1169
|
-
test('weekStartDay', async () => {
|
|
1170
|
-
component = createComponent({ weekStartDay: 'sunday' })
|
|
1171
|
-
new MOJFrontend.DatePicker(component).init()
|
|
1172
|
-
calendarButton = screen.getByRole('button', { name: 'Choose date' })
|
|
1173
|
-
await user.click(calendarButton)
|
|
1174
|
-
const headers = getAllByRole(component, 'columnheader')
|
|
1175
|
-
|
|
1176
|
-
expect(headers[0]).toHaveAccessibleName('Sunday')
|
|
1177
|
-
})
|
|
1178
|
-
})
|