@ons/design-system 50.0.1 → 53.0.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 (182) hide show
  1. package/README.md +35 -15
  2. package/components/access-code/_macro.njk +1 -1
  3. package/components/access-code/_macro.spec.js +162 -0
  4. package/components/access-code/uac.spec.js +26 -0
  5. package/components/accordion/_macro.spec.js +224 -0
  6. package/components/accordion/accordion.spec.js +134 -0
  7. package/components/address-input/_macro.njk +1 -1
  8. package/components/address-input/_macro.spec.js +465 -0
  9. package/components/address-input/autosuggest.address.js +5 -4
  10. package/components/address-input/autosuggest.address.setter.js +9 -3
  11. package/components/address-input/autosuggest.address.spec.js +733 -0
  12. package/components/address-output/_macro.njk +6 -6
  13. package/components/address-output/_macro.spec.js +122 -0
  14. package/components/autosuggest/_macro.njk +1 -1
  15. package/components/autosuggest/_macro.spec.js +229 -0
  16. package/components/autosuggest/autosuggest.helpers.js +2 -3
  17. package/components/autosuggest/autosuggest.helpers.spec.js +85 -0
  18. package/components/autosuggest/autosuggest.js +4 -2
  19. package/components/autosuggest/autosuggest.spec.js +625 -0
  20. package/components/autosuggest/autosuggest.ui.js +6 -2
  21. package/components/breadcrumbs/_macro.spec.js +129 -0
  22. package/components/button/_button.scss +75 -33
  23. package/components/button/_macro.njk +6 -6
  24. package/components/button/_macro.spec.js +446 -0
  25. package/components/button/button.spec.js +290 -0
  26. package/components/call-to-action/_macro.njk +3 -1
  27. package/components/call-to-action/_macro.spec.js +52 -0
  28. package/components/card/_macro.njk +26 -19
  29. package/components/card/_macro.spec.js +261 -0
  30. package/components/char-check-limit/_macro.spec.js +73 -0
  31. package/components/char-check-limit/character-check.spec.js +196 -0
  32. package/components/char-check-limit/character-limit.js +1 -1
  33. package/components/checkboxes/_checkbox-macro.spec.js +419 -0
  34. package/components/checkboxes/_macro.njk +1 -3
  35. package/components/checkboxes/_macro.spec.js +306 -0
  36. package/components/checkboxes/checkbox-with-autoselect.js +2 -1
  37. package/components/checkboxes/checkboxes.spec.js +208 -0
  38. package/components/code-highlight/_macro.spec.js +56 -0
  39. package/components/code-highlight/code-highlight.spec.js +18 -0
  40. package/components/collapsible/_macro.spec.js +204 -0
  41. package/components/collapsible/collapsible.js +2 -1
  42. package/components/collapsible/collapsible.spec.js +236 -0
  43. package/components/content-pagination/_macro.spec.js +199 -0
  44. package/components/cookies-banner/_macro.njk +1 -1
  45. package/components/cookies-banner/_macro.spec.js +171 -0
  46. package/components/cookies-banner/cookies-banner.spec.js +90 -0
  47. package/components/date-input/_macro.njk +6 -3
  48. package/components/date-input/_macro.spec.js +286 -0
  49. package/components/document-list/_macro.njk +3 -5
  50. package/components/document-list/_macro.spec.js +491 -0
  51. package/components/download-resources/download-resources.spec.js +540 -0
  52. package/components/duration/_macro.njk +7 -6
  53. package/components/duration/_macro.spec.js +251 -0
  54. package/components/error/_macro.spec.js +97 -0
  55. package/components/external-link/_macro.njk +5 -2
  56. package/components/external-link/_macro.spec.js +77 -0
  57. package/components/feedback/_macro.njk +5 -3
  58. package/components/feedback/_macro.spec.js +122 -0
  59. package/components/field/_macro.njk +2 -2
  60. package/components/field/_macro.spec.js +97 -0
  61. package/components/fieldset/_macro.njk +3 -3
  62. package/components/fieldset/_macro.spec.js +173 -0
  63. package/components/footer/_footer.scss +19 -4
  64. package/components/footer/_macro.njk +106 -137
  65. package/components/footer/_macro.spec.js +678 -0
  66. package/components/header/_header.scss +65 -46
  67. package/components/header/_macro.njk +173 -121
  68. package/components/header/_macro.spec.js +618 -0
  69. package/components/hero/_hero.scss +30 -143
  70. package/components/hero/_macro.njk +12 -23
  71. package/components/hero/_macro.spec.js +218 -0
  72. package/components/icons/_macro.njk +258 -30
  73. package/components/icons/_macro.spec.js +140 -0
  74. package/components/images/_macro.njk +1 -1
  75. package/components/images/_macro.spec.js +121 -0
  76. package/components/input/_input-type.scss +12 -5
  77. package/components/input/_input.scss +8 -0
  78. package/components/input/_macro.njk +4 -5
  79. package/components/input/_macro.spec.js +658 -0
  80. package/components/label/_macro.spec.js +189 -0
  81. package/components/language-selector/_macro.njk +1 -1
  82. package/components/language-selector/_macro.spec.js +137 -0
  83. package/components/lists/_list.scss +4 -0
  84. package/components/lists/_macro.njk +4 -7
  85. package/components/lists/_macro.spec.js +618 -0
  86. package/components/message/_macro.spec.js +137 -0
  87. package/components/message-list/_macro.njk +7 -7
  88. package/components/message-list/_macro.spec.js +159 -0
  89. package/components/metadata/_macro.spec.js +167 -0
  90. package/components/modal/_macro.njk +6 -6
  91. package/components/modal/_macro.spec.js +87 -0
  92. package/components/modal/modal.spec.js +59 -0
  93. package/components/mutually-exclusive/_macro.njk +2 -2
  94. package/components/mutually-exclusive/_macro.spec.js +184 -0
  95. package/components/mutually-exclusive/mutually-exclusive.checkboxes.spec.js +203 -0
  96. package/components/mutually-exclusive/mutually-exclusive.date.spec.js +142 -0
  97. package/components/mutually-exclusive/mutually-exclusive.duration.spec.js +141 -0
  98. package/components/mutually-exclusive/mutually-exclusive.email.spec.js +117 -0
  99. package/components/mutually-exclusive/mutually-exclusive.multiple-options.checkboxes.spec.js +213 -0
  100. package/components/mutually-exclusive/mutually-exclusive.number.spec.js +125 -0
  101. package/components/mutually-exclusive/mutually-exclusive.textarea.spec.js +131 -0
  102. package/components/navigation/_macro.njk +45 -38
  103. package/components/navigation/_macro.spec.js +329 -0
  104. package/components/navigation/_navigation.scss +20 -4
  105. package/components/navigation/navigation.dom.js +1 -1
  106. package/components/navigation/navigation.spec.js +232 -0
  107. package/components/pagination/_macro.njk +1 -1
  108. package/components/pagination/_macro.spec.js +411 -0
  109. package/components/panel/_macro.njk +6 -6
  110. package/components/panel/_macro.spec.js +423 -0
  111. package/components/password/_macro.spec.js +137 -0
  112. package/components/password/password.spec.js +40 -0
  113. package/components/phase-banner/_macro.spec.js +73 -0
  114. package/components/promotional-banner/_macro.spec.js +97 -0
  115. package/components/question/_macro.njk +16 -22
  116. package/components/question/_macro.spec.js +309 -0
  117. package/components/quote/_macro.spec.js +81 -0
  118. package/components/radios/_macro.njk +3 -6
  119. package/components/radios/_macro.spec.js +575 -0
  120. package/components/radios/radios.spec.js +180 -0
  121. package/components/related-content/_macro.njk +14 -21
  122. package/components/related-content/_macro.spec.js +133 -0
  123. package/components/related-content/_section-macro.njk +10 -0
  124. package/components/related-content/_section-macro.spec.js +43 -0
  125. package/components/relationships/_macro.spec.js +108 -0
  126. package/components/relationships/relationships.spec.js +84 -0
  127. package/components/reply/_macro.njk +2 -2
  128. package/components/reply/_macro.spec.js +69 -0
  129. package/components/reply/reply.spec.js +78 -0
  130. package/components/search/_macro.njk +14 -12
  131. package/components/search/_macro.spec.js +44 -0
  132. package/components/search/_search.scss +7 -7
  133. package/components/section-navigation/_macro.njk +7 -2
  134. package/components/section-navigation/_macro.spec.js +206 -0
  135. package/components/select/_macro.njk +3 -3
  136. package/components/select/_macro.spec.js +203 -0
  137. package/components/select/select.spec.js +56 -0
  138. package/components/share-page/_macro.njk +6 -4
  139. package/components/share-page/_macro.spec.js +110 -0
  140. package/components/skip-to-content/_macro.spec.js +57 -0
  141. package/components/skip-to-content/skip-to-content.spec.js +44 -0
  142. package/components/status/_macro.spec.js +77 -0
  143. package/components/summary/_macro.njk +5 -5
  144. package/components/summary/_macro.spec.js +472 -0
  145. package/components/table/_macro.njk +2 -2
  146. package/components/table/_macro.spec.js +557 -0
  147. package/components/table/table.spec.js +155 -0
  148. package/components/table-of-contents/_macro.njk +35 -35
  149. package/components/table-of-contents/_macro.spec.js +178 -0
  150. package/components/table-of-contents/toc.js +29 -25
  151. package/components/table-of-contents/toc.spec.js +61 -0
  152. package/components/tabs/_macro.njk +1 -1
  153. package/components/tabs/_macro.spec.js +79 -0
  154. package/components/tabs/tabs.spec.js +162 -0
  155. package/components/text-indent/_macro.spec.js +52 -0
  156. package/components/textarea/_macro.njk +5 -3
  157. package/components/textarea/_macro.spec.js +300 -0
  158. package/components/textarea/textarea.spec.js +98 -0
  159. package/components/timeline/_macro.njk +3 -3
  160. package/components/timeline/_macro.spec.js +81 -0
  161. package/components/timeout-modal/_macro.spec.js +68 -0
  162. package/components/timeout-modal/timeout-modal.spec.js +226 -0
  163. package/components/timeout-panel/_macro.njk +0 -1
  164. package/components/timeout-panel/_macro.spec.js +54 -0
  165. package/components/timeout-panel/timeout-panel.dom.js +1 -2
  166. package/components/timeout-panel/timeout-panel.spec.js +161 -0
  167. package/components/upload/_macro.spec.js +75 -0
  168. package/components/video/_macro.spec.js +34 -0
  169. package/css/census.css +3 -1
  170. package/css/ids.css +2 -0
  171. package/css/main.css +1 -1
  172. package/img/dummy-brand-logo.svg +1 -0
  173. package/js/cookies-settings.spec.js +154 -0
  174. package/layout/_template.njk +7 -4
  175. package/package.json +10 -23
  176. package/scripts/main.es5.js +2 -2
  177. package/scripts/main.js +1 -1
  178. package/scss/ids.scss +2 -0
  179. package/scss/settings/_census.scss +141 -0
  180. package/scss/settings/_ids.scss +48 -0
  181. package/scss/utilities/_margin.scss +1 -0
  182. package/scss/vars/_colors.scss +5 -2
