@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,129 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-new */
|
|
2
|
-
|
|
3
|
-
const { queryByRole } = require('@testing-library/dom')
|
|
4
|
-
const { userEvent } = require('@testing-library/user-event')
|
|
5
|
-
const $ = require('jquery')
|
|
6
|
-
|
|
7
|
-
require('./search-toggle.js')
|
|
8
|
-
|
|
9
|
-
const user = userEvent.setup()
|
|
10
|
-
|
|
11
|
-
const createComponent = () => {
|
|
12
|
-
const html = `
|
|
13
|
-
<div class="moj-search-toggle" data-module="moj-search-toggle" data-moj-search-toggle-text="Find case">
|
|
14
|
-
<div class="moj-search-toggle__toggle"></div>
|
|
15
|
-
<div class="moj-search-toggle__search">
|
|
16
|
-
|
|
17
|
-
<div class="moj-search moj-search--ondark moj-search--toggle moj-js-hidden">
|
|
18
|
-
|
|
19
|
-
<form action="" method="get">
|
|
20
|
-
|
|
21
|
-
<div class="govuk-form-group">
|
|
22
|
-
<label class="govuk-label moj-search__label govuk-visually-hidden" for="search2">
|
|
23
|
-
Search
|
|
24
|
-
</label>
|
|
25
|
-
|
|
26
|
-
<div id="search2-hint" class="govuk-hint moj-search__hint ">
|
|
27
|
-
Enter case number, for example 123456
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
<input class="govuk-input moj-search__input " id="search2" name="search2" type="search" aria-describedby="search2-hint">
|
|
31
|
-
|
|
32
|
-
</div>
|
|
33
|
-
|
|
34
|
-
<button type="submit" class="govuk-button moj-search__button " data-module="govuk-button">
|
|
35
|
-
Search
|
|
36
|
-
</button>
|
|
37
|
-
|
|
38
|
-
</form>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
<a href="#">link</a>`
|
|
44
|
-
document.body.insertAdjacentHTML('afterbegin', html)
|
|
45
|
-
const component = document.querySelector('.moj-search-toggle')
|
|
46
|
-
return component
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
describe('search toggle', () => {
|
|
50
|
-
let component, buttonContainer, searchContainer
|
|
51
|
-
|
|
52
|
-
beforeEach(() => {
|
|
53
|
-
component = createComponent()
|
|
54
|
-
searchContainer = component.querySelector('.moj-search')
|
|
55
|
-
buttonContainer = component.querySelector('.moj-search-toggle__toggle')
|
|
56
|
-
|
|
57
|
-
new MOJFrontend.SearchToggle({
|
|
58
|
-
toggleButton: {
|
|
59
|
-
container: $(buttonContainer),
|
|
60
|
-
text: component.getAttribute('data-moj-search-toggle-text')
|
|
61
|
-
},
|
|
62
|
-
search: {
|
|
63
|
-
container: $(searchContainer)
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
afterEach(() => {
|
|
69
|
-
document.body.innerHTML = ''
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
test('initialises component', () => {
|
|
73
|
-
const toggleButton = queryByRole(buttonContainer, 'button')
|
|
74
|
-
|
|
75
|
-
expect(toggleButton).toBeInTheDocument()
|
|
76
|
-
expect(toggleButton).toHaveTextContent('Find case')
|
|
77
|
-
expect(toggleButton).toHaveAttribute('aria-haspopup', 'true')
|
|
78
|
-
expect(toggleButton).toHaveAttribute('aria-expanded', 'false')
|
|
79
|
-
|
|
80
|
-
expect(searchContainer).toHaveClass('moj-js-hidden')
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
test('clicking button toggles search container', async () => {
|
|
84
|
-
const toggleButton = queryByRole(buttonContainer, 'button')
|
|
85
|
-
|
|
86
|
-
await user.click(toggleButton)
|
|
87
|
-
|
|
88
|
-
expect(toggleButton).toHaveAttribute('aria-expanded', 'true')
|
|
89
|
-
expect(searchContainer).not.toHaveClass('moj-js-hidden')
|
|
90
|
-
|
|
91
|
-
const input = queryByRole(searchContainer, 'searchbox')
|
|
92
|
-
expect(input).toHaveFocus()
|
|
93
|
-
|
|
94
|
-
await user.click(toggleButton)
|
|
95
|
-
|
|
96
|
-
expect(toggleButton).toHaveAttribute('aria-expanded', 'false')
|
|
97
|
-
expect(searchContainer).toHaveClass('moj-js-hidden')
|
|
98
|
-
expect(toggleButton).toHaveFocus()
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
test('clicking outside closes the search container', async () => {
|
|
102
|
-
const toggleButton = queryByRole(buttonContainer, 'button')
|
|
103
|
-
|
|
104
|
-
await user.click(toggleButton)
|
|
105
|
-
|
|
106
|
-
expect(toggleButton).toHaveAttribute('aria-expanded', 'true')
|
|
107
|
-
expect(searchContainer).not.toHaveClass('moj-js-hidden')
|
|
108
|
-
|
|
109
|
-
await user.click(document.body)
|
|
110
|
-
|
|
111
|
-
expect(toggleButton).toHaveAttribute('aria-expanded', 'false')
|
|
112
|
-
expect(searchContainer).toHaveClass('moj-js-hidden')
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
test('tabbing closes the search container', async () => {
|
|
116
|
-
const toggleButton = queryByRole(buttonContainer, 'button')
|
|
117
|
-
|
|
118
|
-
await user.click(toggleButton)
|
|
119
|
-
|
|
120
|
-
expect(toggleButton).toHaveAttribute('aria-expanded', 'true')
|
|
121
|
-
expect(searchContainer).not.toHaveClass('moj-js-hidden')
|
|
122
|
-
|
|
123
|
-
await user.tab()
|
|
124
|
-
await user.tab()
|
|
125
|
-
|
|
126
|
-
expect(toggleButton).toHaveAttribute('aria-expanded', 'false')
|
|
127
|
-
expect(searchContainer).toHaveClass('moj-js-hidden')
|
|
128
|
-
})
|
|
129
|
-
})
|
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-new */
|
|
2
|
-
|
|
3
|
-
const { queryByRole } = require('@testing-library/dom')
|
|
4
|
-
const { userEvent } = require('@testing-library/user-event')
|
|
5
|
-
|
|
6
|
-
require('./sortable-table.js')
|
|
7
|
-
|
|
8
|
-
const user = userEvent.setup()
|
|
9
|
-
|
|
10
|
-
const createComponent = (options = {}) => {
|
|
11
|
-
const html = `
|
|
12
|
-
<div>
|
|
13
|
-
<table class="govuk-table" data-module="moj-sortable-table">
|
|
14
|
-
<thead class="govuk-table__head">
|
|
15
|
-
<tr class="govuk-table__row">
|
|
16
|
-
<th scope="col" class="govuk-table__header" aria-sort="ascending">Name</th>
|
|
17
|
-
<th scope="col" class="govuk-table__header" aria-sort="none">Elevation</th>
|
|
18
|
-
<th scope="col" class="govuk-table__header" aria-sort="none">Continent</th>
|
|
19
|
-
<th scope="col" class="govuk-table__header govuk-table__header--numeric" aria-sort="none">First summit</th>
|
|
20
|
-
<th scope="col" class="govuk-table__header" aria-sort="none">Test nickname</th>
|
|
21
|
-
</tr>
|
|
22
|
-
</thead>
|
|
23
|
-
<tbody class="govuk-table__body">
|
|
24
|
-
<tr class="govuk-table__row">
|
|
25
|
-
<td class="govuk-table__cell">Aconcagua</td>
|
|
26
|
-
<td class="govuk-table__cell" data-sort-value="6961">6,961 meters</td>
|
|
27
|
-
<td class="govuk-table__cell">South America</td>
|
|
28
|
-
<td class="govuk-table__cell govuk-table__cell--numeric" data-sort-value="1897">1897</td>
|
|
29
|
-
<td class="govuk-table__cell"></td>
|
|
30
|
-
</tr>
|
|
31
|
-
<tr class="govuk-table__row">
|
|
32
|
-
<td class="govuk-table__cell">Everest</td>
|
|
33
|
-
<td class="govuk-table__cell" data-sort-value="8850">8,850 meters</td>
|
|
34
|
-
<td class="govuk-table__cell">Asia</td>
|
|
35
|
-
<td class="govuk-table__cell govuk-table__cell--numeric" data-sort-value="1953">1953</td>
|
|
36
|
-
<td class="govuk-table__cell">1Tallest</td>
|
|
37
|
-
</tr>
|
|
38
|
-
<tr class="govuk-table__row">
|
|
39
|
-
<td class="govuk-table__cell">Kilimanjaro</td>
|
|
40
|
-
<td class="govuk-table__cell" data-sort-value="5895">5,895 meters</td>
|
|
41
|
-
<td class="govuk-table__cell">Africa</td>
|
|
42
|
-
<td class="govuk-table__cell govuk-table__cell--numeric" data-sort-value="1889">1889</td>
|
|
43
|
-
<td class="govuk-table__cell">KiliJ89</td>
|
|
44
|
-
</tr>
|
|
45
|
-
<tr class="govuk-table__row">
|
|
46
|
-
<td class="govuk-table__cell">K2</td>
|
|
47
|
-
<td class="govuk-table__cell" data-sort-value="8611">8,611 meters</td>
|
|
48
|
-
<td class="govuk-table__cell">Asia</td>
|
|
49
|
-
<td class="govuk-table__cell govuk-table__cell--numeric" data-sort-value="1889">1954</td>
|
|
50
|
-
<td class="govuk-table__cell">1NearlyTallest</td>
|
|
51
|
-
</tr>
|
|
52
|
-
</tbody>
|
|
53
|
-
</table>
|
|
54
|
-
</div>`
|
|
55
|
-
|
|
56
|
-
document.body.insertAdjacentHTML('afterbegin', html)
|
|
57
|
-
const component = document.querySelector('[data-module="moj-sortable-table"]')
|
|
58
|
-
options.table = component
|
|
59
|
-
return { component, options }
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
describe('sortable table', () => {
|
|
63
|
-
let component
|
|
64
|
-
|
|
65
|
-
beforeEach(() => {
|
|
66
|
-
;({ component } = createComponent())
|
|
67
|
-
new MOJFrontend.SortableTable({
|
|
68
|
-
table: component
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
afterEach(() => {
|
|
73
|
-
document.body.innerHTML = ''
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('initialises with buttons in headers', () => {
|
|
77
|
-
const headers = Array.from(component.querySelectorAll('th')).filter(
|
|
78
|
-
(header) => header.getAttribute('aria-sort')
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
for (const header of headers) {
|
|
82
|
-
const button = header.querySelector('button')
|
|
83
|
-
expect(button).toBeInTheDocument()
|
|
84
|
-
expect(button).toHaveTextContent(header.textContent)
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
test('creates status box for announcements', () => {
|
|
89
|
-
const statusBox = queryByRole(component.parentElement, 'status')
|
|
90
|
-
expect(statusBox).toBeInTheDocument()
|
|
91
|
-
expect(statusBox).toHaveClass('govuk-visually-hidden')
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
test('sorts ascending by Name on initial load', () => {
|
|
95
|
-
const tbody = component.querySelector('tbody')
|
|
96
|
-
const cells = tbody.querySelectorAll('tr td:first-child')
|
|
97
|
-
const values = Array.from(cells).map((cell) => cell.textContent.trim())
|
|
98
|
-
|
|
99
|
-
expect(component.querySelector('th')).toHaveAttribute(
|
|
100
|
-
'aria-sort',
|
|
101
|
-
'ascending'
|
|
102
|
-
)
|
|
103
|
-
expect(values).toEqual(['Aconcagua', 'Everest', 'K2', 'Kilimanjaro'])
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
test('sorts string column in descending order when clicked', async () => {
|
|
107
|
-
const nameHeaderButton = queryByRole(component, 'button', { name: 'Name' })
|
|
108
|
-
const tbody = component.querySelector('tbody')
|
|
109
|
-
|
|
110
|
-
await user.click(nameHeaderButton)
|
|
111
|
-
|
|
112
|
-
const descCells = tbody.querySelectorAll('tr td:first-child')
|
|
113
|
-
const descValues = Array.from(descCells).map((cell) =>
|
|
114
|
-
cell.textContent.trim()
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
expect(descValues).toEqual(['Kilimanjaro', 'K2', 'Everest', 'Aconcagua'])
|
|
118
|
-
expect(nameHeaderButton.parentElement).toHaveAttribute(
|
|
119
|
-
'aria-sort',
|
|
120
|
-
'descending'
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
await user.click(nameHeaderButton)
|
|
124
|
-
|
|
125
|
-
const ascCells = tbody.querySelectorAll('tr td:first-child')
|
|
126
|
-
const ascValues = Array.from(ascCells).map((cell) =>
|
|
127
|
-
cell.textContent.trim()
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
expect(ascValues).toEqual(['Aconcagua', 'Everest', 'K2', 'Kilimanjaro'])
|
|
131
|
-
expect(nameHeaderButton.parentElement).toHaveAttribute(
|
|
132
|
-
'aria-sort',
|
|
133
|
-
'ascending'
|
|
134
|
-
)
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
test('sorts numeric column using data-sort-value', async () => {
|
|
138
|
-
const elevationHeaderButton = queryByRole(component, 'button', {
|
|
139
|
-
name: 'Elevation'
|
|
140
|
-
})
|
|
141
|
-
const tbody = component.querySelector('tbody')
|
|
142
|
-
|
|
143
|
-
await user.click(elevationHeaderButton)
|
|
144
|
-
|
|
145
|
-
const ascCells = tbody.querySelectorAll('tr td:nth-child(2)')
|
|
146
|
-
const ascValues = Array.from(ascCells).map((cell) =>
|
|
147
|
-
parseInt(cell.getAttribute('data-sort-value'))
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
expect(ascValues).toEqual([5895, 6961, 8611, 8850])
|
|
151
|
-
expect(elevationHeaderButton.parentElement).toHaveAttribute(
|
|
152
|
-
'aria-sort',
|
|
153
|
-
'ascending'
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
await user.click(elevationHeaderButton)
|
|
157
|
-
|
|
158
|
-
const descCells = tbody.querySelectorAll('tr td:nth-child(2)')
|
|
159
|
-
const descValues = Array.from(descCells).map((cell) =>
|
|
160
|
-
parseInt(cell.getAttribute('data-sort-value'))
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
expect(descValues).toEqual([8850, 8611, 6961, 5895])
|
|
164
|
-
expect(elevationHeaderButton.parentElement).toHaveAttribute(
|
|
165
|
-
'aria-sort',
|
|
166
|
-
'descending'
|
|
167
|
-
)
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
test('sorts mixed data column without specified data-sort-value', async () => {
|
|
171
|
-
const nicknameHeaderButton = queryByRole(component, 'button', {
|
|
172
|
-
name: 'Test nickname'
|
|
173
|
-
})
|
|
174
|
-
const tbody = component.querySelector('tbody')
|
|
175
|
-
|
|
176
|
-
await user.click(nicknameHeaderButton)
|
|
177
|
-
|
|
178
|
-
const ascCells = tbody.querySelectorAll('tr td:nth-child(5)')
|
|
179
|
-
const ascValues = Array.from(ascCells).map((cell) =>
|
|
180
|
-
cell.textContent.trim()
|
|
181
|
-
)
|
|
182
|
-
// Values converted to numbers in getCellValue function for comparison
|
|
183
|
-
|
|
184
|
-
expect(ascValues).toEqual(['', '1NearlyTallest', '1Tallest', 'KiliJ89'])
|
|
185
|
-
expect(nicknameHeaderButton.parentElement).toHaveAttribute(
|
|
186
|
-
'aria-sort',
|
|
187
|
-
'ascending'
|
|
188
|
-
)
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
test('updates status message when sorting', async () => {
|
|
192
|
-
const elevationHeaderButton = queryByRole(component, 'button', {
|
|
193
|
-
name: 'Elevation'
|
|
194
|
-
})
|
|
195
|
-
const statusBox = queryByRole(component.parentElement, 'status')
|
|
196
|
-
|
|
197
|
-
await user.click(elevationHeaderButton)
|
|
198
|
-
|
|
199
|
-
expect(statusBox).toHaveTextContent('Sort by Elevation (ascending)')
|
|
200
|
-
|
|
201
|
-
await user.click(elevationHeaderButton)
|
|
202
|
-
|
|
203
|
-
expect(statusBox).toHaveTextContent('Sort by Elevation (descending)')
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
test('removes sort state from other columns when sorting a new column', async () => {
|
|
207
|
-
const nameHeaderButton = queryByRole(component, 'button', { name: 'Name' })
|
|
208
|
-
const elevationHeaderButton = queryByRole(component, 'button', {
|
|
209
|
-
name: 'Elevation'
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
await user.click(elevationHeaderButton)
|
|
213
|
-
|
|
214
|
-
expect(nameHeaderButton.parentElement).toHaveAttribute('aria-sort', 'none')
|
|
215
|
-
expect(elevationHeaderButton.parentElement).toHaveAttribute(
|
|
216
|
-
'aria-sort',
|
|
217
|
-
'ascending'
|
|
218
|
-
)
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
test('cycles through sort states: none -> ascending -> descending', async () => {
|
|
222
|
-
const headerButton = queryByRole(component, 'button', { name: 'Continent' })
|
|
223
|
-
const header = headerButton.parentElement
|
|
224
|
-
|
|
225
|
-
expect(header).toHaveAttribute('aria-sort', 'none')
|
|
226
|
-
|
|
227
|
-
await user.click(headerButton)
|
|
228
|
-
expect(header).toHaveAttribute('aria-sort', 'ascending')
|
|
229
|
-
|
|
230
|
-
await user.click(headerButton)
|
|
231
|
-
expect(header).toHaveAttribute('aria-sort', 'descending')
|
|
232
|
-
|
|
233
|
-
await user.click(headerButton)
|
|
234
|
-
expect(header).toHaveAttribute('aria-sort', 'ascending')
|
|
235
|
-
})
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
describe('sortable table options', () => {
|
|
239
|
-
let component
|
|
240
|
-
let options
|
|
241
|
-
|
|
242
|
-
beforeEach(() => {
|
|
243
|
-
;({ component, options } = createComponent())
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
afterEach(() => {
|
|
247
|
-
document.body.innerHTML = ''
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
test('uses default status message when no options provided', async () => {
|
|
251
|
-
new MOJFrontend.SortableTable(options)
|
|
252
|
-
|
|
253
|
-
const elevationHeaderButton = queryByRole(component, 'button', {
|
|
254
|
-
name: 'Elevation'
|
|
255
|
-
})
|
|
256
|
-
const statusBox = queryByRole(component.parentElement, 'status')
|
|
257
|
-
|
|
258
|
-
await user.click(elevationHeaderButton)
|
|
259
|
-
expect(statusBox).toHaveTextContent('Sort by Elevation (ascending)')
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
test('uses custom status message when provided', async () => {
|
|
263
|
-
options.statusMessage = 'Sorted column: %heading% (order: %direction%)'
|
|
264
|
-
new MOJFrontend.SortableTable(options)
|
|
265
|
-
|
|
266
|
-
const elevationHeaderButton = queryByRole(component, 'button', {
|
|
267
|
-
name: 'Elevation'
|
|
268
|
-
})
|
|
269
|
-
const statusBox = queryByRole(component.parentElement, 'status')
|
|
270
|
-
|
|
271
|
-
await user.click(elevationHeaderButton)
|
|
272
|
-
expect(statusBox).toHaveTextContent(
|
|
273
|
-
'Sorted column: Elevation (order: ascending)'
|
|
274
|
-
)
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
test('uses custom ascending text when provided', async () => {
|
|
278
|
-
options.ascendingText = 'A to Z'
|
|
279
|
-
new MOJFrontend.SortableTable(options)
|
|
280
|
-
|
|
281
|
-
const nameHeaderButton = queryByRole(component, 'button', { name: 'Name' })
|
|
282
|
-
const statusBox = queryByRole(component.parentElement, 'status')
|
|
283
|
-
|
|
284
|
-
await user.click(nameHeaderButton)
|
|
285
|
-
await user.click(nameHeaderButton)
|
|
286
|
-
|
|
287
|
-
expect(statusBox).toHaveTextContent('Sort by Name (A to Z)')
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
test('uses custom descending text when provided', async () => {
|
|
291
|
-
options.descendingText = 'Z to A'
|
|
292
|
-
new MOJFrontend.SortableTable(options)
|
|
293
|
-
|
|
294
|
-
const nameHeaderButton = queryByRole(component, 'button', { name: 'Name' })
|
|
295
|
-
const statusBox = queryByRole(component.parentElement, 'status')
|
|
296
|
-
|
|
297
|
-
await user.click(nameHeaderButton)
|
|
298
|
-
|
|
299
|
-
expect(statusBox).toHaveTextContent('Sort by Name (Z to A)')
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
test('uses all custom options together', async () => {
|
|
303
|
-
options = {
|
|
304
|
-
table: component,
|
|
305
|
-
statusMessage: 'component sorted by %heading% in %direction% order',
|
|
306
|
-
ascendingText: 'lowest to highest',
|
|
307
|
-
descendingText: 'highest to lowest'
|
|
308
|
-
}
|
|
309
|
-
new MOJFrontend.SortableTable(options)
|
|
310
|
-
|
|
311
|
-
const elevationHeaderButton = queryByRole(component, 'button', {
|
|
312
|
-
name: 'Elevation'
|
|
313
|
-
})
|
|
314
|
-
const statusBox = queryByRole(component.parentElement, 'status')
|
|
315
|
-
|
|
316
|
-
await user.click(elevationHeaderButton)
|
|
317
|
-
expect(statusBox).toHaveTextContent(
|
|
318
|
-
'component sorted by Elevation in lowest to highest order'
|
|
319
|
-
)
|
|
320
|
-
|
|
321
|
-
await user.click(elevationHeaderButton)
|
|
322
|
-
expect(statusBox).toHaveTextContent(
|
|
323
|
-
'component sorted by Elevation in highest to lowest order'
|
|
324
|
-
)
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
test('allows reinitialization of component without duplicating functionality', () => {
|
|
328
|
-
const { component, options } = createComponent()
|
|
329
|
-
new MOJFrontend.SortableTable(options)
|
|
330
|
-
new MOJFrontend.SortableTable(options) // Initialize again
|
|
331
|
-
|
|
332
|
-
// Check that we don't have duplicate buttons in headers
|
|
333
|
-
const headers = component.querySelectorAll('th[aria-sort]')
|
|
334
|
-
headers.forEach((header) => {
|
|
335
|
-
const buttons = header.querySelectorAll('button')
|
|
336
|
-
expect(buttons).toHaveLength(1)
|
|
337
|
-
})
|
|
338
|
-
})
|
|
339
|
-
|
|
340
|
-
test('maintains original sort when reinitialized', async () => {
|
|
341
|
-
const { component, options } = createComponent()
|
|
342
|
-
new MOJFrontend.SortableTable(options)
|
|
343
|
-
|
|
344
|
-
const elevationHeaderButton = queryByRole(component, 'button', {
|
|
345
|
-
name: 'Elevation'
|
|
346
|
-
})
|
|
347
|
-
await user.click(elevationHeaderButton)
|
|
348
|
-
|
|
349
|
-
new MOJFrontend.SortableTable(options) // Reinitialize
|
|
350
|
-
|
|
351
|
-
const cells = component.querySelectorAll('tbody tr td:nth-child(2)')
|
|
352
|
-
const values = Array.from(cells).map((cell) =>
|
|
353
|
-
parseInt(cell.getAttribute('data-sort-value'))
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
expect(values).toEqual([5895, 6961, 8611, 8850])
|
|
357
|
-
expect(elevationHeaderButton.parentElement).toHaveAttribute(
|
|
358
|
-
'aria-sort',
|
|
359
|
-
'ascending'
|
|
360
|
-
)
|
|
361
|
-
})
|
|
362
|
-
})
|