@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.
Files changed (33) hide show
  1. package/moj/all.jquery.min.js +7 -70
  2. package/moj/all.js +2856 -2865
  3. package/moj/components/add-another/add-another.js +135 -104
  4. package/moj/components/alert/alert.js +482 -247
  5. package/moj/components/alert/alert.spec.helper.js +30 -5
  6. package/moj/components/button-menu/button-menu.js +346 -319
  7. package/moj/components/date-picker/date-picker.js +925 -900
  8. package/moj/components/filter-toggle-button/filter-toggle-button.js +122 -91
  9. package/moj/components/form-validator/form-validator.js +399 -164
  10. package/moj/components/multi-file-upload/multi-file-upload.js +445 -210
  11. package/moj/components/multi-select/multi-select.js +106 -75
  12. package/moj/components/password-reveal/password-reveal.js +64 -33
  13. package/moj/components/rich-text-editor/rich-text-editor.js +186 -153
  14. package/moj/components/search-toggle/search-toggle.js +77 -46
  15. package/moj/components/sortable-table/sortable-table.js +167 -146
  16. package/moj/helpers/_links.scss +1 -1
  17. package/moj/helpers.js +218 -180
  18. package/moj/moj-frontend.min.js +7 -70
  19. package/moj/version.js +28 -1
  20. package/package.json +1 -1
  21. package/moj/all.spec.js +0 -24
  22. package/moj/components/add-another/add-another.spec.js +0 -165
  23. package/moj/components/alert/alert.spec.js +0 -229
  24. package/moj/components/button-menu/button-menu.spec.js +0 -360
  25. package/moj/components/date-picker/date-picker.spec.js +0 -1178
  26. package/moj/components/filter-toggle-button/filter-toggle-button.spec.js +0 -302
  27. package/moj/components/multi-file-upload/multi-file-upload.spec.js +0 -510
  28. package/moj/components/multi-select/multi-select.spec.js +0 -128
  29. package/moj/components/password-reveal/password-reveal.spec.js +0 -57
  30. package/moj/components/search-toggle/search-toggle.spec.js +0 -129
  31. package/moj/components/sortable-table/sortable-table.spec.js +0 -362
  32. package/moj/helpers.spec.js +0 -235
  33. package/moj/namespace.js +0 -2
