@ons/design-system 50.0.0 → 52.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 (166) 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/_macro.njk +5 -5
  23. package/components/button/_macro.spec.js +446 -0
  24. package/components/button/button.spec.js +290 -0
  25. package/components/call-to-action/_macro.njk +3 -1
  26. package/components/call-to-action/_macro.spec.js +52 -0
  27. package/components/card/_macro.njk +26 -19
  28. package/components/card/_macro.spec.js +261 -0
  29. package/components/char-check-limit/_macro.spec.js +73 -0
  30. package/components/char-check-limit/character-check.spec.js +196 -0
  31. package/components/char-check-limit/character-limit.js +1 -1
  32. package/components/checkboxes/_checkbox-macro.spec.js +419 -0
  33. package/components/checkboxes/_macro.njk +1 -3
  34. package/components/checkboxes/_macro.spec.js +306 -0
  35. package/components/checkboxes/checkbox-with-autoselect.js +2 -1
  36. package/components/checkboxes/checkboxes.spec.js +208 -0
  37. package/components/code-highlight/_macro.spec.js +56 -0
  38. package/components/code-highlight/code-highlight.spec.js +18 -0
  39. package/components/collapsible/_macro.spec.js +204 -0
  40. package/components/collapsible/collapsible.js +2 -1
  41. package/components/collapsible/collapsible.spec.js +236 -0
  42. package/components/content-pagination/_macro.spec.js +199 -0
  43. package/components/cookies-banner/_macro.njk +1 -1
  44. package/components/cookies-banner/_macro.spec.js +171 -0
  45. package/components/cookies-banner/cookies-banner.spec.js +90 -0
  46. package/components/date-input/_macro.njk +6 -3
  47. package/components/date-input/_macro.spec.js +286 -0
  48. package/components/document-list/_macro.njk +3 -5
  49. package/components/document-list/_macro.spec.js +491 -0
  50. package/components/download-resources/download-resources.spec.js +540 -0
  51. package/components/duration/_macro.njk +7 -6
  52. package/components/duration/_macro.spec.js +251 -0
  53. package/components/error/_macro.spec.js +97 -0
  54. package/components/external-link/_macro.spec.js +60 -0
  55. package/components/feedback/_macro.njk +5 -3
  56. package/components/feedback/_macro.spec.js +122 -0
  57. package/components/field/_macro.njk +2 -2
  58. package/components/field/_macro.spec.js +97 -0
  59. package/components/fieldset/_macro.njk +3 -3
  60. package/components/fieldset/_macro.spec.js +173 -0
  61. package/components/footer/_macro.njk +12 -49
  62. package/components/footer/_macro.spec.js +549 -0
  63. package/components/header/_macro.njk +3 -3
  64. package/components/header/_macro.spec.js +562 -0
  65. package/components/hero/_hero.scss +0 -3
  66. package/components/hero/_macro.njk +4 -4
  67. package/components/hero/_macro.spec.js +224 -0
  68. package/components/icons/_macro.njk +15 -15
  69. package/components/icons/_macro.spec.js +140 -0
  70. package/components/images/_macro.njk +1 -1
  71. package/components/images/_macro.spec.js +121 -0
  72. package/components/input/_input-type.scss +12 -5
  73. package/components/input/_macro.njk +4 -5
  74. package/components/input/_macro.spec.js +658 -0
  75. package/components/label/_macro.spec.js +189 -0
  76. package/components/language-selector/_macro.spec.js +129 -0
  77. package/components/lists/_list.scss +4 -0
  78. package/components/lists/_macro.njk +4 -7
  79. package/components/lists/_macro.spec.js +618 -0
  80. package/components/message/_macro.spec.js +137 -0
  81. package/components/message-list/_macro.njk +7 -7
  82. package/components/message-list/_macro.spec.js +159 -0
  83. package/components/metadata/_macro.spec.js +167 -0
  84. package/components/modal/_macro.njk +6 -6
  85. package/components/modal/_macro.spec.js +87 -0
  86. package/components/modal/modal.js +0 -16
  87. package/components/modal/modal.spec.js +59 -0
  88. package/components/mutually-exclusive/_macro.njk +2 -2
  89. package/components/mutually-exclusive/_macro.spec.js +184 -0
  90. package/components/mutually-exclusive/mutually-exclusive.checkboxes.spec.js +203 -0
  91. package/components/mutually-exclusive/mutually-exclusive.date.spec.js +142 -0
  92. package/components/mutually-exclusive/mutually-exclusive.duration.spec.js +141 -0
  93. package/components/mutually-exclusive/mutually-exclusive.email.spec.js +117 -0
  94. package/components/mutually-exclusive/mutually-exclusive.multiple-options.checkboxes.spec.js +213 -0
  95. package/components/mutually-exclusive/mutually-exclusive.number.spec.js +125 -0
  96. package/components/mutually-exclusive/mutually-exclusive.textarea.spec.js +131 -0
  97. package/components/navigation/_macro.njk +6 -6
  98. package/components/navigation/_macro.spec.js +327 -0
  99. package/components/navigation/navigation.dom.js +1 -1
  100. package/components/navigation/navigation.spec.js +232 -0
  101. package/components/pagination/_macro.njk +1 -1
  102. package/components/pagination/_macro.spec.js +411 -0
  103. package/components/panel/_macro.njk +6 -6
  104. package/components/panel/_macro.spec.js +423 -0
  105. package/components/password/_macro.spec.js +137 -0
  106. package/components/password/password.spec.js +40 -0
  107. package/components/phase-banner/_macro.spec.js +73 -0
  108. package/components/promotional-banner/_macro.spec.js +97 -0
  109. package/components/question/_macro.njk +16 -22
  110. package/components/question/_macro.spec.js +309 -0
  111. package/components/quote/_macro.spec.js +81 -0
  112. package/components/radios/_macro.njk +3 -6
  113. package/components/radios/_macro.spec.js +575 -0
  114. package/components/radios/radios.spec.js +180 -0
  115. package/components/related-content/_macro.njk +1 -0
  116. package/components/related-content/_macro.spec.js +142 -0
  117. package/components/relationships/_macro.spec.js +108 -0
  118. package/components/relationships/relationships.spec.js +84 -0
  119. package/components/reply/_macro.njk +2 -2
  120. package/components/reply/_macro.spec.js +69 -0
  121. package/components/reply/reply.spec.js +78 -0
  122. package/components/search/_macro.njk +14 -12
  123. package/components/search/_macro.spec.js +44 -0
  124. package/components/search/_search.scss +7 -7
  125. package/components/section-navigation/_macro.njk +7 -2
  126. package/components/section-navigation/_macro.spec.js +206 -0
  127. package/components/select/_macro.njk +3 -3
  128. package/components/select/_macro.spec.js +203 -0
  129. package/components/select/select.spec.js +56 -0
  130. package/components/share-page/_macro.njk +2 -2
  131. package/components/share-page/_macro.spec.js +110 -0
  132. package/components/skip-to-content/_macro.spec.js +57 -0
  133. package/components/skip-to-content/skip-to-content.spec.js +44 -0
  134. package/components/status/_macro.spec.js +77 -0
  135. package/components/summary/_macro.njk +5 -5
  136. package/components/summary/_macro.spec.js +472 -0
  137. package/components/table/_macro.njk +2 -2
  138. package/components/table/_macro.spec.js +557 -0
  139. package/components/table/table.spec.js +155 -0
  140. package/components/table-of-contents/_macro.njk +35 -35
  141. package/components/table-of-contents/_macro.spec.js +178 -0
  142. package/components/table-of-contents/toc.js +29 -25
  143. package/components/table-of-contents/toc.spec.js +61 -0
  144. package/components/tabs/_macro.njk +1 -1
  145. package/components/tabs/_macro.spec.js +79 -0
  146. package/components/tabs/tabs.spec.js +162 -0
  147. package/components/text-indent/_macro.spec.js +52 -0
  148. package/components/textarea/_macro.njk +5 -3
  149. package/components/textarea/_macro.spec.js +300 -0
  150. package/components/textarea/textarea.spec.js +98 -0
  151. package/components/timeline/_macro.njk +3 -3
  152. package/components/timeline/_macro.spec.js +81 -0
  153. package/components/timeout-modal/_macro.spec.js +68 -0
  154. package/components/timeout-modal/timeout-modal.spec.js +226 -0
  155. package/components/timeout-panel/_macro.njk +0 -1
  156. package/components/timeout-panel/_macro.spec.js +54 -0
  157. package/components/timeout-panel/timeout-panel.dom.js +1 -2
  158. package/components/timeout-panel/timeout-panel.spec.js +161 -0
  159. package/components/upload/_macro.spec.js +75 -0
  160. package/components/video/_macro.spec.js +34 -0
  161. package/css/census.css +1 -1
  162. package/css/main.css +1 -1
  163. package/js/cookies-settings.spec.js +154 -0
  164. package/package.json +10 -23
  165. package/scripts/main.es5.js +1 -1
  166. package/scripts/main.js +2 -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
+ });