@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.
- package/README.md +35 -15
- package/components/access-code/_macro.njk +1 -1
- package/components/access-code/_macro.spec.js +162 -0
- package/components/access-code/uac.spec.js +26 -0
- package/components/accordion/_macro.spec.js +224 -0
- package/components/accordion/accordion.spec.js +134 -0
- package/components/address-input/_macro.njk +1 -1
- package/components/address-input/_macro.spec.js +465 -0
- package/components/address-input/autosuggest.address.js +5 -4
- package/components/address-input/autosuggest.address.setter.js +9 -3
- package/components/address-input/autosuggest.address.spec.js +733 -0
- package/components/address-output/_macro.njk +6 -6
- package/components/address-output/_macro.spec.js +122 -0
- package/components/autosuggest/_macro.njk +1 -1
- package/components/autosuggest/_macro.spec.js +229 -0
- package/components/autosuggest/autosuggest.helpers.js +2 -3
- package/components/autosuggest/autosuggest.helpers.spec.js +85 -0
- package/components/autosuggest/autosuggest.js +4 -2
- package/components/autosuggest/autosuggest.spec.js +625 -0
- package/components/autosuggest/autosuggest.ui.js +6 -2
- package/components/breadcrumbs/_macro.spec.js +129 -0
- package/components/button/_button.scss +75 -33
- package/components/button/_macro.njk +6 -6
- package/components/button/_macro.spec.js +446 -0
- package/components/button/button.spec.js +290 -0
- package/components/call-to-action/_macro.njk +3 -1
- package/components/call-to-action/_macro.spec.js +52 -0
- package/components/card/_macro.njk +26 -19
- package/components/card/_macro.spec.js +261 -0
- package/components/char-check-limit/_macro.spec.js +73 -0
- package/components/char-check-limit/character-check.spec.js +196 -0
- package/components/char-check-limit/character-limit.js +1 -1
- package/components/checkboxes/_checkbox-macro.spec.js +419 -0
- package/components/checkboxes/_macro.njk +1 -3
- package/components/checkboxes/_macro.spec.js +306 -0
- package/components/checkboxes/checkbox-with-autoselect.js +2 -1
- package/components/checkboxes/checkboxes.spec.js +208 -0
- package/components/code-highlight/_macro.spec.js +56 -0
- package/components/code-highlight/code-highlight.spec.js +18 -0
- package/components/collapsible/_macro.spec.js +204 -0
- package/components/collapsible/collapsible.js +2 -1
- package/components/collapsible/collapsible.spec.js +236 -0
- package/components/content-pagination/_macro.spec.js +199 -0
- package/components/cookies-banner/_macro.njk +1 -1
- package/components/cookies-banner/_macro.spec.js +171 -0
- package/components/cookies-banner/cookies-banner.spec.js +90 -0
- package/components/date-input/_macro.njk +6 -3
- package/components/date-input/_macro.spec.js +286 -0
- package/components/document-list/_macro.njk +3 -5
- package/components/document-list/_macro.spec.js +491 -0
- package/components/download-resources/download-resources.spec.js +540 -0
- package/components/duration/_macro.njk +7 -6
- package/components/duration/_macro.spec.js +251 -0
- package/components/error/_macro.spec.js +97 -0
- package/components/external-link/_macro.njk +5 -2
- package/components/external-link/_macro.spec.js +77 -0
- package/components/feedback/_macro.njk +5 -3
- package/components/feedback/_macro.spec.js +122 -0
- package/components/field/_macro.njk +2 -2
- package/components/field/_macro.spec.js +97 -0
- package/components/fieldset/_macro.njk +3 -3
- package/components/fieldset/_macro.spec.js +173 -0
- package/components/footer/_footer.scss +19 -4
- package/components/footer/_macro.njk +106 -137
- package/components/footer/_macro.spec.js +678 -0
- package/components/header/_header.scss +65 -46
- package/components/header/_macro.njk +173 -121
- package/components/header/_macro.spec.js +618 -0
- package/components/hero/_hero.scss +30 -143
- package/components/hero/_macro.njk +12 -23
- package/components/hero/_macro.spec.js +218 -0
- package/components/icons/_macro.njk +258 -30
- package/components/icons/_macro.spec.js +140 -0
- package/components/images/_macro.njk +1 -1
- package/components/images/_macro.spec.js +121 -0
- package/components/input/_input-type.scss +12 -5
- package/components/input/_input.scss +8 -0
- package/components/input/_macro.njk +4 -5
- package/components/input/_macro.spec.js +658 -0
- package/components/label/_macro.spec.js +189 -0
- package/components/language-selector/_macro.njk +1 -1
- package/components/language-selector/_macro.spec.js +137 -0
- package/components/lists/_list.scss +4 -0
- package/components/lists/_macro.njk +4 -7
- package/components/lists/_macro.spec.js +618 -0
- package/components/message/_macro.spec.js +137 -0
- package/components/message-list/_macro.njk +7 -7
- package/components/message-list/_macro.spec.js +159 -0
- package/components/metadata/_macro.spec.js +167 -0
- package/components/modal/_macro.njk +6 -6
- package/components/modal/_macro.spec.js +87 -0
- package/components/modal/modal.spec.js +59 -0
- package/components/mutually-exclusive/_macro.njk +2 -2
- package/components/mutually-exclusive/_macro.spec.js +184 -0
- package/components/mutually-exclusive/mutually-exclusive.checkboxes.spec.js +203 -0
- package/components/mutually-exclusive/mutually-exclusive.date.spec.js +142 -0
- package/components/mutually-exclusive/mutually-exclusive.duration.spec.js +141 -0
- package/components/mutually-exclusive/mutually-exclusive.email.spec.js +117 -0
- package/components/mutually-exclusive/mutually-exclusive.multiple-options.checkboxes.spec.js +213 -0
- package/components/mutually-exclusive/mutually-exclusive.number.spec.js +125 -0
- package/components/mutually-exclusive/mutually-exclusive.textarea.spec.js +131 -0
- package/components/navigation/_macro.njk +45 -38
- package/components/navigation/_macro.spec.js +329 -0
- package/components/navigation/_navigation.scss +20 -4
- package/components/navigation/navigation.dom.js +1 -1
- package/components/navigation/navigation.spec.js +232 -0
- package/components/pagination/_macro.njk +1 -1
- package/components/pagination/_macro.spec.js +411 -0
- package/components/panel/_macro.njk +6 -6
- package/components/panel/_macro.spec.js +423 -0
- package/components/password/_macro.spec.js +137 -0
- package/components/password/password.spec.js +40 -0
- package/components/phase-banner/_macro.spec.js +73 -0
- package/components/promotional-banner/_macro.spec.js +97 -0
- package/components/question/_macro.njk +16 -22
- package/components/question/_macro.spec.js +309 -0
- package/components/quote/_macro.spec.js +81 -0
- package/components/radios/_macro.njk +3 -6
- package/components/radios/_macro.spec.js +575 -0
- package/components/radios/radios.spec.js +180 -0
- package/components/related-content/_macro.njk +14 -21
- package/components/related-content/_macro.spec.js +133 -0
- package/components/related-content/_section-macro.njk +10 -0
- package/components/related-content/_section-macro.spec.js +43 -0
- package/components/relationships/_macro.spec.js +108 -0
- package/components/relationships/relationships.spec.js +84 -0
- package/components/reply/_macro.njk +2 -2
- package/components/reply/_macro.spec.js +69 -0
- package/components/reply/reply.spec.js +78 -0
- package/components/search/_macro.njk +14 -12
- package/components/search/_macro.spec.js +44 -0
- package/components/search/_search.scss +7 -7
- package/components/section-navigation/_macro.njk +7 -2
- package/components/section-navigation/_macro.spec.js +206 -0
- package/components/select/_macro.njk +3 -3
- package/components/select/_macro.spec.js +203 -0
- package/components/select/select.spec.js +56 -0
- package/components/share-page/_macro.njk +6 -4
- package/components/share-page/_macro.spec.js +110 -0
- package/components/skip-to-content/_macro.spec.js +57 -0
- package/components/skip-to-content/skip-to-content.spec.js +44 -0
- package/components/status/_macro.spec.js +77 -0
- package/components/summary/_macro.njk +5 -5
- package/components/summary/_macro.spec.js +472 -0
- package/components/table/_macro.njk +2 -2
- package/components/table/_macro.spec.js +557 -0
- package/components/table/table.spec.js +155 -0
- package/components/table-of-contents/_macro.njk +35 -35
- package/components/table-of-contents/_macro.spec.js +178 -0
- package/components/table-of-contents/toc.js +29 -25
- package/components/table-of-contents/toc.spec.js +61 -0
- package/components/tabs/_macro.njk +1 -1
- package/components/tabs/_macro.spec.js +79 -0
- package/components/tabs/tabs.spec.js +162 -0
- package/components/text-indent/_macro.spec.js +52 -0
- package/components/textarea/_macro.njk +5 -3
- package/components/textarea/_macro.spec.js +300 -0
- package/components/textarea/textarea.spec.js +98 -0
- package/components/timeline/_macro.njk +3 -3
- package/components/timeline/_macro.spec.js +81 -0
- package/components/timeout-modal/_macro.spec.js +68 -0
- package/components/timeout-modal/timeout-modal.spec.js +226 -0
- package/components/timeout-panel/_macro.njk +0 -1
- package/components/timeout-panel/_macro.spec.js +54 -0
- package/components/timeout-panel/timeout-panel.dom.js +1 -2
- package/components/timeout-panel/timeout-panel.spec.js +161 -0
- package/components/upload/_macro.spec.js +75 -0
- package/components/video/_macro.spec.js +34 -0
- package/css/census.css +3 -1
- package/css/ids.css +2 -0
- package/css/main.css +1 -1
- package/img/dummy-brand-logo.svg +1 -0
- package/js/cookies-settings.spec.js +154 -0
- package/layout/_template.njk +7 -4
- package/package.json +10 -23
- package/scripts/main.es5.js +2 -2
- package/scripts/main.js +1 -1
- package/scss/ids.scss +2 -0
- package/scss/settings/_census.scss +141 -0
- package/scss/settings/_ids.scss +48 -0
- package/scss/utilities/_margin.scss +1 -0
- package/scss/vars/_colors.scss +5 -2
|
@@ -0,0 +1,204 @@
|
|
|
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_COLLAPSIBLE_BASIC = {
|
|
9
|
+
id: 'collapsible-id',
|
|
10
|
+
title: 'Title for collapsible',
|
|
11
|
+
content: 'Content for collapsible',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe('macro: collapsible', () => {
|
|
15
|
+
it('passes jest-axe checks', async () => {
|
|
16
|
+
const $ = cheerio.load(renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
17
|
+
|
|
18
|
+
const results = await axe($.html());
|
|
19
|
+
expect(results).toHaveNoViolations();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('has the provided `id` attribute', () => {
|
|
23
|
+
const $ = cheerio.load(renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
24
|
+
|
|
25
|
+
expect($('.ons-collapsible').attr('id')).toBe('collapsible-id');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('has additionally provided style classes', () => {
|
|
29
|
+
const $ = cheerio.load(
|
|
30
|
+
renderComponent('collapsible', {
|
|
31
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
32
|
+
classes: 'extra-class another-extra-class',
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
expect($('.ons-collapsible').hasClass('extra-class')).toBe(true);
|
|
37
|
+
expect($('.ons-collapsible').hasClass('another-extra-class')).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('has provided variant style classes', () => {
|
|
41
|
+
const $ = cheerio.load(
|
|
42
|
+
renderComponent('collapsible', {
|
|
43
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
44
|
+
variants: ['variant-a', 'variant-b'],
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect($('.ons-collapsible--variant-a').length).toBe(1);
|
|
49
|
+
expect($('.ons-collapsible--variant-b').length).toBe(1);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('has provided title text', () => {
|
|
53
|
+
const $ = cheerio.load(renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
54
|
+
|
|
55
|
+
const titleText = $('.ons-collapsible__title')
|
|
56
|
+
.first()
|
|
57
|
+
.text()
|
|
58
|
+
.trim();
|
|
59
|
+
expect(titleText).toBe('Title for collapsible');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('has title with provided tag override', () => {
|
|
63
|
+
const $ = cheerio.load(
|
|
64
|
+
renderComponent('collapsible', {
|
|
65
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
66
|
+
titleTag: 'h4',
|
|
67
|
+
}),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const titleTag = $('.ons-collapsible__title')[0].tagName;
|
|
71
|
+
expect(titleTag).toBe('h4');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('has provided content text', () => {
|
|
75
|
+
const $ = cheerio.load(renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
76
|
+
|
|
77
|
+
const titleText = $('.ons-collapsible__content')
|
|
78
|
+
.text()
|
|
79
|
+
.trim();
|
|
80
|
+
expect(titleText).toEqual(expect.stringContaining('Content for collapsible'));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('has additionally provided `attributes`', () => {
|
|
84
|
+
const $ = cheerio.load(
|
|
85
|
+
renderComponent('collapsible', {
|
|
86
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
87
|
+
attributes: {
|
|
88
|
+
a: 123,
|
|
89
|
+
b: 456,
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
93
|
+
expect($('.ons-collapsible').attr('a')).toBe('123');
|
|
94
|
+
expect($('.ons-collapsible').attr('b')).toBe('456');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('has the correct data attribute when `saveState` is provided', () => {
|
|
98
|
+
const $ = cheerio.load(
|
|
99
|
+
renderComponent('collapsible', {
|
|
100
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
101
|
+
saveState: true,
|
|
102
|
+
}),
|
|
103
|
+
);
|
|
104
|
+
expect($('.ons-collapsible').attr('data-save-state')).toBe('true');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('has the correct data attribute when `open` is provided', () => {
|
|
108
|
+
const $ = cheerio.load(
|
|
109
|
+
renderComponent('collapsible', {
|
|
110
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
111
|
+
open: true,
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
114
|
+
expect($('.ons-collapsible').attr('data-open')).toBe('true');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('has additionally provided `headingAttributes`', () => {
|
|
118
|
+
const $ = cheerio.load(
|
|
119
|
+
renderComponent('collapsible', {
|
|
120
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
121
|
+
headingAttributes: {
|
|
122
|
+
a: 123,
|
|
123
|
+
b: 456,
|
|
124
|
+
},
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
expect($('.ons-collapsible__heading').attr('a')).toBe('123');
|
|
129
|
+
expect($('.ons-collapsible__heading').attr('b')).toBe('456');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('has additionally provided `contentAttributes`', () => {
|
|
133
|
+
const $ = cheerio.load(
|
|
134
|
+
renderComponent('collapsible', {
|
|
135
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
136
|
+
contentAttributes: {
|
|
137
|
+
a: 123,
|
|
138
|
+
b: 456,
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
expect($('.ons-collapsible__content').attr('a')).toBe('123');
|
|
144
|
+
expect($('.ons-collapsible__content').attr('b')).toBe('456');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('has `chevron` icon', () => {
|
|
148
|
+
const faker = templateFaker();
|
|
149
|
+
const iconsSpy = faker.spy('icons');
|
|
150
|
+
faker.renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC);
|
|
151
|
+
|
|
152
|
+
expect(iconsSpy.occurrences[0].iconType).toBe('chevron');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('has the expected button output', () => {
|
|
156
|
+
const faker = templateFaker();
|
|
157
|
+
const buttonSpy = faker.spy('button');
|
|
158
|
+
|
|
159
|
+
faker.renderComponent('collapsible', {
|
|
160
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
161
|
+
button: {
|
|
162
|
+
close: 'Close this',
|
|
163
|
+
attributes: {
|
|
164
|
+
a: 123,
|
|
165
|
+
b: 456,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
expect(buttonSpy.occurrences[0]).toEqual({
|
|
171
|
+
text: 'Close this',
|
|
172
|
+
type: 'button',
|
|
173
|
+
buttonContext: 'Title for collapsible content',
|
|
174
|
+
classes: 'ons-js-collapsible-button ons-u-d-no ons-btn--secondary',
|
|
175
|
+
innerClasses: 'ons-js-collapsible-button-inner',
|
|
176
|
+
variants: 'small',
|
|
177
|
+
attributes: {
|
|
178
|
+
a: 123,
|
|
179
|
+
b: 456,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('has the expected data attribute when `button` is provided', () => {
|
|
185
|
+
const $ = cheerio.load(
|
|
186
|
+
renderComponent('collapsible', {
|
|
187
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
188
|
+
button: {
|
|
189
|
+
close: 'Close this',
|
|
190
|
+
},
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
expect($('.ons-collapsible').attr('data-btn-close')).toBe('Close this');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('calls with content', () => {
|
|
197
|
+
const $ = cheerio.load(renderComponent('collapsible', { EXAMPLE_COLLAPSIBLE_BASIC }, 'Example content...'));
|
|
198
|
+
|
|
199
|
+
const content = $('.ons-collapsible__content')
|
|
200
|
+
.text()
|
|
201
|
+
.trim();
|
|
202
|
+
expect(content).toEqual(expect.stringContaining('Example content...'));
|
|
203
|
+
});
|
|
204
|
+
});
|
|
@@ -6,6 +6,7 @@ export default class Collapsible {
|
|
|
6
6
|
// State
|
|
7
7
|
this.group = collapsibleElement.getAttribute('data-group');
|
|
8
8
|
this.isAccordion = collapsibleElement.classList.contains('ons-collapsible--accordion');
|
|
9
|
+
this.isSimpleAccordion = collapsibleElement.classList.contains('ons-collapsible--simple');
|
|
9
10
|
|
|
10
11
|
// Elements
|
|
11
12
|
this.collapsible = collapsibleElement;
|
|
@@ -29,7 +30,7 @@ export default class Collapsible {
|
|
|
29
30
|
this.collapsibleHeader.setAttribute('role', 'link');
|
|
30
31
|
this.collapsibleHeader.setAttribute('aria-controls', collapsibleId);
|
|
31
32
|
|
|
32
|
-
if (!this.isAccordion) {
|
|
33
|
+
if (!this.isAccordion || this.isSimpleAccordion) {
|
|
33
34
|
this.collapsibleHeader.setAttribute('tabindex', 0);
|
|
34
35
|
}
|
|
35
36
|
if (localStorage.getItem(collapsibleId) || this.open) {
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { renderComponent, setTestPage } from '../../tests/helpers/rendering';
|
|
2
|
+
|
|
3
|
+
const EXAMPLE_COLLAPSIBLE_BASIC = {
|
|
4
|
+
id: 'collapsible-id',
|
|
5
|
+
title: 'Title for collapsible',
|
|
6
|
+
content: 'Content for collapsible',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
describe('script: collapsible', () => {
|
|
10
|
+
it('begins closed', async () => {
|
|
11
|
+
await setTestPage('/test', renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
12
|
+
|
|
13
|
+
const openItemCount = await page.$$eval('.ons-collapsible--open', elements => elements.length);
|
|
14
|
+
expect(openItemCount).toBe(0);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('sets the `role` attribute', async () => {
|
|
18
|
+
await setTestPage('/test', renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
19
|
+
|
|
20
|
+
const role = await page.$eval('.ons-collapsible', element => element.getAttribute('role'));
|
|
21
|
+
expect(role).toBe('group');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('adds the correct class', async () => {
|
|
25
|
+
await setTestPage('/test', renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
26
|
+
|
|
27
|
+
const className = await page.$eval('.ons-collapsible', element => element.classList.contains('ons-collapsible--initialised'));
|
|
28
|
+
expect(className).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('sets attributes on the heading element', async () => {
|
|
32
|
+
await setTestPage('/test', renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
33
|
+
|
|
34
|
+
const role = await page.$eval('.ons-js-collapsible-heading', element => element.getAttribute('role'));
|
|
35
|
+
const ariaControls = await page.$eval('.ons-js-collapsible-heading', element => element.getAttribute('aria-controls'));
|
|
36
|
+
const tabIndex = await page.$eval('.ons-js-collapsible-heading', element => element.getAttribute('tabindex'));
|
|
37
|
+
|
|
38
|
+
expect(role).toBe('link');
|
|
39
|
+
expect(ariaControls).toBe('collapsible-id');
|
|
40
|
+
expect(tabIndex).toBe('0');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('sets attributes on the button element', async () => {
|
|
44
|
+
await setTestPage('/test', renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
45
|
+
|
|
46
|
+
const ariaControls = await page.$eval('.ons-js-collapsible-button', element => element.getAttribute('aria-controls'));
|
|
47
|
+
expect(ariaControls).toBe('collapsible-id');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('sets the button element to be visible', async () => {
|
|
51
|
+
await setTestPage('/test', renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
52
|
+
|
|
53
|
+
const openClass = await page.$eval('.ons-collapsible', element => element.classList.contains('ons-collapsible--open'));
|
|
54
|
+
expect(openClass).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('begins open when specified', async () => {
|
|
58
|
+
await setTestPage(
|
|
59
|
+
'/test',
|
|
60
|
+
renderComponent('collapsible', {
|
|
61
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
62
|
+
open: true,
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const openClass = await page.$eval('.ons-collapsible', element => element.classList.contains('ons-collapsible--open'));
|
|
67
|
+
expect(openClass).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('when the collapsible heading is clicked to open the collapsible', () => {
|
|
71
|
+
beforeEach(async () => {
|
|
72
|
+
await setTestPage('/test', renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
73
|
+
await page.click('.ons-js-collapsible-heading');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('sets the `open` attribute', async () => {
|
|
77
|
+
const openAttribute = await page.$eval('.ons-js-collapsible', node => node.open !== null);
|
|
78
|
+
expect(openAttribute).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('sets the open class', async () => {
|
|
82
|
+
const openClass = await page.$eval('.ons-collapsible', element => element.classList.contains('ons-collapsible--open'));
|
|
83
|
+
expect(openClass).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('sets the `aria` attributes', async () => {
|
|
87
|
+
const ariaExpanded = await page.$eval('.ons-js-collapsible-heading', element => element.getAttribute('aria-expanded'));
|
|
88
|
+
const ariaHidden = await page.$eval('.ons-js-collapsible-content', element => element.getAttribute('aria-hidden'));
|
|
89
|
+
|
|
90
|
+
expect(ariaExpanded).toBe('true');
|
|
91
|
+
expect(ariaHidden).toBe('false');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('sets the `ga` attributes', async () => {
|
|
95
|
+
const gaHeadingAttribute = await page.$eval('.ons-js-collapsible-heading', element => element.getAttribute('data-ga-action'));
|
|
96
|
+
const gaButtonAttribute = await page.$eval('.ons-js-collapsible-button', element => element.getAttribute('data-ga-action'));
|
|
97
|
+
|
|
98
|
+
expect(gaHeadingAttribute).toBe('Open panel');
|
|
99
|
+
expect(gaButtonAttribute).toBe('Open panel');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('when the collapsible button is clicked to close the collapsible', () => {
|
|
104
|
+
beforeEach(async () => {
|
|
105
|
+
await setTestPage('/test', renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
106
|
+
await page.click('.ons-js-collapsible-heading');
|
|
107
|
+
await page.click('.ons-js-collapsible-button');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('removes the `open` attribute', async () => {
|
|
111
|
+
const openAttribute = await page.$eval('.ons-js-collapsible', node => node.open === true);
|
|
112
|
+
expect(openAttribute).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('removes the open class', async () => {
|
|
116
|
+
const openClass = await page.$eval('.ons-collapsible', element => element.classList.contains('ons-collapsible--open'));
|
|
117
|
+
expect(openClass).toBe(false);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('sets the `aria` attributes', async () => {
|
|
121
|
+
const ariaExpanded = await page.$eval('.ons-js-collapsible-heading', element => element.getAttribute('aria-expanded'));
|
|
122
|
+
const ariaHidden = await page.$eval('.ons-js-collapsible-content', element => element.getAttribute('aria-hidden'));
|
|
123
|
+
|
|
124
|
+
expect(ariaExpanded).toBe('false');
|
|
125
|
+
expect(ariaHidden).toBe('true');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('sets the `ga` attributes', async () => {
|
|
129
|
+
const gaHeadingAttribute = await page.$eval('.ons-js-collapsible-heading', element => element.getAttribute('data-ga-action'));
|
|
130
|
+
const gaButtonAttribute = await page.$eval('.ons-js-collapsible-button', element => element.getAttribute('data-ga-action'));
|
|
131
|
+
|
|
132
|
+
expect(gaHeadingAttribute).toBe('Close panel');
|
|
133
|
+
expect(gaButtonAttribute).toBe('Close panel');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('when the collapsible heading is focused', () => {
|
|
138
|
+
beforeEach(async () => {
|
|
139
|
+
await setTestPage('/test', renderComponent('collapsible', EXAMPLE_COLLAPSIBLE_BASIC));
|
|
140
|
+
await page.focus('.ons-js-collapsible-heading');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('when the space bar is pressed', () => {
|
|
144
|
+
beforeEach(async () => {
|
|
145
|
+
await page.keyboard.press('Space');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('opens the collapsible content', async () => {
|
|
149
|
+
const openClass = await page.$eval('.ons-collapsible', element => element.classList.contains('ons-collapsible--open'));
|
|
150
|
+
expect(openClass).toBe(true);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('when the Enter key is pressed', () => {
|
|
155
|
+
beforeEach(async () => {
|
|
156
|
+
await page.keyboard.press('Enter');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('opens the collapsible content', async () => {
|
|
160
|
+
const openClass = await page.$eval('.ons-collapsible', element => element.classList.contains('ons-collapsible--open'));
|
|
161
|
+
expect(openClass).toBe(true);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('when the state is set to save', () => {
|
|
167
|
+
beforeEach(async () => {
|
|
168
|
+
await setTestPage(
|
|
169
|
+
'/test',
|
|
170
|
+
renderComponent('collapsible', {
|
|
171
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
172
|
+
saveState: true,
|
|
173
|
+
}),
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe('when the collapsible is opened', () => {
|
|
178
|
+
beforeEach(async () => {
|
|
179
|
+
await page.click('.ons-js-collapsible-heading');
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('sets state in localStorage', async () => {
|
|
183
|
+
const localStorage = await page.evaluate(() => localStorage.getItem('collapsible-id'));
|
|
184
|
+
expect(localStorage).toBe('true');
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe('when the collapsible is closed', () => {
|
|
189
|
+
beforeEach(async () => {
|
|
190
|
+
await page.click('.ons-js-collapsible-heading');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('removes state in localStorage', async () => {
|
|
194
|
+
const localStorage = await page.evaluate(() => localStorage.getItem('collapsible-id'));
|
|
195
|
+
expect(localStorage).toBe(null);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('when the collapsible is an accordion', () => {
|
|
201
|
+
beforeEach(async () => {
|
|
202
|
+
await setTestPage(
|
|
203
|
+
'/test',
|
|
204
|
+
renderComponent('collapsible', {
|
|
205
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
206
|
+
isAccordion: true,
|
|
207
|
+
}),
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('does not set `tabindex` on the heading element', async () => {
|
|
212
|
+
const tabIndex = await page.$eval('.ons-js-collapsible-heading', element => element.getAttribute('tabindex'));
|
|
213
|
+
|
|
214
|
+
expect(tabIndex).toBe(null);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
describe('when the collapsible is an accordion and the simple variant', () => {
|
|
219
|
+
beforeEach(async () => {
|
|
220
|
+
await setTestPage(
|
|
221
|
+
'/test',
|
|
222
|
+
renderComponent('collapsible', {
|
|
223
|
+
...EXAMPLE_COLLAPSIBLE_BASIC,
|
|
224
|
+
isAccordion: true,
|
|
225
|
+
variants: 'simple',
|
|
226
|
+
}),
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('does set `tabindex` on the heading element', async () => {
|
|
231
|
+
const tabIndex = await page.$eval('.ons-js-collapsible-heading', element => element.getAttribute('tabindex'));
|
|
232
|
+
|
|
233
|
+
expect(tabIndex).toBe('0');
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
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_CONTENT_PAGINATION_NONE = {
|
|
9
|
+
contentPaginationItems: [],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const EXAMPLE_CONTENT_PAGINATION_PREV_ONLY = {
|
|
13
|
+
contentPaginationItems: [
|
|
14
|
+
{
|
|
15
|
+
rel: 'prev',
|
|
16
|
+
text: 'Previous',
|
|
17
|
+
url: '/guide/overview',
|
|
18
|
+
label: 'Overview',
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const EXAMPLE_CONTENT_PAGINATION_NEXT_ONLY = {
|
|
24
|
+
contentPaginationItems: [
|
|
25
|
+
{
|
|
26
|
+
rel: 'next',
|
|
27
|
+
text: 'Next',
|
|
28
|
+
url: '/guide/who-and-why',
|
|
29
|
+
label: 'Who should take part and why',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const EXAMPLE_CONTENT_PAGINATION_BOTH = {
|
|
35
|
+
contentPaginationItems: [
|
|
36
|
+
{
|
|
37
|
+
rel: 'prev',
|
|
38
|
+
text: 'Previous',
|
|
39
|
+
url: '/guide/overview',
|
|
40
|
+
label: 'Overview',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
rel: 'next',
|
|
44
|
+
text: 'Next',
|
|
45
|
+
url: '/guide/who-and-why',
|
|
46
|
+
label: 'Who should take part and why',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
describe('macro: content-pagination', () => {
|
|
52
|
+
it('passes jest-axe checks', async () => {
|
|
53
|
+
const $ = cheerio.load(renderComponent('content-pagination', EXAMPLE_CONTENT_PAGINATION_NONE));
|
|
54
|
+
|
|
55
|
+
const results = await axe($.html());
|
|
56
|
+
expect(results).toHaveNoViolations();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('has a default `aria-label` of "Guide pagination"', () => {
|
|
60
|
+
const $ = cheerio.load(renderComponent('content-pagination', EXAMPLE_CONTENT_PAGINATION_NONE));
|
|
61
|
+
|
|
62
|
+
expect($('.ons-content-pagination').attr('aria-label')).toBe('Guide pagination');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('has the provided `aria-label`', () => {
|
|
66
|
+
const $ = cheerio.load(
|
|
67
|
+
renderComponent('content-pagination', {
|
|
68
|
+
...EXAMPLE_CONTENT_PAGINATION_NONE,
|
|
69
|
+
ariaLabel: 'Other pages',
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
expect($('.ons-content-pagination').attr('aria-label')).toBe('Other pages');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('outputs no list items when `contentPaginationItems` is empty', () => {
|
|
77
|
+
const $ = cheerio.load(renderComponent('content-pagination', EXAMPLE_CONTENT_PAGINATION_NONE));
|
|
78
|
+
|
|
79
|
+
expect($('.ons-content-pagination__item').length).toBe(0);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('renders the `arrow-previous` icon for the previous link entry', () => {
|
|
83
|
+
const faker = templateFaker();
|
|
84
|
+
const iconsSpy = faker.spy('icons');
|
|
85
|
+
|
|
86
|
+
faker.renderComponent('content-pagination', EXAMPLE_CONTENT_PAGINATION_PREV_ONLY);
|
|
87
|
+
|
|
88
|
+
expect(iconsSpy.occurrences[0]).toHaveProperty('iconType', 'arrow-previous');
|
|
89
|
+
expect(iconsSpy.occurrences[0]).toHaveProperty('iconSize', 'm');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('renders the `arrow-next` icon for the next link entry', () => {
|
|
93
|
+
const faker = templateFaker();
|
|
94
|
+
const iconsSpy = faker.spy('icons');
|
|
95
|
+
|
|
96
|
+
faker.renderComponent('content-pagination', EXAMPLE_CONTENT_PAGINATION_NEXT_ONLY);
|
|
97
|
+
|
|
98
|
+
expect(iconsSpy.occurrences[0]).toHaveProperty('iconType', 'arrow-next');
|
|
99
|
+
expect(iconsSpy.occurrences[0]).toHaveProperty('iconSize', 'm');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('previous link', () => {
|
|
103
|
+
describe.each([
|
|
104
|
+
['with only the previous link', EXAMPLE_CONTENT_PAGINATION_PREV_ONLY],
|
|
105
|
+
['with both the previous and next links', EXAMPLE_CONTENT_PAGINATION_BOTH],
|
|
106
|
+
])('%s', (_, params) => {
|
|
107
|
+
it('renders a link with the correct URL', () => {
|
|
108
|
+
const $ = cheerio.load(renderComponent('content-pagination', params));
|
|
109
|
+
|
|
110
|
+
const prevLink = $('.ons-content-pagination__link[rel="prev"]');
|
|
111
|
+
expect(prevLink.attr('href')).toBe('/guide/overview');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('renders the correct pagination item text', () => {
|
|
115
|
+
const $ = cheerio.load(renderComponent('content-pagination', params));
|
|
116
|
+
|
|
117
|
+
const linkText = $('.ons-content-pagination__link[rel="prev"] .ons-content-pagination__link-text');
|
|
118
|
+
expect(linkText.text().trim()).toBe('Previous');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('renders the expected default `bridgingText`', () => {
|
|
122
|
+
const $ = cheerio.load(renderComponent('content-pagination', params));
|
|
123
|
+
|
|
124
|
+
const bridgingText = $('.ons-content-pagination__link[rel="prev"] .ons-content-pagination__link-divider');
|
|
125
|
+
expect(bridgingText.text().trim()).toBe('page in this guide is:');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('renders the provided `bridgingText`', () => {
|
|
129
|
+
const $ = cheerio.load(
|
|
130
|
+
renderComponent('content-pagination', {
|
|
131
|
+
contentPaginationItems: params.contentPaginationItems.map(item => ({
|
|
132
|
+
...item,
|
|
133
|
+
bridgingText: 'custom bridging text:',
|
|
134
|
+
})),
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const bridgingText = $('.ons-content-pagination__link[rel="prev"] .ons-content-pagination__link-divider');
|
|
139
|
+
expect(bridgingText.text().trim()).toBe('custom bridging text:');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('renders the provided `label`', () => {
|
|
143
|
+
const $ = cheerio.load(renderComponent('content-pagination', params));
|
|
144
|
+
|
|
145
|
+
const labelText = $('.ons-content-pagination__link[rel="prev"] .ons-content-pagination__link-label');
|
|
146
|
+
expect(labelText.text().trim()).toBe('Overview');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe('next link', () => {
|
|
152
|
+
describe.each([
|
|
153
|
+
['with only the next link', EXAMPLE_CONTENT_PAGINATION_NEXT_ONLY],
|
|
154
|
+
['with both the previous and next links', EXAMPLE_CONTENT_PAGINATION_BOTH],
|
|
155
|
+
])('%s', (_, params) => {
|
|
156
|
+
it('renders a link with the correct URL', () => {
|
|
157
|
+
const $ = cheerio.load(renderComponent('content-pagination', params));
|
|
158
|
+
|
|
159
|
+
const prevLink = $('.ons-content-pagination__link[rel="next"]');
|
|
160
|
+
expect(prevLink.attr('href')).toBe('/guide/who-and-why');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('renders the correct pagination item text', () => {
|
|
164
|
+
const $ = cheerio.load(renderComponent('content-pagination', params));
|
|
165
|
+
|
|
166
|
+
const linkText = $('.ons-content-pagination__link[rel="next"] .ons-content-pagination__link-text');
|
|
167
|
+
expect(linkText.text().trim()).toBe('Next');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('renders the expected default `bridgingText`', () => {
|
|
171
|
+
const $ = cheerio.load(renderComponent('content-pagination', params));
|
|
172
|
+
|
|
173
|
+
const bridgingText = $('.ons-content-pagination__link[rel="next"] .ons-content-pagination__link-divider');
|
|
174
|
+
expect(bridgingText.text().trim()).toBe('page in this guide is:');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('renders the provided `bridgingText`', () => {
|
|
178
|
+
const $ = cheerio.load(
|
|
179
|
+
renderComponent('content-pagination', {
|
|
180
|
+
contentPaginationItems: params.contentPaginationItems.map(item => ({
|
|
181
|
+
...item,
|
|
182
|
+
bridgingText: 'custom bridging text:',
|
|
183
|
+
})),
|
|
184
|
+
}),
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const bridgingText = $('.ons-content-pagination__link[rel="next"] .ons-content-pagination__link-divider');
|
|
188
|
+
expect(bridgingText.text().trim()).toBe('custom bridging text:');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('renders the provided `label`', () => {
|
|
192
|
+
const $ = cheerio.load(renderComponent('content-pagination', params));
|
|
193
|
+
|
|
194
|
+
const labelText = $('.ons-content-pagination__link[rel="next"] .ons-content-pagination__link-label');
|
|
195
|
+
expect(labelText.text().trim()).toBe('Who should take part and why');
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{% macro onsCookiesBanner(params) %}
|
|
2
|
-
<div class="ons-cookies-banner" role="region" aria-label="{{ params.ariaLabel | default('
|
|
2
|
+
<div class="ons-cookies-banner" role="region" aria-label="{{ params.ariaLabel | default('Cookies banner')}}">
|
|
3
3
|
<div class="ons-container ons-cookies-banner__primary">
|
|
4
4
|
<div class="ons-grid">
|
|
5
5
|
<div class="ons-grid__col ons-col-8@m">
|