@@ -1,510 +0,0 @@
1
- /* eslint-disable no-new */
2
-
3
- const {
4
- queryByRole,
5
- getByLabelText,
6
- fireEvent
7
- } = require('@testing-library/dom')
8
- const { userEvent } = require('@testing-library/user-event')
9
- const { configureAxe } = require('jest-axe')
10
- const sinon = require('sinon')
11
-
12
- require('../../helpers.js')
13
- require('./multi-file-upload.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 createComponent = (options = {}) => {
24
- const html = `
25
- <div class="govuk-grid-row">
26
- <div class="govuk-grid-column-two-thirds">
27
- <div class="moj-multi-file-upload">
28
- <div class="moj-multi-file__uploaded-files moj-hidden">
29
- <h2 class="govuk-heading-m">Files added</h2>
30
- <div class="govuk-summary-list moj-multi-file-upload__list">
31
- </div>
32
- </div>
33
- <div class="moj-multi-file-upload__upload">
34
- <div class="govuk-form-group">
35
- <label class="govuk-label govuk-label--m" for="documents">
36
- Upload a file
37
- </label>
38
- <input class="govuk-file-upload moj-multi-file-upload__input" id="documents" name="documents" type="file" multiple="">
39
- </div>
40
- </div>
41
- </div>
42
- </div>
43
- </div>`
44
-
45
- document.body.insertAdjacentHTML('afterbegin', html)
46
- const component = document.querySelector('.moj-multi-file-upload')
47
- return {
48
- component,
49
- options: { container: component, ...options }
50
- }
51
- }
52
-
53
- describe('Multi-file upload', () => {
54
- let component
55
- let options
56
- let server
57
- let uploadFileEntryHook
58
- let uploadFileExitHook
59
- let uploadFileErrorHook
60
- let fileDeleteHook
61
-
62
- beforeEach(() => {
63
- server = sinon.fakeServerWithClock.create({
64
- respondImmediately: true
65
- })
66
-
67
- uploadFileEntryHook = sinon.spy()
68
- uploadFileExitHook = sinon.spy()
69
- uploadFileErrorHook = sinon.spy()
70
- fileDeleteHook = sinon.spy()
71
- ;({ component, options } = createComponent({
72
- uploadFileEntryHook,
73
- uploadFileExitHook,
74
- uploadFileErrorHook,
75
- fileDeleteHook,
76
- uploadUrl: '/upload',
77
- deleteUrl: '/delete'
78
- }))
79
-
80
- new MOJFrontend.MultiFileUpload(options)
81
- })
82
-
83
- afterEach(() => {
84
- document.body.innerHTML = ''
85
- server.restore()
86
- sinon.restore()
87
- })
88
-
89
- test('initialises with enhanced class', () => {
90
- expect(component).toHaveClass('moj-multi-file-upload--enhanced')
91
- })
92
-
93
- test('creates dropzone with correct text', () => {
94
- const dropzone = component.querySelector('.moj-multi-file-upload__dropzone')
95
- expect(dropzone).toBeInTheDocument()
96
- expect(dropzone).toHaveTextContent('Drag and drop files here or')
97
- expect(dropzone.querySelector('label')).toHaveTextContent('Choose files')
98
- })
99
-
100
- test('creates status box for announcements', () => {
101
- const statusBox = queryByRole(component, 'status')
102
- expect(statusBox).toBeInTheDocument()
103
- expect(statusBox).toHaveClass('govuk-visually-hidden')
104
- })
105
-
106
- describe('File upload handling', () => {
107
- let file
108
- let input
109
- const successResponse = {
110
- success: {
111
- messageHtml: 'File uploaded successfully',
112
- messageText: 'File uploaded successfully'
113
- },
114
- file: {
115
- filename: 'test',
116
- originalname: 'test.txt'
117
- }
118
- }
119
-
120
- beforeEach(() => {
121
- file = new File(['test content'], 'test.txt', { type: 'text/plain' })
122
- input = component.querySelector('.moj-multi-file-upload__input')
123
- input = getByLabelText(component, 'Upload a file')
124
-
125
- // Configure server response for file upload
126
- server.respondWith('POST', '/upload', [
127
- 200,
128
- { 'Content-Type': 'application/json' },
129
- JSON.stringify(successResponse)
130
- ])
131
- })
132
-
133
- test('handles file input change', async () => {
134
- const changeEvent = new Event('change', { bubbles: true })
135
-
136
- // input.files is not writable, so we do this to add the files to the input
137
- Object.defineProperty(input, 'files', {
138
- value: { files: [file] }
139
- })
140
-
141
- fireEvent(input, changeEvent)
142
-
143
- const feedbackContainer = component.querySelector(
144
- '.moj-multi-file__uploaded-files'
145
- )
146
- expect(feedbackContainer).not.toHaveClass('moj-hidden')
147
- const newInput = getByLabelText(component, 'Upload a file')
148
- expect(newInput).toHaveValue('')
149
- expect(newInput).toHaveFocus()
150
- })
151
-
152
- test('displays upload progress', async () => {
153
- // Create a spy on XMLHttpRequest to simulate upload progress
154
- const xhr = sinon.useFakeXMLHttpRequest()
155
- let request
156
- xhr.onCreate = (req) => {
157
- request = req
158
- }
159
-
160
- await user.upload(input, file)
161
-
162
- request.uploadProgress({
163
- lengthComputable: true,
164
- loaded: 50,
165
- total: 100
166
- })
167
-
168
- const fileRows = component.querySelectorAll('.moj-multi-file-upload__row')
169
- const progressElement = component.querySelector(
170
- '.moj-multi-file-upload__progress'
171
- )
172
- const nameElement = component.querySelector(
173
- '.moj-multi-file-upload__filename'
174
- )
175
-
176
- expect(fileRows).toHaveLength(1)
177
- expect(progressElement).toHaveTextContent('50%')
178
- expect(nameElement).toHaveTextContent(file.name)
179
-
180
- xhr.restore()
181
- })
182
-
183
- test('handles successful upload', async () => {
184
- await user.upload(input, file)
185
-
186
- expect(uploadFileEntryHook).toHaveBeenCalledOnce()
187
- expect(uploadFileExitHook).toHaveBeenCalledOnce()
188
- expect(uploadFileExitHook).toHaveBeenCalledAfter(uploadFileEntryHook)
189
-
190
- const successMessage = component.querySelector(
191
- '.moj-multi-file-upload__success'
192
- )
193
- const deleteButton = component.querySelector(
194
- '.moj-multi-file-upload__delete'
195
- )
196
-
197
- expect(successMessage).toHaveTextContent('File uploaded successfully')
198
- expect(deleteButton).toBeInTheDocument()
199
- expect(deleteButton).toHaveAccessibleName(`Delete test.txt`)
200
- expect(deleteButton).toHaveValue('test')
201
- })
202
-
203
- // eslint-disable-next-line jest/no-disabled-tests -- this fails as the component still attempts to access response.file (line 149)
204
- test.skip('handles 200 status with error in response json', async () => {
205
- server.respondWith('POST', '/upload', [
206
- 200,
207
- { 'Content-Type': 'application/json' },
208
- JSON.stringify({
209
- error: {
210
- message: 'Upload failed'
211
- }
212
- })
213
- ])
214
-
215
- await user.upload(input, file)
216
-
217
- const errorMessage = component.querySelector(
218
- '.moj-multi-file-upload__error'
219
- )
220
- expect(errorMessage).toHaveTextContent('Upload failed')
221
- })
222
-
223
- test('handles non 200 response status', async () => {
224
- server.respondWith('POST', '/upload', [
225
- 500,
226
- { 'Content-Type': 'text/plain' },
227
- ''
228
- ])
229
-
230
- await user.upload(input, file)
231
-
232
- expect(uploadFileErrorHook).toHaveBeenCalledOnce()
233
- })
234
- })
235
-
236
- describe('File deletion', () => {
237
- beforeEach(async () => {
238
- const file = new File(['test content'], 'test.txt', {
239
- type: 'text/plain'
240
- })
241
- const input = component.querySelector('.moj-multi-file-upload__input')
242
-
243
- server.respondWith('POST', '/upload', [
244
- 200,
245
- { 'Content-Type': 'application/json' },
246
- JSON.stringify({
247
- success: {
248
- messageHtml: 'File uploaded successfully'
249
- },
250
- file: {
251
- filename: '123',
252
- originalname: 'test.txt'
253
- }
254
- })
255
- ])
256
-
257
- await user.upload(input, file)
258
- })
259
-
260
- test('handles file deletion', async () => {
261
- server.respondWith('POST', '/delete', [
262
- 200,
263
- { 'Content-Type': 'application/json' },
264
- JSON.stringify({ success: true })
265
- ])
266
-
267
- const deleteButton = component.querySelector(
268
- '.moj-multi-file-upload__delete'
269
- )
270
- await user.click(deleteButton)
271
-
272
- expect(fileDeleteHook).toHaveBeenCalledOnce()
273
- expect(server.requests[server.requests.length - 1].url).toBe('/delete')
274
- expect(server.requests[server.requests.length - 1].method).toBe('POST')
275
-
276
- const fileRow = component.querySelector('.moj-multi-file-upload__row')
277
- expect(fileRow).not.toBeInTheDocument()
278
- })
279
-
280
- test('hides feedback container when all files are deleted', async () => {
281
- server.respondWith('POST', '/delete', [
282
- 200,
283
- { 'Content-Type': 'application/json' },
284
- JSON.stringify({ success: true })
285
- ])
286
-
287
- const deleteButton = component.querySelector(
288
- '.moj-multi-file-upload__delete'
289
- )
290
- await user.click(deleteButton)
291
-
292
- const feedbackContainer = component.querySelector(
293
- '.moj-multi-file__uploaded-files'
294
- )
295
- expect(feedbackContainer).toHaveClass('moj-hidden')
296
- })
297
- })
298
-
299
- describe('Drag and drop', () => {
300
- test('handles dragover event', () => {
301
- const dropzone = component.querySelector(
302
- '.moj-multi-file-upload__dropzone'
303
- )
304
- const dragOverEvent = new Event('dragover')
305
- dropzone.dispatchEvent(dragOverEvent)
306
-
307
- expect(dropzone).toHaveClass('moj-multi-file-upload--dragover')
308
- })
309
-
310
- test('handles dragleave event', () => {
311
- const dropzone = component.querySelector(
312
- '.moj-multi-file-upload__dropzone'
313
- )
314
- dropzone.classList.add('moj-multi-file-upload--dragover')
315
-
316
- const dragLeaveEvent = new Event('dragleave')
317
- dropzone.dispatchEvent(dragLeaveEvent)
318
-
319
- expect(dropzone).not.toHaveClass('moj-multi-file-upload--dragover')
320
- })
321
-
322
- test('handles file drop', () => {
323
- server.respondWith('POST', '/upload', [
324
- 200,
325
- { 'Content-Type': 'application/json' },
326
- JSON.stringify({
327
- success: {
328
- messageHtml: 'File uploaded successfully'
329
- },
330
- file: {
331
- filename: 'test',
332
- originalname: 'test.txt'
333
- }
334
- })
335
- ])
336
-
337
- const dropzone = component.querySelector(
338
- '.moj-multi-file-upload__dropzone'
339
- )
340
- const file = new File(['test content'], 'test.txt', {
341
- type: 'text/plain'
342
- })
343
-
344
- const dropEvent = new Event('drop')
345
- dropEvent.preventDefault = () => {}
346
- Object.defineProperty(dropEvent, 'dataTransfer', {
347
- value: {
348
- files: [file]
349
- }
350
- })
351
-
352
- dropzone.dispatchEvent(dropEvent)
353
-
354
- expect(server.requests).toHaveLength(1)
355
- expect(server.requests[0].url).toBe('/upload')
356
- expect(server.requests[0].method).toBe('POST')
357
-
358
- const feedbackContainer = component.querySelector(
359
- '.moj-multi-file__uploaded-files'
360
- )
361
- const successMessage = component.querySelector(
362
- '.moj-multi-file-upload__success'
363
- )
364
- const deleteButton = component.querySelector(
365
- '.moj-multi-file-upload__delete'
366
- )
367
-
368
- // test callbacks
369
- expect(uploadFileEntryHook).toHaveBeenCalledOnce()
370
- expect(uploadFileExitHook).toHaveBeenCalledOnce()
371
- expect(uploadFileExitHook).toHaveBeenCalledAfter(uploadFileEntryHook)
372
-
373
- // test file present in UI
374
- expect(feedbackContainer).not.toHaveClass('moj-hidden')
375
- expect(successMessage).toHaveTextContent('File uploaded successfully')
376
- expect(deleteButton).toBeInTheDocument()
377
- expect(deleteButton).toHaveAccessibleName(`Delete test.txt`)
378
- expect(deleteButton).toHaveValue('test')
379
- })
380
- })
381
-
382
- describe('Uploading multiple files', () => {
383
- let files
384
- let input
385
- const successResponse = {
386
- success: {
387
- messageHtml: 'File uploaded successfully',
388
- messageText: 'File uploaded successfully'
389
- },
390
- file: {
391
- filename: 'test',
392
- originalname: 'test.txt'
393
- }
394
- }
395
-
396
- beforeEach(() => {
397
- files = [
398
- new File(['test content'], 'test-1.txt', { type: 'text/plain' }),
399
- new File(['test content'], 'test-2.txt', { type: 'text/plain' })
400
- ]
401
- input = component.querySelector('.moj-multi-file-upload__input')
402
- input = getByLabelText(component, 'Upload a file')
403
-
404
- // Configure server response for file upload
405
- server.respondWith('POST', '/upload', [
406
- 200,
407
- { 'Content-Type': 'application/json' },
408
- JSON.stringify(successResponse)
409
- ])
410
- })
411
-
412
- test('handles multiple files', async () => {
413
- await user.upload(input, files)
414
-
415
- const feedbackContainer = component.querySelector(
416
- '.moj-multi-file__uploaded-files'
417
- )
418
- const fileRows = component.querySelectorAll('.moj-multi-file-upload__row')
419
- const successMessages = component.querySelectorAll(
420
- '.moj-multi-file-upload__success'
421
- )
422
- const deleteButtons = component.querySelectorAll(
423
- '.moj-multi-file-upload__delete'
424
- )
425
-
426
- expect(uploadFileEntryHook).toHaveBeenCalledTwice()
427
- expect(uploadFileExitHook).toHaveBeenCalledTwice()
428
-
429
- expect(feedbackContainer).not.toHaveClass('moj-hidden')
430
- expect(fileRows).toHaveLength(2)
431
-
432
- expect(successMessages[0]).toHaveTextContent('File uploaded successfully')
433
- expect(deleteButtons[0]).toHaveAccessibleName(`Delete test.txt`)
434
- expect(deleteButtons[0]).toHaveValue('test')
435
- expect(successMessages[1]).toHaveTextContent('File uploaded successfully')
436
- expect(deleteButtons[1]).toHaveAccessibleName(`Delete test.txt`)
437
- expect(deleteButtons[1]).toHaveValue('test')
438
- })
439
-
440
- test('handles multiple file drop', () => {
441
- const dropzone = component.querySelector(
442
- '.moj-multi-file-upload__dropzone'
443
- )
444
-
445
- const dropEvent = new Event('drop')
446
- dropEvent.preventDefault = () => {}
447
- Object.defineProperty(dropEvent, 'dataTransfer', {
448
- value: {
449
- files
450
- }
451
- })
452
-
453
- dropzone.dispatchEvent(dropEvent)
454
-
455
- expect(server.requests).toHaveLength(2)
456
- expect(server.requests[0].url).toBe('/upload')
457
- expect(server.requests[0].method).toBe('POST')
458
-
459
- const feedbackContainer = component.querySelector(
460
- '.moj-multi-file__uploaded-files'
461
- )
462
-
463
- const fileRows = component.querySelectorAll('.moj-multi-file-upload__row')
464
- const successMessages = component.querySelectorAll(
465
- '.moj-multi-file-upload__success'
466
- )
467
- const deleteButtons = component.querySelectorAll(
468
- '.moj-multi-file-upload__delete'
469
- )
470
-
471
- expect(uploadFileEntryHook).toHaveBeenCalledTwice()
472
- expect(uploadFileExitHook).toHaveBeenCalledTwice()
473
-
474
- expect(feedbackContainer).not.toHaveClass('moj-hidden')
475
- expect(fileRows).toHaveLength(2)
476
-
477
- expect(successMessages[0]).toHaveTextContent('File uploaded successfully')
478
- expect(deleteButtons[0]).toHaveAccessibleName(`Delete test.txt`)
479
- expect(deleteButtons[0]).toHaveValue('test')
480
- expect(successMessages[1]).toHaveTextContent('File uploaded successfully')
481
- expect(deleteButtons[1]).toHaveAccessibleName(`Delete test.txt`)
482
- expect(deleteButtons[1]).toHaveValue('test')
483
- })
484
- })
485
-
486
- describe('Accessibility', () => {
487
- let file
488
- let input
489
-
490
- beforeEach(() => {
491
- file = new File(['test content'], 'test.txt', {
492
- type: 'text/plain'
493
- })
494
- input = component.querySelector('.moj-multi-file-upload__input')
495
- })
496
-
497
- test('status messages are announced to screen readers', async () => {
498
- await user.upload(input, file)
499
-
500
- const statusBox = queryByRole(component, 'status')
501
- expect(statusBox).toHaveTextContent('Uploading files, please wait')
502
- })
503
-
504
- test('component has no wcag violations', async () => {
505
- expect(await axe(document.body)).toHaveNoViolations()
506
- await user.upload(input, file)
507
- expect(await axe(document.body)).toHaveNoViolations()
508
- })
509
- })
510
- })
@@ -1,128 +0,0 @@
1
- /* eslint-disable no-new */
2
-
3
- const { queryByRole, queryAllByRole } = require('@testing-library/dom')
4
- const { userEvent } = require('@testing-library/user-event')
5
-
6
- require('./multi-select.js')
7
-
8
- const user = userEvent.setup()
9
-
10
- const createComponent = (id = 'multi-select', idprefix = false) => {
11
- const html = `
12
- <table id="${id}" class="govuk-table" data-module="moj-multi-select" data-multi-select-checkbox="#${id}-select-all" ${idprefix ? `data-multi-select-idprefix="${idprefix}-"` : ''}>
13
- <thead class="govuk-table__head">
14
- <tr class="govuk-table__row">
15
- <th class="govuk-table__header" scope="col" id="${id}-select-all"></th>
16
- <th class="govuk-table__header" scope="col">Name</th>
17
- </tr>
18
- </thead>
19
- <tbody class="govuk-table__body">
20
- <tr class="govuk-table__row govuk-table__row--selected">
21
- <td class="govuk-table__cell">
22
- <div class="govuk-checkboxes__item govuk-checkboxes--small moj-multi-select__checkbox">
23
- <input type="checkbox" class="govuk-checkboxes__input" id="mountain-aconcagua">
24
- <label class="govuk-label govuk-checkboxes__label" for="mountain-aconcagua">
25
- <span class="govuk-visually-hidden">Select Aconcagua</span>
26
- </label>
27
- </div>
28
- </td>
29
- <td class="govuk-table__cell">Aconcagua</td>
30
- </tr>
31
- <tr class="govuk-table__row">
32
- <td class="govuk-table__cell">
33
- <div class="govuk-checkboxes__item govuk-checkboxes--small moj-multi-select__checkbox">
34
- <input type="checkbox" class="govuk-checkboxes__input" id="mountain-denali" value="denali">
35
- <label class="govuk-label govuk-checkboxes__label" for="mountain-denali">
36
- <span class="govuk-visually-hidden">Select Denali</span>
37
- </label>
38
- </div>
39
- </td>
40
- </td>
41
- <td class="govuk-table__cell">Denali</td>
42
- </tr>
43
- </tbody>
44
- </table>
45
- `
46
- document.body.insertAdjacentHTML('afterbegin', html)
47
- const component = document.querySelector(`#${id}`)
48
- return component
49
- }
50
-
51
- describe('multi select', () => {
52
- let component
53
- let container
54
- let checkboxes
55
-
56
- beforeEach(() => {
57
- component = createComponent()
58
- container = component.querySelector('#multi-select-select-all')
59
- checkboxes = component.querySelectorAll('tbody input[type=checkbox]')
60
-
61
- new MOJFrontend.MultiSelect({
62
- container,
63
- checkboxes
64
- })
65
- })
66
-
67
- afterEach(() => {
68
- document.body.innerHTML = ''
69
- })
70
-
71
- test('initialises component', () => {
72
- const selectToggle = queryByRole(container, 'checkbox')
73
-
74
- expect(selectToggle).toBeInTheDocument()
75
- expect(selectToggle).toHaveAccessibleName('Select all')
76
- })
77
-
78
- test('toggles all checkboxes', async () => {
79
- const selectToggle = queryByRole(container, 'checkbox')
80
- const tbody = component.querySelector('tbody')
81
- const checkboxes = queryAllByRole(tbody, 'checkbox')
82
-
83
- expect(checkboxes).toHaveLength(2)
84
- checkboxes.forEach((checkbox) => {
85
- expect(checkbox).not.toBeChecked()
86
- })
87
-
88
- await user.click(selectToggle)
89
- expect(selectToggle).toBeChecked()
90
-
91
- checkboxes.forEach((checkbox) => {
92
- expect(checkbox).toBeChecked()
93
- })
94
-
95
- await user.click(selectToggle)
96
- expect(selectToggle).not.toBeChecked()
97
-
98
- checkboxes.forEach((checkbox) => {
99
- expect(checkbox).not.toBeChecked()
100
- })
101
- })
102
-
103
- test('deselcting single checkbox unchecks all checkbox', async () => {
104
- const selectToggle = queryByRole(container, 'checkbox')
105
- const tbody = component.querySelector('tbody')
106
- const checkboxes = queryAllByRole(tbody, 'checkbox')
107
-
108
- expect(checkboxes).toHaveLength(2)
109
- checkboxes.forEach((checkbox) => {
110
- expect(checkbox).not.toBeChecked()
111
- })
112
-
113
- await user.click(selectToggle)
114
- expect(selectToggle).toBeChecked()
115
-
116
- checkboxes.forEach((checkbox) => {
117
- expect(checkbox).toBeChecked()
118
- })
119
-
120
- await user.click(checkboxes[0])
121
- expect(checkboxes[0]).not.toBeChecked()
122
- expect(selectToggle).not.toBeChecked()
123
-
124
- await user.click(checkboxes[0])
125
- expect(checkboxes[0]).toBeChecked()
126
- expect(selectToggle).toBeChecked()
127
- })
128
- })
@@ -1,57 +0,0 @@
1
- /* eslint-disable no-new */
2
-
3
- const { getByDisplayValue, getByText } = require('@testing-library/dom')
4
- const { userEvent } = require('@testing-library/user-event')
5
- const { configureAxe } = require('jest-axe')
6
-
7
- require('./password-reveal.js')
8
-
9
- const user = userEvent.setup()
10
- const axe = configureAxe({
11
- rules: {
12
- // disable landmark rules when testing isolated components.
13
- region: { enabled: false }
14
- }
15
- })
16
-
17
- describe('Password reveal', () => {
18
- let container
19
-
20
- beforeEach(() => {
21
- const input = document.createElement('input')
22
- input.type = 'password'
23
- input.value = 'password'
24
-
25
- new MOJFrontend.PasswordReveal(input)
26
-
27
- container = input.parentNode
28
- })
29
-
30
- test('initialises container', () => {
31
- expect(container).toHaveClass('moj-password-reveal')
32
- expect(container).toContainElement(getByText(container, 'Show'))
33
- })
34
-
35
- test('toggle reveal', async () => {
36
- const input = getByDisplayValue(container, 'password')
37
- const button = getByText(container, 'Show')
38
-
39
- await user.click(button)
40
-
41
- expect(input).toHaveAttribute('type', 'text')
42
- expect(button).toHaveTextContent('Hide')
43
-
44
- await user.click(button)
45
-
46
- expect(input).toHaveAttribute('type', 'password')
47
- expect(button).toHaveTextContent('Show')
48
- })
49
-
50
- test('accessibility', async () => {
51
- const button = getByText(container, 'Show')
52
-
53
- expect(await axe(document.body)).toHaveNoViolations()
54
- await user.click(button)
55
- expect(await axe(document.body)).toHaveNoViolations()
56
- })
57
- })