@ons/design-system 60.0.3 → 61.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 (40) hide show
  1. package/components/accordion/_macro.njk +2 -3
  2. package/components/accordion/_macro.spec.js +9 -9
  3. package/components/accordion/accordion.dom.js +4 -4
  4. package/components/accordion/accordion.js +14 -14
  5. package/components/accordion/accordion.spec.js +6 -6
  6. package/components/collapsible/_macro.njk +20 -28
  7. package/components/collapsible/_macro.spec.js +15 -15
  8. package/components/{collapsible/_collapsible.scss → details/_details.scss} +14 -14
  9. package/components/details/_macro.njk +30 -0
  10. package/components/details/_macro.spec.js +151 -0
  11. package/components/details/details.dom.js +13 -0
  12. package/components/details/details.js +66 -0
  13. package/components/details/details.spec.js +103 -0
  14. package/components/hero/_hero.scss +2 -2
  15. package/components/question/_macro.njk +4 -4
  16. package/components/question/_macro.spec.js +14 -14
  17. package/components/summary/_macro.njk +1 -1
  18. package/components/summary/_macro.spec.js +148 -1
  19. package/components/summary/_summary.scss +6 -2
  20. package/components/table/_macro.spec.js +10 -8
  21. package/components/video/_macro.njk +18 -4
  22. package/components/video/_macro.spec.js +46 -33
  23. package/components/video/_video.scss +4 -0
  24. package/components/video/video.dom.js +13 -0
  25. package/components/video/video.js +30 -0
  26. package/components/video/video.spec.js +72 -0
  27. package/css/main.css +3 -3
  28. package/css/print.css +1 -1
  29. package/js/main.js +2 -1
  30. package/package.json +2 -1
  31. package/scripts/main.es5.js +1 -1
  32. package/scripts/main.js +1 -1
  33. package/scss/main.scss +1 -1
  34. package/scss/objects/_page.scss +1 -1
  35. package/scss/objects/_spacing.scss +1 -1
  36. package/scss/overrides/hcm.scss +1 -1
  37. package/scss/print.scss +1 -1
  38. package/components/collapsible/collapsible.dom.js +0 -13
  39. package/components/collapsible/collapsible.js +0 -66
  40. package/components/collapsible/collapsible.spec.js +0 -103