@@ -0,0 +1,658 @@
1
+ /** @jest-environment jsdom */
2
+
3
+ import * as cheerio from 'cheerio';
4
+
5
+ import axe from '../../tests/helpers/axe';
6
+ import { renderComponent, templateFaker } from '../../tests/helpers/rendering';
7
+
8
+ const EXAMPLE_INPUT_MINIMAL = {
9
+ id: 'example-id',
10
+ name: 'example-name',
11
+ };
12
+
13
+ const EXAMPLE_INPUT_WITH_LABEL = {
14
+ ...EXAMPLE_INPUT_MINIMAL,
15
+ label: {
16
+ id: 'example-input-label',
17
+ text: 'Example input label',
18
+ classes: 'extra-label-class',
19
+ description: 'Example input label description',
20
+ attributes: { a: 42 },
21
+ inline: false,
22
+ },
23
+ accessiblePlaceholder: true,
24
+ };
25
+
26
+ const EXAMPLE_INPUT_WITH_ERROR = {
27
+ ...EXAMPLE_INPUT_WITH_LABEL,
28
+ error: {
29
+ id: 'feedback-error',
30
+ text: 'Enter your feedback',
31
+ },
32
+ };
33
+
34
+ const EXAMPLE_WITH_SEARCH = {
35
+ ...EXAMPLE_INPUT_MINIMAL,
36
+ accessiblePlaceholder: true,
37
+ searchButton: {
38
+ type: 'button',
39
+ text: 'Search for address',
40
+ id: 'search-for-address',
41
+ attributes: { a: 42 },
42
+ classes: 'extra-search-button-class',
43
+ iconType: 'search',
44
+ },
45
+ };
46
+
47
+ const EXAMPLE_INPUT_WITH_CHARACTER_LIMIT = {
48
+ ...EXAMPLE_INPUT_MINIMAL,
49
+ minLength: 10,
50
+ maxLength: 200,
51
+ charCheckLimit: {
52
+ limit: 200,
53
+ charCountSingular: 'You have {x} character remaining',
54
+ charCountPlural: 'You have {x} characters remaining',
55
+ charCountOverLimitSingular: '{x} character too many',
56
+ charCountOverLimitPlural: '{x} characters too many',
57
+ },
58
+ };
59
+
60
+ const EXAMPLE_INPUT_WITH_MUTUALLY_EXCLUSIVE_WITH_ERROR = {
61
+ ...EXAMPLE_INPUT_WITH_ERROR,
62
+ dontWrap: true,
63
+ mutuallyExclusive: {
64
+ or: 'Or',
65
+ deselectMessage: 'Selecting this will clear your feedback',
66
+ deselectGroupAdjective: 'cleared',
67
+ deselectExclusiveOptionAdjective: 'deselected',
68
+ exclusiveOptions: [
69
+ {
70
+ id: 'feedback-exclusive-option',
71
+ name: 'no-feedback',
72
+ value: 'no-feedback',
73
+ label: {
74
+ text: 'I dont want to provide feedback',
75
+ },
76
+ },
77
+ ],
78
+ },
79
+ };
80
+
81
+ describe('macro: input', () => {
82
+ it('has the provided `id` attribute', () => {
83
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
84
+
85
+ expect($('.ons-input').attr('id')).toBe('example-id');
86
+ });
87
+
88
+ it('has the provided `name` attribute', () => {
89
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
90
+
91
+ expect($('.ons-input').attr('name')).toBe('example-name');
92
+ });
93
+
94
+ it('has additionally provided `attributes`', () => {
95
+ const $ = cheerio.load(
96
+ renderComponent('input', {
97
+ ...EXAMPLE_INPUT_MINIMAL,
98
+ attributes: { a: '123', b: '456' },
99
+ }),
100
+ );
101
+
102
+ expect($('.ons-input').attr('a')).toBe('123');
103
+ expect($('.ons-input').attr('b')).toBe('456');
104
+ });
105
+
106
+ it('outputs number type in a way that works with more browsers', () => {
107
+ const $ = cheerio.load(
108
+ renderComponent('input', {
109
+ ...EXAMPLE_INPUT_MINIMAL,
110
+ type: 'number',
111
+ }),
112
+ );
113
+
114
+ expect($('.ons-input').attr('type')).toBe('text');
115
+ expect($('.ons-input').attr('pattern')).toBe('[0-9]*');
116
+ expect($('.ons-input').attr('inputmode')).toBe('numeric');
117
+ });
118
+
119
+ it('has additionally provided style classes', () => {
120
+ const $ = cheerio.load(
121
+ renderComponent('input', {
122
+ ...EXAMPLE_INPUT_MINIMAL,
123
+ classes: 'extra-class another-extra-class',
124
+ }),
125
+ );
126
+
127
+ expect($('.ons-input').hasClass('extra-class')).toBe(true);
128
+ expect($('.ons-input').hasClass('another-extra-class')).toBe(true);
129
+ });
130
+
131
+ it('does not have "placeholder" modifier', () => {
132
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
133
+
134
+ expect($('.ons-input').hasClass('ons-input--placeholder')).toBe(false);
135
+ });
136
+
137
+ it('has "placeholder" modifier when `accessiblePlaceholder` is provided', () => {
138
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_LABEL));
139
+
140
+ expect($('.ons-input').hasClass('ons-input--placeholder')).toBe(true);
141
+ });
142
+
143
+ it('does not have `placeholder` attribute', () => {
144
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
145
+
146
+ expect($('.ons-input').attr('placeholder')).toBeUndefined();
147
+ });
148
+
149
+ it('has `placeholder` attribute when `placeholder` is provided', () => {
150
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_LABEL));
151
+
152
+ expect($('.ons-input').attr('placeholder')).toBe('Example input label');
153
+ });
154
+
155
+ it('does not have `min` attribute', () => {
156
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
157
+
158
+ expect($('.ons-input').attr('min')).toBeUndefined();
159
+ });
160
+
161
+ it('has `min` attribute when `min` is provided', () => {
162
+ const $ = cheerio.load(
163
+ renderComponent('input', {
164
+ ...EXAMPLE_INPUT_MINIMAL,
165
+ min: 10,
166
+ }),
167
+ );
168
+
169
+ expect($('.ons-input').attr('min')).toBe('10');
170
+ });
171
+
172
+ it('does not have `max` attribute', () => {
173
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
174
+
175
+ expect($('.ons-input').attr('max')).toBeUndefined();
176
+ });
177
+
178
+ it('has `max` attribute when `max` is provided', () => {
179
+ const $ = cheerio.load(
180
+ renderComponent('input', {
181
+ ...EXAMPLE_INPUT_MINIMAL,
182
+ max: 100,
183
+ }),
184
+ );
185
+
186
+ expect($('.ons-input').attr('max')).toBe('100');
187
+ });
188
+
189
+ it('does not have `value` attribute', () => {
190
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
191
+
192
+ expect($('.ons-input').attr('value')).toBeUndefined();
193
+ });
194
+
195
+ it('has `value` attribute when `value` is provided', () => {
196
+ const $ = cheerio.load(
197
+ renderComponent('input', {
198
+ ...EXAMPLE_INPUT_MINIMAL,
199
+ value: '100',
200
+ }),
201
+ );
202
+
203
+ expect($('.ons-input').attr('value')).toBe('100');
204
+ });
205
+
206
+ it('does not have `accept` attribute', () => {
207
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
208
+
209
+ expect($('.ons-input').attr('accept')).toBeUndefined();
210
+ });
211
+
212
+ it('has `accept` attribute when `accept` is provided', () => {
213
+ const $ = cheerio.load(
214
+ renderComponent('input', {
215
+ ...EXAMPLE_INPUT_MINIMAL,
216
+ accept: 'image/*',
217
+ }),
218
+ );
219
+
220
+ expect($('.ons-input').attr('accept')).toBe('image/*');
221
+ });
222
+
223
+ it('does not have `autocomplete` attribute', () => {
224
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
225
+
226
+ expect($('.ons-input').attr('autocomplete')).toBeUndefined();
227
+ });
228
+
229
+ it('has `autocomplete` attribute when `autocomplete` is provided', () => {
230
+ const $ = cheerio.load(
231
+ renderComponent('input', {
232
+ ...EXAMPLE_INPUT_MINIMAL,
233
+ autocomplete: 'on',
234
+ }),
235
+ );
236
+
237
+ expect($('.ons-input').attr('autocomplete')).toBe('on');
238
+ });
239
+
240
+ it('does not have `required` attribute', () => {
241
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_MINIMAL));
242
+
243
+ expect($('.ons-input').attr('required')).toBeUndefined();
244
+ });
245
+
246
+ it('has `required` attribute when `required` is provided', () => {
247
+ const $ = cheerio.load(
248
+ renderComponent('input', {
249
+ ...EXAMPLE_INPUT_MINIMAL,
250
+ required: true,
251
+ }),
252
+ );
253
+
254
+ expect($('.ons-input').attr('required')).toBe('required');
255
+ });
256
+
257
+ it.each([['email'], ['tel'], ['text']])('outputs `type` attribute of "%s"', type => {
258
+ const $ = cheerio.load(
259
+ renderComponent('input', {
260
+ ...EXAMPLE_INPUT_MINIMAL,
261
+ type,
262
+ }),
263
+ );
264
+
265
+ expect($('.ons-input').attr('type')).toBe(type);
266
+ expect($('.ons-input').attr('pattern')).toBeUndefined();
267
+ expect($('.ons-input').attr('inputmode')).toBeUndefined();
268
+ });
269
+
270
+ it.each([
271
+ ['number', 10, 'ons-input-number--w-10'],
272
+ ['tel', 20, 'ons-input-number--w-20'],
273
+ ])('adds class "ons-input-number" when `type` is "%s"', (type, width, expectedClass) => {
274
+ const $ = cheerio.load(
275
+ renderComponent('input', {
276
+ ...EXAMPLE_INPUT_MINIMAL,
277
+ type,
278
+ width,
279
+ }),
280
+ );
281
+
282
+ expect($('.ons-input').hasClass(expectedClass)).toBe(true);
283
+ });
284
+
285
+ describe('listeners', () => {
286
+ it('renders each listener', () => {
287
+ const $ = cheerio.load(
288
+ renderComponent('input', {
289
+ ...EXAMPLE_INPUT_MINIMAL,
290
+ listeners: {
291
+ click: `alert('Input was clicked')`,
292
+ keypress: `alert('Key was pressed')`,
293
+ },
294
+ }),
295
+ );
296
+
297
+ const script = $('script').html();
298
+ expect(script).toContain(
299
+ `document.getElementById("example-id").addEventListener('click', function(){ alert('Input was clicked') });`,
300
+ );
301
+ expect(script).toContain(
302
+ `document.getElementById("example-id").addEventListener('keypress', function(){ alert('Key was pressed') });`,
303
+ );
304
+ });
305
+ });
306
+
307
+ it('renders field component', () => {
308
+ const faker = templateFaker();
309
+ const fieldSpy = faker.spy('field');
310
+
311
+ faker.renderComponent('input', {
312
+ ...EXAMPLE_INPUT_WITH_ERROR,
313
+ fieldId: 'example-field-id',
314
+ fieldClasses: 'extra-field-class',
315
+ dontWrap: true,
316
+ });
317
+
318
+ expect(fieldSpy.occurrences).toContainEqual({
319
+ id: 'example-field-id',
320
+ classes: 'extra-field-class',
321
+ dontWrap: true,
322
+ error: EXAMPLE_INPUT_WITH_ERROR.error,
323
+ inline: false,
324
+ });
325
+ });
326
+
327
+ describe('label', () => {
328
+ it('does not output a label when `label` is not provided', () => {
329
+ const faker = templateFaker();
330
+ const labelSpy = faker.spy('label');
331
+
332
+ faker.renderComponent('input', EXAMPLE_INPUT_MINIMAL);
333
+
334
+ expect(labelSpy.occurrences.length).toBe(0);
335
+ });
336
+
337
+ it('outputs a label when `label` is provided', () => {
338
+ const faker = templateFaker();
339
+ const labelSpy = faker.spy('label');
340
+
341
+ faker.renderComponent('input', EXAMPLE_INPUT_WITH_LABEL);
342
+
343
+ expect(labelSpy.occurrences).toContainEqual({
344
+ for: 'example-id',
345
+ id: 'example-input-label',
346
+ text: 'Example input label',
347
+ classes: 'extra-label-class',
348
+ description: 'Example input label description',
349
+ attributes: { a: 42 },
350
+ inline: false,
351
+ accessiblePlaceholder: true,
352
+ });
353
+ });
354
+
355
+ it('outputs `aria-describedby` attribute referencing the label', () => {
356
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_LABEL));
357
+
358
+ expect($('.ons-input').attr('aria-describedby')).toBe('example-input-label-description-hint');
359
+ });
360
+
361
+ it('outputs a default `aria-describedby` attribute referencing the label when label does not have an `id`', () => {
362
+ const $ = cheerio.load(
363
+ renderComponent('input', {
364
+ ...EXAMPLE_INPUT_MINIMAL,
365
+ label: {
366
+ text: 'Example input label',
367
+ description: 'Example input label description',
368
+ },
369
+ }),
370
+ );
371
+
372
+ expect($('.ons-input').attr('aria-describedby')).toBe('description-hint');
373
+ });
374
+ });
375
+
376
+ describe('prefix and suffix', () => {
377
+ it('adds `aria-labelledby` attribute when `prefix` is provided', () => {
378
+ const $ = cheerio.load(
379
+ renderComponent('input', {
380
+ ...EXAMPLE_INPUT_MINIMAL,
381
+ prefix: {
382
+ id: 'example-prefix-id',
383
+ title: 'Example prefix title',
384
+ },
385
+ }),
386
+ );
387
+
388
+ expect($('.ons-input').attr('aria-labelledby')).toBe('example-prefix-id');
389
+ });
390
+
391
+ it('renders prefix element from `prefix.title`', () => {
392
+ const $ = cheerio.load(
393
+ renderComponent('input', {
394
+ ...EXAMPLE_INPUT_MINIMAL,
395
+ prefix: {
396
+ id: 'example-prefix-id',
397
+ title: 'Example prefix title',
398
+ },
399
+ }),
400
+ );
401
+
402
+ expect($('.ons-input-type--prefix .ons-js-input-abbr').attr('id')).toBe('example-prefix-id');
403
+ expect($('.ons-input-type--prefix .ons-js-input-abbr').attr('title')).toBe('Example prefix title');
404
+ expect(
405
+ $('.ons-input-type--prefix .ons-js-input-abbr')
406
+ .text()
407
+ .trim(),
408
+ ).toBe('Example prefix title');
409
+ });
410
+
411
+ it('renders prefix element from `prefix.text`', () => {
412
+ const $ = cheerio.load(
413
+ renderComponent('input', {
414
+ ...EXAMPLE_INPUT_MINIMAL,
415
+ prefix: {
416
+ id: 'example-prefix-id',
417
+ title: 'Example prefix title',
418
+ text: 'Example prefix text',
419
+ },
420
+ }),
421
+ );
422
+
423
+ expect($('.ons-input-type--prefix .ons-js-input-abbr').attr('id')).toBe('example-prefix-id');
424
+ expect($('.ons-input-type--prefix .ons-js-input-abbr').attr('title')).toBe('Example prefix title');
425
+ expect(
426
+ $('.ons-input-type--prefix .ons-js-input-abbr')
427
+ .text()
428
+ .trim(),
429
+ ).toBe('Example prefix text');
430
+ });
431
+
432
+ it('adds `aria-labelledby` attribute when `suffix` is provided', () => {
433
+ const $ = cheerio.load(
434
+ renderComponent('input', {
435
+ ...EXAMPLE_INPUT_MINIMAL,
436
+ suffix: {
437
+ id: 'example-suffix-id',
438
+ title: 'Example suffix title',
439
+ },
440
+ }),
441
+ );
442
+
443
+ expect($('.ons-input').attr('aria-labelledby')).toBe('example-suffix-id');
444
+ });
445
+
446
+ it('renders suffix element from `suffix.title`', () => {
447
+ const $ = cheerio.load(
448
+ renderComponent('input', {
449
+ ...EXAMPLE_INPUT_MINIMAL,
450
+ suffix: {
451
+ id: 'example-suffix-id',
452
+ title: 'Example suffix title',
453
+ },
454
+ }),
455
+ );
456
+
457
+ expect($('.ons-js-input-abbr').attr('id')).toBe('example-suffix-id');
458
+ expect($('.ons-js-input-abbr').attr('title')).toBe('Example suffix title');
459
+ expect(
460
+ $('.ons-js-input-abbr')
461
+ .text()
462
+ .trim(),
463
+ ).toBe('Example suffix title');
464
+ });
465
+
466
+ it('renders suffix element from `suffix.text`', () => {
467
+ const $ = cheerio.load(
468
+ renderComponent('input', {
469
+ ...EXAMPLE_INPUT_MINIMAL,
470
+ suffix: {
471
+ id: 'example-suffix-id',
472
+ title: 'Example suffix title',
473
+ text: 'Example suffix text',
474
+ },
475
+ }),
476
+ );
477
+
478
+ expect($('.ons-js-input-abbr').attr('id')).toBe('example-suffix-id');
479
+ expect($('.ons-js-input-abbr').attr('title')).toBe('Example suffix title');
480
+ expect(
481
+ $('.ons-js-input-abbr')
482
+ .text()
483
+ .trim(),
484
+ ).toBe('Example suffix text');
485
+ });
486
+ });
487
+
488
+ describe('search', () => {
489
+ it('renders `search` component', () => {
490
+ const faker = templateFaker();
491
+ const searchSpy = faker.spy('search');
492
+
493
+ faker.renderComponent('input', EXAMPLE_WITH_SEARCH);
494
+
495
+ expect(searchSpy.occurrences[0]).toEqual({
496
+ accessiblePlaceholder: true,
497
+ searchButton: {
498
+ type: 'button',
499
+ text: 'Search for address',
500
+ id: 'search-for-address',
501
+ attributes: { a: 42 },
502
+ classes: 'extra-search-button-class',
503
+ iconType: 'search',
504
+ },
505
+ });
506
+ });
507
+
508
+ it.each('outputs `type` attribute of "search"', () => {
509
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_WITH_SEARCH));
510
+
511
+ expect($('.ons-input').attr('type')).toBe('search');
512
+ expect($('.ons-input').attr('pattern')).toBeUndefined();
513
+ expect($('.ons-input').attr('inputmode')).toBeUndefined();
514
+ });
515
+
516
+ it('has the "ons-search__input" class', () => {
517
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_WITH_SEARCH));
518
+
519
+ expect($('.ons-input').hasClass('ons-search__input')).toBe(true);
520
+ });
521
+ });
522
+
523
+ describe('with character limit', () => {
524
+ it('has the provided minimum length', () => {
525
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_CHARACTER_LIMIT));
526
+
527
+ expect($('.ons-input').attr('minlength')).toBe('10');
528
+ });
529
+
530
+ it('has the provided maximum length', () => {
531
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_CHARACTER_LIMIT));
532
+
533
+ expect($('.ons-input').attr('maxlength')).toBe('200');
534
+ });
535
+
536
+ it('does not have `data-char-check-countdown` attribute when `charcheckCountdown` is not provided', () => {
537
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_CHARACTER_LIMIT));
538
+
539
+ expect($('.ons-input').attr('data-char-check-countdown')).toBe(undefined);
540
+ });
541
+
542
+ it('has `data-char-check-countdown` attribute when `charcheckCountdown` is true', () => {
543
+ const $ = cheerio.load(
544
+ renderComponent('input', {
545
+ ...EXAMPLE_INPUT_WITH_CHARACTER_LIMIT,
546
+ charCheckLimit: {
547
+ ...EXAMPLE_INPUT_WITH_CHARACTER_LIMIT.charCheckLimit,
548
+ charcheckCountdown: true,
549
+ },
550
+ }),
551
+ );
552
+
553
+ expect($('.ons-input').attr('data-char-check-countdown')).toBe('true');
554
+ });
555
+
556
+ it('has data attribute which references the character limit component', () => {
557
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_CHARACTER_LIMIT));
558
+
559
+ expect($('.ons-input').attr('data-char-check-ref')).toBe('example-id-check-remaining');
560
+ });
561
+
562
+ it('has data attribute which defines limit for character check', () => {
563
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_CHARACTER_LIMIT));
564
+
565
+ expect($('.ons-input').attr('data-char-check-num')).toBe('200');
566
+ });
567
+
568
+ it('has `aria-describedby` attribute which references the character limit component', () => {
569
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_CHARACTER_LIMIT));
570
+
571
+ expect($('.ons-input').attr('aria-describedby')).toBe('example-id-check-remaining');
572
+ });
573
+
574
+ it('renders character limit component', () => {
575
+ const faker = templateFaker();
576
+ const charCheckLimitSpy = faker.spy('char-check-limit');
577
+
578
+ faker.renderComponent('input', EXAMPLE_INPUT_WITH_CHARACTER_LIMIT);
579
+
580
+ expect(charCheckLimitSpy.occurrences).toContainEqual({
581
+ id: 'example-id-check',
582
+ limit: 200,
583
+ type: 'check',
584
+ charCountSingular: 'You have {x} character remaining',
585
+ charCountPlural: 'You have {x} characters remaining',
586
+ charCountOverLimitSingular: '{x} character too many',
587
+ charCountOverLimitPlural: '{x} characters too many',
588
+ });
589
+ });
590
+ });
591
+
592
+ describe('with error', () => {
593
+ it('has the `error` modifier class', () => {
594
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_ERROR));
595
+
596
+ expect($('.ons-input').hasClass('ons-input--error')).toBe(true);
597
+ });
598
+ });
599
+
600
+ describe('with post textbox link', () => {
601
+ it('renders the expected link', () => {
602
+ const $ = cheerio.load(
603
+ renderComponent('input', {
604
+ ...EXAMPLE_INPUT_MINIMAL,
605
+ postTextboxLinkUrl: 'https://example.com/link',
606
+ postTextboxLinkText: 'Example link',
607
+ }),
608
+ );
609
+
610
+ expect($('a.ons-input__post-link').attr('href')).toBe('https://example.com/link');
611
+ expect(
612
+ $('a.ons-input__post-link')
613
+ .text()
614
+ .trim(),
615
+ ).toBe('Example link');
616
+ });
617
+ });
618
+
619
+ describe('mutually exclusive', () => {
620
+ it('has the `ons-js-exclusive-group-item` class', () => {
621
+ const $ = cheerio.load(renderComponent('input', EXAMPLE_INPUT_WITH_MUTUALLY_EXCLUSIVE_WITH_ERROR));
622
+
623
+ expect($('.ons-input').hasClass('ons-js-exclusive-group-item')).toBe(true);
624
+ });
625
+
626
+ it('renders mutually exclusive component', () => {
627
+ const faker = templateFaker();
628
+ const mutuallyExclusiveSpy = faker.spy('mutually-exclusive');
629
+
630
+ faker.renderComponent('input', {
631
+ ...EXAMPLE_INPUT_WITH_MUTUALLY_EXCLUSIVE_WITH_ERROR,
632
+ fieldId: 'example-field-id',
633
+ fieldClasses: 'extra-field-class',
634
+ legend: 'Legend text',
635
+ legendClasses: 'extra-legend-class',
636
+ description: 'Example description text',
637
+ legendIsQuestionTitle: true,
638
+ autosuggestResults: 'RESULTS',
639
+ });
640
+
641
+ expect(mutuallyExclusiveSpy.occurrences).toContainEqual({
642
+ id: 'example-field-id',
643
+ legend: 'Legend text',
644
+ legendClasses: 'extra-legend-class ons-js-input-legend',
645
+ description: 'Example description text',
646
+ dontWrap: true,
647
+ legendIsQuestionTitle: true,
648
+ exclusiveOptions: EXAMPLE_INPUT_WITH_MUTUALLY_EXCLUSIVE_WITH_ERROR.mutuallyExclusive.exclusiveOptions,
649
+ or: 'Or',
650
+ deselectMessage: 'Selecting this will clear your feedback',
651
+ deselectGroupAdjective: 'cleared',
652
+ deselectExclusiveOptionAdjective: 'deselected',
653
+ error: EXAMPLE_INPUT_WITH_MUTUALLY_EXCLUSIVE_WITH_ERROR.error,
654
+ autosuggestResults: 'RESULTS',
655
+ });
656
+ });
657
+ });
658
+ });