@@ -0,0 +1,66 @@
1
+ export default class Details {
2
+ constructor(detailsElement) {
3
+ this.saveState = detailsElement.getAttribute('data-save-state') === 'true';
4
+ this.open = detailsElement.getAttribute('data-open') === 'true';
5
+ this.group = detailsElement.getAttribute('data-group');
6
+
7
+ // Elements
8
+ this.details = detailsElement;
9
+ this.detailsHeader = this.details.querySelector('.ons-js-details-heading');
10
+
11
+ // Initialise
12
+ const detailsId = detailsElement.getAttribute('id');
13
+
14
+ if (localStorage.getItem(detailsId) || this.open) {
15
+ this.setOpen(true);
16
+ this.details['setAttribute']('open', '');
17
+ }
18
+
19
+ this.detailsHeader.addEventListener('click', this.toggle.bind(this));
20
+ this.detailsHeader.addEventListener('keydown', this.keyboardInteraction.bind(this));
21
+ }
22
+
23
+ toggle(event) {
24
+ event.preventDefault();
25
+ this.setOpen(!this.isOpen);
26
+ }
27
+
28
+ setOpen(open) {
29
+ if (open !== this.isOpen) {
30
+ const action = open ? 'Open' : 'Close';
31
+ const openAttribute = open ? 'set' : 'remove';
32
+
33
+ this.isOpen = open;
34
+ this.details[`${openAttribute}Attribute`]('open', '');
35
+ this.detailsHeader.setAttribute('data-ga-action', `${action} panel`);
36
+
37
+ if (this.onOpen && this.onClose) {
38
+ if (open) {
39
+ this.onOpen();
40
+ } else {
41
+ this.onClose();
42
+ }
43
+ }
44
+ }
45
+
46
+ if (this.saveState === true && open === true) {
47
+ localStorage.setItem(this.details.getAttribute('id'), true);
48
+ } else {
49
+ localStorage.removeItem(this.details.getAttribute('id'));
50
+ }
51
+ }
52
+
53
+ keyboardInteraction(event) {
54
+ const keyCode = event.which;
55
+ switch (keyCode) {
56
+ // Enter/Space
57
+ case 13:
58
+ case 32:
59
+ event.preventDefault();
60
+ event.stopPropagation();
61
+
62
+ this.toggle(event);
63
+ break;
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,103 @@
1
+ import { renderComponent, setTestPage } from '../../tests/helpers/rendering';
2
+
3
+ const EXAMPLE_DETAILS_BASIC = {
4
+ id: 'details-id',
5
+ title: 'Title for details',
6
+ content: 'Content for details',
7
+ };
8
+
9
+ describe('script: details', () => {
10
+ it('begins open when specified', async () => {
11
+ await setTestPage(
12
+ '/test',
13
+ renderComponent('details', {
14
+ ...EXAMPLE_DETAILS_BASIC,
15
+ open: true,
16
+ }),
17
+ );
18
+
19
+ const openAttribute = await page.$eval('.ons-js-details', node => node.open !== null);
20
+ expect(openAttribute).toBe(true);
21
+ });
22
+
23
+ describe('when the details heading is clicked to open the details', () => {
24
+ beforeEach(async () => {
25
+ await setTestPage('/test', renderComponent('details', EXAMPLE_DETAILS_BASIC));
26
+ await page.click('.ons-js-details-heading');
27
+ });
28
+
29
+ it('sets the `open` attribute', async () => {
30
+ const openAttribute = await page.$eval('.ons-js-details', node => node.open !== null);
31
+ expect(openAttribute).toBe(true);
32
+ });
33
+
34
+ it('sets the `ga` attributes', async () => {
35
+ const gaHeadingAttribute = await page.$eval('.ons-js-details-heading', element => element.getAttribute('data-ga-action'));
36
+
37
+ expect(gaHeadingAttribute).toBe('Open panel');
38
+ });
39
+ });
40
+
41
+ describe('when the details heading is focused', () => {
42
+ beforeEach(async () => {
43
+ await setTestPage('/test', renderComponent('details', EXAMPLE_DETAILS_BASIC));
44
+ await page.focus('.ons-js-details-heading');
45
+ });
46
+
47
+ describe('when the space bar is pressed', () => {
48
+ beforeEach(async () => {
49
+ await page.keyboard.press('Space');
50
+ });
51
+
52
+ it('opens the details content', async () => {
53
+ const openAttribute = await page.$eval('.ons-js-details', node => node.open !== null);
54
+ expect(openAttribute).toBe(true);
55
+ });
56
+ });
57
+
58
+ describe('when the Enter key is pressed', () => {
59
+ beforeEach(async () => {
60
+ await page.keyboard.press('Enter');
61
+ });
62
+
63
+ it('opens the details content', async () => {
64
+ const openAttribute = await page.$eval('.ons-js-details', node => node.open !== null);
65
+ expect(openAttribute).toBe(true);
66
+ });
67
+ });
68
+ });
69
+
70
+ describe('when the state is set to save', () => {
71
+ beforeEach(async () => {
72
+ await setTestPage(
73
+ '/test',
74
+ renderComponent('details', {
75
+ ...EXAMPLE_DETAILS_BASIC,
76
+ saveState: true,
77
+ }),
78
+ );
79
+ });
80
+
81
+ describe('when the details is opened', () => {
82
+ beforeEach(async () => {
83
+ await page.click('.ons-js-details-heading');
84
+ });
85
+
86
+ it('sets state in localStorage', async () => {
87
+ const localStorage = await page.evaluate(() => localStorage.getItem('details-id'));
88
+ expect(localStorage).toBe('true');
89
+ });
90
+ });
91
+
92
+ describe('when the details is closed', () => {
93
+ beforeEach(async () => {
94
+ await page.click('.ons-js-details-heading');
95
+ });
96
+
97
+ it('removes state in localStorage', async () => {
98
+ const localStorage = await page.evaluate(() => localStorage.getItem('details-id'));
99
+ expect(localStorage).toBe(null);
100
+ });
101
+ });
102
+ });
103
+ });
@@ -16,7 +16,7 @@
16
16
  min-height: 300px;
17
17
  position: relative;
18
18
 
19
- &--has-collapsible {
19
+ &--has-details {
20
20
  align-items: flex-start; // Prevents undesired shift if not enough content
21
21
  }
22
22
  }
@@ -59,7 +59,7 @@
59
59
  text-decoration-thickness: 2px;
60
60
  }
61
61
 
62
- .ons-collapsible__heading {
62
+ .ons-details__heading {
63
63
  color: inherit;
64
64
  }
65
65
  }
@@ -18,8 +18,8 @@
18
18
 
19
19
  {% if params.definition %}
20
20
  {% set questionDefinition %}
21
- {% from "components/collapsible/_macro.njk" import onsCollapsible %}
22
- {% call onsCollapsible({
21
+ {% from "components/details/_macro.njk" import onsDetails %}
22
+ {% call onsDetails({
23
23
  "id": params.definition.id,
24
24
  "classes": 'ons-u-mb-m',
25
25
  "title": params.definition.title
@@ -109,8 +109,8 @@
109
109
  {% endif %}
110
110
 
111
111
  {% if params.justification %}
112
- {% from "components/collapsible/_macro.njk" import onsCollapsible %}
113
- {% call onsCollapsible({
112
+ {% from "components/details/_macro.njk" import onsDetails %}
113
+ {% call onsDetails({
114
114
  "id": params.justification.id,
115
115
  "classes": 'ons-u-mb-m',
116
116
  "title": params.justification.title | default('Why we ask this question')
@@ -163,21 +163,21 @@ describe('macro: question', () => {
163
163
  });
164
164
 
165
165
  describe('mode: with definition', () => {
166
- it('outputs the expected collapsible', () => {
166
+ it('outputs the expected details', () => {
167
167
  const faker = templateFaker();
168
- const collapsibleSpy = faker.spy('collapsible');
168
+ const detailsSpy = faker.spy('details');
169
169
 
170
170
  faker.renderComponent('question', EXAMPLE_QUESTION_DEFINITION);
171
171
 
172
- expect(collapsibleSpy.occurrences[0]).toHaveProperty('classes', 'ons-u-mb-m');
173
- expect(collapsibleSpy.occurrences[0]).toHaveProperty('id', 'definition-id');
174
- expect(collapsibleSpy.occurrences[0]).toHaveProperty('title', 'Definition title');
172
+ expect(detailsSpy.occurrences[0]).toHaveProperty('classes', 'ons-u-mb-m');
173
+ expect(detailsSpy.occurrences[0]).toHaveProperty('id', 'definition-id');
174
+ expect(detailsSpy.occurrences[0]).toHaveProperty('title', 'Definition title');
175
175
  });
176
176
 
177
- it('outputs the expected collapsible call content', () => {
177
+ it('outputs the expected details call content', () => {
178
178
  const $ = cheerio.load(renderComponent('question', EXAMPLE_QUESTION_DEFINITION));
179
179
 
180
- expect($('.ons-collapsible__content > p').text()).toBe('Definition content');
180
+ expect($('.ons-details__content > p').text()).toBe('Definition content');
181
181
  });
182
182
  });
183
183
 
@@ -227,21 +227,21 @@ describe('macro: question', () => {
227
227
  });
228
228
 
229
229
  describe('mode: with justification', () => {
230
- it('outputs the expected collapsible', () => {
230
+ it('outputs the expected details', () => {
231
231
  const faker = templateFaker();
232
- const collapsibleSpy = faker.spy('collapsible');
232
+ const detailsSpy = faker.spy('details');
233
233
 
234
234
  faker.renderComponent('question', EXAMPLE_QUESTION_JUSTIFICATION);
235
235
 
236
- expect(collapsibleSpy.occurrences[0]).toHaveProperty('classes', 'ons-u-mb-m');
237
- expect(collapsibleSpy.occurrences[0]).toHaveProperty('id', 'justification-id');
238
- expect(collapsibleSpy.occurrences[0]).toHaveProperty('title', 'Justification title');
236
+ expect(detailsSpy.occurrences[0]).toHaveProperty('classes', 'ons-u-mb-m');
237
+ expect(detailsSpy.occurrences[0]).toHaveProperty('id', 'justification-id');
238
+ expect(detailsSpy.occurrences[0]).toHaveProperty('title', 'Justification title');
239
239
  });
240
240
 
241
- it('outputs the expected collapsible call content', () => {
241
+ it('outputs the expected details call content', () => {
242
242
  const $ = cheerio.load(renderComponent('question', EXAMPLE_QUESTION_JUSTIFICATION));
243
243
 
244
- expect($('.ons-collapsible__content > p').text()).toBe('Justification content');
244
+ expect($('.ons-details__content > p').text()).toBe('Justification content');
245
245
  });
246
246
  });
247
247
 
@@ -112,7 +112,7 @@
112
112
  {% endif %}
113
113
 
114
114
  {% if group.summaryLink %}
115
- <div class="ons-summary__link{% if group.placeholderText or group.rows %} ons-u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows | length > 1 %} ons-u-bt{% endif %}">
115
+ <div class="ons-summary__link{% if group.placeholderText or group.rows %} ons-u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows | length > 1 %} ons-u-bt{% endif %}{% if not group.last %} ons-u-mb-xl{% endif %}">
116
116
  <a {% if group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
117
117
  </div>
118
118
  {% endif %}
@@ -115,7 +115,6 @@ const EXAMPLE_SUMMARY_GROUPS = {
115
115
  {
116
116
  id: 'group-id-1',
117
117
  groupTitle: 'group title',
118
- headers: ['Header 1', 'Header 2', 'Header 3'],
119
118
  ...EXAMPLE_SUMMARY_ROWS,
120
119
  },
121
120
  ],
@@ -136,6 +135,123 @@ const EXAMPLE_SUMMARY_GROUPS_NO_ROWS = {
136
135
  ],
137
136
  };
138
137
 
138
+ const EXAMPLE_SUMMARY_HOUSEHOLD_GROUP = {
139
+ rows: [
140
+ {
141
+ rowItems: [
142
+ {
143
+ rowTitle: 'row item 1',
144
+ valueList: [
145
+ {
146
+ text: 'list item 1',
147
+ },
148
+ ],
149
+ actions: [
150
+ {
151
+ text: 'Change',
152
+ ariaLabel: 'Change list item',
153
+ url: '#0',
154
+ },
155
+ {
156
+ text: 'Remove',
157
+ ariaLabel: 'Remove list item',
158
+ url: '#0',
159
+ },
160
+ ],
161
+ },
162
+ {
163
+ rowTitle: 'row item 2',
164
+ valueList: [
165
+ {
166
+ text: 'list item 2',
167
+ },
168
+ ],
169
+ actions: [
170
+ {
171
+ text: 'Change',
172
+ ariaLabel: 'Remove list item',
173
+ url: '#0',
174
+ },
175
+ ],
176
+ },
177
+ {
178
+ rowTitle: 'row item 3',
179
+ valueList: [
180
+ {
181
+ text: 'list item 3',
182
+ },
183
+ ],
184
+ actions: [
185
+ {
186
+ text: 'Change',
187
+ ariaLabel: 'Change list item',
188
+ url: '#0',
189
+ },
190
+ ],
191
+ },
192
+ ],
193
+ },
194
+ {
195
+ rowItems: [
196
+ {
197
+ rowTitle: 'row item 4',
198
+ valueList: [
199
+ {
200
+ text: 'list item 4',
201
+ },
202
+ ],
203
+ actions: [
204
+ {
205
+ text: 'Change',
206
+ ariaLabel: 'Change answer',
207
+ url: '#0',
208
+ },
209
+ {
210
+ text: 'Remove',
211
+ ariaLabel: 'Change list item',
212
+ url: '#0',
213
+ },
214
+ ],
215
+ },
216
+ {
217
+ rowTitle: 'row item 5',
218
+ valueList: [
219
+ {
220
+ text: 'list item 5',
221
+ },
222
+ ],
223
+ actions: [
224
+ {
225
+ text: 'Change',
226
+ ariaLabel: 'Change list item',
227
+ url: '#0',
228
+ },
229
+ ],
230
+ },
231
+ {
232
+ rowTitle: 'row item 6',
233
+ valueList: [
234
+ {
235
+ text: 'list item 6',
236
+ },
237
+ ],
238
+ actions: [
239
+ {
240
+ text: 'Change',
241
+ ariaLabel: 'Change list item',
242
+ url: '#0',
243
+ },
244
+ ],
245
+ },
246
+ ],
247
+ },
248
+ ],
249
+ summaryLink: {
250
+ text: 'Summary link',
251
+ url: '#0',
252
+ },
253
+ };
254
+
139
255
  const EXAMPLE_SUMMARY_BASIC = {
140
256
  summaries: [
141
257
  {
@@ -162,6 +278,31 @@ const EXAMPLE_SUMMARY_WITH_NO_ROWS = {
162
278
  ],
163
279
  };
164
280
 
281
+ const EXAMPLE_SUMMARY_MULTIPLE_GROUPS = {
282
+ summaries: [
283
+ {
284
+ summaryTitle: 'summary title',
285
+ groups: [
286
+ {
287
+ id: 'group-id-1',
288
+ groupTitle: 'group title',
289
+ ...EXAMPLE_SUMMARY_ROWS,
290
+ },
291
+ {
292
+ id: 'group-id-2',
293
+ groupTitle: 'group title',
294
+ ...EXAMPLE_SUMMARY_HOUSEHOLD_GROUP,
295
+ },
296
+ {
297
+ id: 'group-id-3',
298
+ groupTitle: 'group title',
299
+ ...EXAMPLE_SUMMARY_ROWS,
300
+ },
301
+ ],
302
+ },
303
+ ],
304
+ };
305
+
165
306
  describe('macro: summary', () => {
166
307
  describe('mode: general', () => {
167
308
  it('passes jest-axe checks', async () => {
@@ -200,6 +341,12 @@ describe('macro: summary', () => {
200
341
 
201
342
  expect($('.ons-summary__group-title').text()).toBe('group title');
202
343
  });
344
+
345
+ it('has larger margin between groups if the top one is a household style summary', () => {
346
+ const $ = cheerio.load(renderComponent('summary', EXAMPLE_SUMMARY_MULTIPLE_GROUPS));
347
+
348
+ expect($('.ons-summary__group:nth-last-of-type(2) .ons-summary__link').hasClass('ons-u-mb-xl')).toBe(true);
349
+ });
203
350
  });
204
351
 
205
352
  describe('part: row', () => {
@@ -178,7 +178,7 @@ $hub-row-spacing: 1.3rem;
178
178
  &__item-title,
179
179
  &__values,
180
180
  &__actions {
181
- flex: 2;
181
+ flex: 4;
182
182
  padding-top: $summary-row-spacing;
183
183
  vertical-align: top;
184
184
 
@@ -192,9 +192,13 @@ $hub-row-spacing: 1.3rem;
192
192
  justify-content: right;
193
193
  }
194
194
 
195
+ &__button {
196
+ align-self: flex-start;
197
+ }
198
+
195
199
  &__item-title,
196
200
  &__values {
197
- flex: 6.19;
201
+ flex: 7.3;
198
202
  }
199
203
 
200
204
  &__item-title--2 {
@@ -356,14 +356,16 @@ describe('macro: table', () => {
356
356
 
357
357
  faker.renderComponent('table', params);
358
358
 
359
- expect(buttonSpy.occurrences).toEqual([{
360
- text: 'Submit form',
361
- id: 'submit-form-button',
362
- classes: 'custom-button-class',
363
- url: 'https://example.com/link',
364
- value: '42', // `| safe` filter is used in macro which makes a string
365
- name: 'submit-form-button-name',
366
- }]);
359
+ expect(buttonSpy.occurrences).toEqual([
360
+ {
361
+ text: 'Submit form',
362
+ id: 'submit-form-button',
363
+ classes: 'custom-button-class',
364
+ url: 'https://example.com/link',
365
+ value: '42', // `| safe` filter is used in macro which makes a string
366
+ name: 'submit-form-button-name',
367
+ },
368
+ ]);
367
369
  });
368
370
  });
369
371
  });
@@ -1,7 +1,21 @@
1
+ {% from "components/external-link/_macro.njk" import onsExternalLink %}
1
2
  {%- macro onsVideo(params) -%}
2
- <div class="ons-video">
3
- {% if params.videoEmbedUrl %}
4
- <iframe title="{{ params.title }}" class="ons-video__iframe" src="{{ params.videoEmbedUrl }}" frameborder="0" allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
5
- {% endif %}
3
+
4
+ {% set linkContents %}
5
+ {% if params.image.smallSrc %}
6
+ <img class="ons-video__img ons-u-mb-xs" {% if params.image.largeSrc %} srcset="{{ params.image.smallSrc }} 1x, {{ params.image.largeSrc }} 2x"{% endif %} src="{{ params.image.smallSrc }}" alt="{{ params.image.alt }}" loading="lazy">
7
+ {% endif %}
8
+ <span class="ons-video__link-text ons-u-mt-xs">{{ params.linkText }}</span>
9
+ {% endset %}
10
+
11
+ <div class="ons-video ons-js-video">
12
+ {{
13
+ onsExternalLink({
14
+ "url": params.videoLinkURL,
15
+ "classes": "ons-video__link ons-js-video-placeholder ons-u-db",
16
+ "linkText": linkContents
17
+ })
18
+ }}
19
+ <iframe data-src="{{ params.videoEmbedUrl }}" title="{{ params.title }}" class="ons-video__iframe ons-js-video-iframe ons-u-d-no" src="about:blank" frameborder="0" allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
6
20
  </div>
7
21
  {%- endmacro -%}
@@ -7,54 +7,67 @@ import { renderComponent } from '../../tests/helpers/rendering';
7
7
 
8
8
  const EXAMPLE_VIDEO_YOUTUBE = {
9
9
  videoEmbedUrl: 'https://www.youtube.com/embed/_EGJlvkgbPo',
10
+ videoLinkURL: 'https://www.youtube.com/watch?v=_EGJlvkgbPo',
10
11
  title: 'Census 2021 promotional TV advert',
11
- };
12
-
13
- const EXAMPLE_VIDEO_VIMEO = {
14
- videoEmbedUrl: 'https://player.vimeo.com/video/508878572',
15
- title: 'A message from National Statistician Ian Diamond for National Apprenticeship Week 2021',
12
+ linkText: 'Example link text',
13
+ image: {
14
+ smallSrc: 'example-small.png',
15
+ largeSrc: 'example-large.png',
16
+ alt: 'Example alt text',
17
+ },
16
18
  };
17
19
 
18
20
  describe('macro: video', () => {
19
- describe('mode: YouTube', () => {
20
- it('passes jest-axe checks', async () => {
21
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
21
+ it('passes jest-axe checks', async () => {
22
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
23
+
24
+ const results = await axe($.html());
25
+ expect(results).toHaveNoViolations();
26
+ });
27
+
28
+ it('outputs an `img` element with the expected `srcset`', () => {
29
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
30
+
31
+ expect($('.ons-video__img').attr('srcset')).toBe('example-small.png 1x, example-large.png 2x');
32
+ });
33
+
34
+ it('outputs an `img` element with the expected `src`', () => {
35
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
22
36
 
23
- const results = await axe($.html());
24
- expect(results).toHaveNoViolations();
25
- });
37
+ expect($('.ons-video__img').attr('src')).toBe('example-small.png');
38
+ });
26
39
 
27
- it('outputs an <iframe> element with the provided `title`', () => {
28
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
40
+ it('outputs an `img` element with the expected alt text', () => {
41
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
29
42
 
30
- expect($('iframe').attr('title')).toBe('Census 2021 promotional TV advert');
31
- });
43
+ expect($('.ons-video__img').attr('alt')).toBe('Example alt text');
44
+ });
32
45
 
33
- it('outputs an <iframe> element with the provided `videoEmbedUrl`', () => {
34
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
46
+ it('outputs the provided link text', () => {
47
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
35
48
 
36
- expect($('iframe').attr('src')).toBe('https://www.youtube.com/embed/_EGJlvkgbPo');
37
- });
49
+ expect(
50
+ $('.ons-video__link-text')
51
+ .text()
52
+ .trim(),
53
+ ).toBe('Example link text');
38
54
  });
39
55
 
40
- describe('mode: Vimeo', () => {
41
- it('passes jest-axe checks', async () => {
42
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_VIMEO));
56
+ it('outputs a hyperlink with the provided `url`', () => {
57
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
43
58
 
44
- const results = await axe($.html());
45
- expect(results).toHaveNoViolations();
46
- });
59
+ expect($('.ons-video__link').attr('href')).toBe('https://www.youtube.com/watch?v=_EGJlvkgbPo');
60
+ });
47
61
 
48
- it('outputs an <iframe> element with the provided `title`', () => {
49
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_VIMEO));
62
+ it('outputs an <iframe> element with the provided `title`', () => {
63
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
50
64
 
51
- expect($('iframe').attr('title')).toBe('A message from National Statistician Ian Diamond for National Apprenticeship Week 2021');
52
- });
65
+ expect($('iframe').attr('title')).toBe('Census 2021 promotional TV advert');
66
+ });
53
67
 
54
- it('outputs an <iframe> element with the provided `videoEmbedUrl`', () => {
55
- const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_VIMEO));
68
+ it('outputs an <iframe> element with the provided `videoEmbedUrl` data attribute', () => {
69
+ const $ = cheerio.load(renderComponent('video', EXAMPLE_VIDEO_YOUTUBE));
56
70
 
57
- expect($('iframe').attr('src')).toBe('https://player.vimeo.com/video/508878572');
58
- });
71
+ expect($('iframe').attr('data-src')).toBe('https://www.youtube.com/embed/_EGJlvkgbPo');
59
72
  });
60
73
  });
@@ -12,4 +12,8 @@
12
12
  top: 0;
13
13
  width: 100%;
14
14
  }
15
+
16
+ &__img {
17
+ width: 100%;
18
+ }
15
19
  }
@@ -0,0 +1,13 @@
1
+ import domready from '../../js/domready';
2
+
3
+ async function video() {
4
+ const videos = [...document.querySelectorAll('.ons-js-video')];
5
+
6
+ if (videos.length) {
7
+ const Video = (await import('./video')).default;
8
+
9
+ videos.forEach(component => new Video(component));
10
+ }
11
+ }
12
+
13
+ domready(video);