@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,232 @@
1
+ import { setViewport } from '../../tests/helpers/puppeteer';
2
+ import { renderComponent, setTestPage } from '../../tests/helpers/rendering';
3
+
4
+ const EXAMPLE_NAVIGATION = {
5
+ navigation: {
6
+ id: 'main-nav',
7
+ ariaLabel: 'Main menu',
8
+ currentPath: '#0',
9
+ itemsList: [
10
+ {
11
+ title: 'Main nav item 1',
12
+ url: '#0',
13
+ classes: 'custom-class-main-item-1',
14
+ id: 'main-item-1',
15
+ },
16
+ {
17
+ title: 'Main nav item 2',
18
+ url: '#1',
19
+ classes: 'custom-class-main-item-2',
20
+ id: 'main-item-2',
21
+ },
22
+ ],
23
+ toggleNavigationButton: {
24
+ text: 'Menu',
25
+ ariaLabel: 'Toggle main navigation',
26
+ },
27
+ },
28
+ };
29
+
30
+ const EXAMPLE_NAVIGATION_WITH_SUBNAVIGATION = {
31
+ navigation: {
32
+ id: 'main-nav',
33
+ ariaLabel: 'Main menu',
34
+ currentPath: '#1',
35
+ currentPageTitle: 'Main nav item 2',
36
+ itemsList: [
37
+ {
38
+ title: 'Main nav item 1',
39
+ url: '#0',
40
+ classes: 'custom-class-main-item-1',
41
+ id: 'main-item-1',
42
+ },
43
+ {
44
+ title: 'Main nav item 2',
45
+ url: '#1',
46
+ classes: 'custom-class-main-item-2',
47
+ id: 'main-item-2',
48
+ },
49
+ ],
50
+ subNavigation: {
51
+ id: 'sub-nav',
52
+ overviewURL: '#overview',
53
+ overviewText: 'Overview',
54
+ ariaLabel: 'Section menu',
55
+ currentPath: '#1',
56
+ itemsList: [
57
+ {
58
+ title: 'Sub nav item 1',
59
+ url: '#0',
60
+ classes: 'custom-class-sub-item-1',
61
+ id: 'sub-item-1',
62
+ },
63
+ {
64
+ title: 'Sub nav item 2',
65
+ url: '#1',
66
+ classes: 'custom-class-sub-item-2',
67
+ id: 'sub-item-2',
68
+ sections: [
69
+ {
70
+ sectionTitle: 'Section 1',
71
+ children: [
72
+ {
73
+ title: 'Child item 1',
74
+ url: '#0',
75
+ },
76
+ {
77
+ title: 'Child item 2',
78
+ url: '#1',
79
+ },
80
+ ],
81
+ },
82
+ ],
83
+ },
84
+ ],
85
+ },
86
+ },
87
+ };
88
+
89
+ describe('script: navigation', () => {
90
+ afterEach(async () => {
91
+ // Clear viewport size and browser emulation after each test.
92
+ await jestPuppeteer.resetPage();
93
+ });
94
+
95
+ describe.each([
96
+ ['main', EXAMPLE_NAVIGATION, '.ons-navigation--main', '.ons-js-navigation-button', false],
97
+ ['sub', EXAMPLE_NAVIGATION_WITH_SUBNAVIGATION, '.ons-navigation--sub-mobile', '.ons-js-sub-navigation-button', true],
98
+ ])('level: %s navigation', (_, params, navEl, buttonEl, ariaStatus) => {
99
+ describe('when the component initialises', () => {
100
+ beforeEach(async () => {
101
+ await setTestPage('/test', renderComponent('header', params));
102
+ });
103
+
104
+ it('has removed the display class from the menu toggle button', async () => {
105
+ const hasClass = await page.$eval(buttonEl, node => node.classList.contains('ons-u-d-no'));
106
+ expect(hasClass).toBe(false);
107
+ });
108
+ });
109
+
110
+ describe('when the viewport is large', () => {
111
+ beforeEach(async () => {
112
+ await setViewport(page, { width: 1650, height: 1050 });
113
+ await setTestPage('/test', renderComponent('header', params));
114
+ });
115
+
116
+ it('has the correct aria hidden attribute on the navigation list', async () => {
117
+ const nav = await page.$(navEl);
118
+ const hasAriaAttribute = await nav.evaluate(node => node.getAttribute('aria-hidden') !== null);
119
+ expect(hasAriaAttribute).toBe(ariaStatus);
120
+ });
121
+
122
+ it('has aria-expanded set as `false` on the navigation toggle button', async () => {
123
+ const button = await page.$(buttonEl);
124
+ const ariaExpandedIsFalse = await button.evaluate(node => node.getAttribute('aria-expanded') === 'false');
125
+ expect(ariaExpandedIsFalse).toBe(true);
126
+ });
127
+ });
128
+
129
+ describe('when the viewport is small', () => {
130
+ beforeEach(async () => {
131
+ await setViewport(page, { width: 600, height: 1050 });
132
+ await setTestPage('/test', renderComponent('header', params));
133
+ });
134
+
135
+ it('has aria-hidden set as `true` on the navigation list', async () => {
136
+ const nav = await page.$(navEl);
137
+ const hasAriaAttribute = await nav.evaluate(node => node.getAttribute('aria-hidden') === 'true');
138
+ expect(hasAriaAttribute).toBe(true);
139
+ });
140
+
141
+ describe('when the toggle button is clicked to open the navigation list', () => {
142
+ beforeEach(async () => {
143
+ await page.focus(buttonEl);
144
+ await page.keyboard.press('Enter');
145
+ });
146
+
147
+ it('has aria-hidden set as `false` on the navigation list', async () => {
148
+ const nav = await page.$(navEl);
149
+ const hasAriaAttribute = await nav.evaluate(node => node.getAttribute('aria-hidden') === 'false');
150
+ expect(hasAriaAttribute).toBe(true);
151
+ });
152
+
153
+ it('has the hide class removed from the navigation list', async () => {
154
+ const hasClass = await page.$eval(navEl, node =>
155
+ node.classList.contains('ons-u-d-no@xxs@l' || 'ons-u-d-no' || 'ons-u-d-no@xs@l'),
156
+ );
157
+ expect(hasClass).toBe(false);
158
+ });
159
+
160
+ it('has aria-expanded set as `true` on the navigation toggle button', async () => {
161
+ const button = await page.$(buttonEl);
162
+ const ariaExpandedIsTrue = await button.evaluate(node => node.getAttribute('aria-expanded') === 'true');
163
+ expect(ariaExpandedIsTrue).toBe(true);
164
+ });
165
+
166
+ it('has the correct class applied to the navigation toggle button', async () => {
167
+ const hasClass = await page.$eval(buttonEl, node => node.classList.contains('active'));
168
+ expect(hasClass).toBe(true);
169
+ });
170
+ });
171
+
172
+ describe('when the toggle button is clicked to close the navigation list', () => {
173
+ beforeEach(async () => {
174
+ await page.focus(buttonEl);
175
+ await page.keyboard.press('Enter');
176
+ await page.waitForTimeout(100);
177
+ await page.keyboard.press('Enter');
178
+ await page.waitForTimeout(100);
179
+ });
180
+
181
+ it('has aria-hidden set as `true` on the navigation list', async () => {
182
+ const nav = await page.$(navEl);
183
+ const hasAriaAttribute = await nav.evaluate(node => node.getAttribute('aria-hidden') === 'true');
184
+ expect(hasAriaAttribute).toBe(true);
185
+ });
186
+
187
+ it('has aria-expanded set as `false` on the navigation toggle button', async () => {
188
+ const button = await page.$(buttonEl);
189
+ const ariaExpandedIsTrue = await button.evaluate(node => node.getAttribute('aria-expanded') === 'false');
190
+ expect(ariaExpandedIsTrue).toBe(true);
191
+ });
192
+
193
+ it('has the active class removed from the navigation toggle button', async () => {
194
+ const hasClass = await page.$eval(buttonEl, node => node.classList.contains('active'));
195
+ expect(hasClass).toBe(false);
196
+ });
197
+ });
198
+ });
199
+ });
200
+
201
+ describe.each([['main', EXAMPLE_NAVIGATION, '.ons-navigation--main', '.ons-js-navigation-button']])(
202
+ 'level: %s navigation',
203
+ (_, params, navEl, buttonEl) => {
204
+ describe('when the viewport is small and manually made wider', () => {
205
+ beforeEach(async () => {
206
+ await setViewport(page, { width: 600, height: 1050 });
207
+ await setTestPage('/test', renderComponent('header', params));
208
+ await setViewport(page, { width: 1200, height: 1050 });
209
+ });
210
+
211
+ it('has the aria-hidden attribute removed from the navigation list', async () => {
212
+ const nav = await page.$(navEl);
213
+ const hasAriaAttribute = await nav.evaluate(node => node.getAttribute('aria-hidden') !== null);
214
+ expect(hasAriaAttribute).toBe(false);
215
+ });
216
+
217
+ it('has aria-expanded removed from the navigation toggle button', async () => {
218
+ const button = await page.$(buttonEl);
219
+ const hasAriaExpanded = await button.evaluate(node => node.getAttribute('aria-expanded') !== null);
220
+ expect(hasAriaExpanded).toBe(false);
221
+ });
222
+
223
+ it('has the hide class removed from the navigation list', async () => {
224
+ const hasClass = await page.$eval(navEl, node =>
225
+ node.classList.contains('ons-u-d-no@xxs@l' || 'ons-u-d-no' || 'ons-u-d-no@xs@l'),
226
+ );
227
+ expect(hasClass).toBe(false);
228
+ });
229
+ });
230
+ },
231
+ );
232
+ });
@@ -25,7 +25,7 @@
25
25
  {% endif %}
26
26
 
27
27
 
28
- <nav class="ons-pagination {{ params.classes }}{% if params.hideRangeIndicator is defined and params.hideRangeIndicator %} ons-pagination--no-indicator{% endif %}" arial-label="Pagination ({{ position }})">
28
+ <nav class="ons-pagination {{ params.classes }}{% if params.hideRangeIndicator is defined and params.hideRangeIndicator %} ons-pagination--no-indicator{% endif %}" aria-label="Pagination ({{ position }})">
29
29
  <div class="ons-pagination__position">{{ position }}</div>
30
30
  <ul class="ons-pagination__items">
31
31
  {% if currentPageIndex != 1 %}
@@ -0,0 +1,411 @@
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 PAGINATION_PREV_NEXT_LABELS = {
9
+ previous: 'Previous page',
10
+ next: 'Next page',
11
+ };
12
+
13
+ const EXAMPLE_PAGINATION_MINIMAL = {
14
+ ...PAGINATION_PREV_NEXT_LABELS,
15
+ pages: [{ url: '/page/1', current: true }],
16
+ };
17
+
18
+ describe('macro: pagination', () => {
19
+ it('has additionally provided style classes', () => {
20
+ const $ = cheerio.load(
21
+ renderComponent('pagination', {
22
+ ...EXAMPLE_PAGINATION_MINIMAL,
23
+ classes: 'extra-class another-extra-class',
24
+ }),
25
+ );
26
+
27
+ expect($('.ons-pagination').hasClass('extra-class')).toBe(true);
28
+ expect($('.ons-pagination').hasClass('another-extra-class')).toBe(true);
29
+ });
30
+
31
+ it('has `ons-pagination--no-indicator` style class when `hideRangeIndicator` is `true`', () => {
32
+ const $ = cheerio.load(
33
+ renderComponent('pagination', {
34
+ ...EXAMPLE_PAGINATION_MINIMAL,
35
+ hideRangeIndicator: true,
36
+ }),
37
+ );
38
+
39
+ expect($('.ons-pagination').hasClass('ons-pagination--no-indicator')).toBe(true);
40
+ });
41
+
42
+ it('does not have `ons-pagination--no-indicator` style class when `hideRangeIndicator` is `false`', () => {
43
+ const $ = cheerio.load(
44
+ renderComponent('pagination', {
45
+ ...EXAMPLE_PAGINATION_MINIMAL,
46
+ hideRangeIndicator: false,
47
+ }),
48
+ );
49
+
50
+ expect($('.ons-pagination').hasClass('ons-pagination--no-indicator')).toBe(false);
51
+ });
52
+
53
+ describe('one page', () => {
54
+ const $ = cheerio.load(
55
+ renderComponent('pagination', {
56
+ ...PAGINATION_PREV_NEXT_LABELS,
57
+ pages: [{ url: '/page/1', current: true }],
58
+ }),
59
+ );
60
+
61
+ it('passes jest-axe checks', async () => {
62
+ const results = await axe($.html());
63
+ expect(results).toHaveNoViolations();
64
+ });
65
+
66
+ it('has `aria-label` attribute indicating position within pagination', () => {
67
+ expect($('.ons-pagination').attr('aria-label')).toBe('Pagination (Page 1 of 1)');
68
+ });
69
+
70
+ it('renders element indicating position within pagination', () => {
71
+ expect(
72
+ $('.ons-pagination__position')
73
+ .text()
74
+ .trim(),
75
+ ).toBe('Page 1 of 1');
76
+ });
77
+
78
+ it('has a single list item', () => {
79
+ expect($('li').length).toBe(1);
80
+ assertIsCurrentPage($('.ons-pagination__item'), '/page/1', 'Current page (Page 1 of 1)', '1');
81
+ });
82
+ });
83
+
84
+ describe('two pages where first is the current page', () => {
85
+ const $ = cheerio.load(
86
+ renderComponent('pagination', {
87
+ ...PAGINATION_PREV_NEXT_LABELS,
88
+ pages: [{ url: '/page/1', current: true }, { url: '/page/2' }],
89
+ }),
90
+ );
91
+
92
+ it('passes jest-axe checks', async () => {
93
+ const results = await axe($.html());
94
+ expect(results).toHaveNoViolations();
95
+ });
96
+
97
+ it('has `aria-label` attribute indicating position within pagination', () => {
98
+ expect($('.ons-pagination').attr('aria-label')).toBe('Pagination (Page 1 of 2)');
99
+ });
100
+
101
+ it('renders element indicating position within pagination', () => {
102
+ expect(
103
+ $('.ons-pagination__position')
104
+ .text()
105
+ .trim(),
106
+ ).toBe('Page 1 of 2');
107
+ });
108
+
109
+ it('has a 3 list items ("1", "2", "Next page")', () => {
110
+ expect($('li').length).toBe(3);
111
+ assertIsCurrentPage($('.ons-pagination__item:nth-child(1)'), '/page/1', 'Current page (Page 1 of 2)', '1');
112
+ assertIsNextPage($('.ons-pagination__item:nth-child(2)'), '/page/2', 'Go to page 2', '2');
113
+ assertIsNextPage($('.ons-pagination__item:nth-child(3)'), '/page/2', 'Go to the next page (Page 2)', 'Next page');
114
+ });
115
+ });
116
+
117
+ describe('two pages where second is the current page', () => {
118
+ const $ = cheerio.load(
119
+ renderComponent('pagination', {
120
+ ...PAGINATION_PREV_NEXT_LABELS,
121
+ pages: [{ url: '/page/1' }, { url: '/page/2', current: true }],
122
+ }),
123
+ );
124
+
125
+ it('passes jest-axe checks', async () => {
126
+ const results = await axe($.html());
127
+ expect(results).toHaveNoViolations();
128
+ });
129
+
130
+ it('has `aria-label` attribute indicating position within pagination', () => {
131
+ expect($('.ons-pagination').attr('aria-label')).toBe('Pagination (Page 2 of 2)');
132
+ });
133
+
134
+ it('renders element indicating position within pagination', () => {
135
+ expect(
136
+ $('.ons-pagination__position')
137
+ .text()
138
+ .trim(),
139
+ ).toBe('Page 2 of 2');
140
+ });
141
+
142
+ it('has a 3 list items ("Previous page", "1", "2")', () => {
143
+ expect($('li').length).toBe(3);
144
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(1)'), '/page/1', 'Go to the previous page (Page 1)', 'Previous page');
145
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(2)'), '/page/1', 'Go to page 1', '1');
146
+ assertIsCurrentPage($('.ons-pagination__item:nth-child(3)'), '/page/2', 'Current page (Page 2 of 2)', '2');
147
+ });
148
+ });
149
+
150
+ describe('three pages where second is the current page', () => {
151
+ const $ = cheerio.load(
152
+ renderComponent('pagination', {
153
+ ...PAGINATION_PREV_NEXT_LABELS,
154
+ pages: [{ url: '/page/1' }, { url: '/page/2', current: true }, { url: '/page/3' }],
155
+ }),
156
+ );
157
+
158
+ it('passes jest-axe checks', async () => {
159
+ const results = await axe($.html());
160
+ expect(results).toHaveNoViolations();
161
+ });
162
+
163
+ it('has `aria-label` attribute indicating position within pagination', () => {
164
+ expect($('.ons-pagination').attr('aria-label')).toBe('Pagination (Page 2 of 3)');
165
+ });
166
+
167
+ it('renders element indicating position within pagination', () => {
168
+ expect(
169
+ $('.ons-pagination__position')
170
+ .text()
171
+ .trim(),
172
+ ).toBe('Page 2 of 3');
173
+ });
174
+
175
+ it('has a 5 list items ("Previous page", "1", "2", "3", "Next page")', () => {
176
+ expect($('li').length).toBe(5);
177
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(1)'), '/page/1', 'Go to the previous page (Page 1)', 'Previous page');
178
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(2)'), '/page/1', 'Go to page 1', '1');
179
+ assertIsCurrentPage($('.ons-pagination__item:nth-child(3)'), '/page/2', 'Current page (Page 2 of 3)', '2');
180
+ assertIsNextPage($('.ons-pagination__item:nth-child(4)'), '/page/3', 'Go to page 3', '3');
181
+ assertIsNextPage($('.ons-pagination__item:nth-child(5)'), '/page/3', 'Go to the next page (Page 3)', 'Next page');
182
+ });
183
+ });
184
+
185
+ describe('five pages where second is the current page', () => {
186
+ const $ = cheerio.load(
187
+ renderComponent('pagination', {
188
+ ...PAGINATION_PREV_NEXT_LABELS,
189
+ pages: [{ url: '/page/1' }, { url: '/page/2', current: true }, { url: '/page/3' }, { url: '/page/4' }, { url: '/page/5' }],
190
+ }),
191
+ );
192
+
193
+ it('passes jest-axe checks', async () => {
194
+ const results = await axe($.html());
195
+ expect(results).toHaveNoViolations();
196
+ });
197
+
198
+ it('has `aria-label` attribute indicating position within pagination', () => {
199
+ expect($('.ons-pagination').attr('aria-label')).toBe('Pagination (Page 2 of 5)');
200
+ });
201
+
202
+ it('renders element indicating position within pagination', () => {
203
+ expect(
204
+ $('.ons-pagination__position')
205
+ .text()
206
+ .trim(),
207
+ ).toBe('Page 2 of 5');
208
+ });
209
+
210
+ it('has a 7 list items ("Previous page", "1", "2", "3", "4", "5", "Next page")', () => {
211
+ expect($('li').length).toBe(7);
212
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(1)'), '/page/1', 'Go to the previous page (Page 1)', 'Previous page');
213
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(2)'), '/page/1', 'Go to page 1', '1');
214
+ assertIsCurrentPage($('.ons-pagination__item:nth-child(3)'), '/page/2', 'Current page (Page 2 of 5)', '2');
215
+ assertIsNextPage($('.ons-pagination__item:nth-child(4)'), '/page/3', 'Go to page 3', '3');
216
+ assertIsOtherPage($('.ons-pagination__item:nth-child(5)'), '/page/4', 'Go to page 4', '4');
217
+ assertIsOtherPage($('.ons-pagination__item:nth-child(6)'), '/page/5', 'Go to the last page (Page 5)', '5');
218
+ assertIsNextPage($('.ons-pagination__item:nth-child(7)'), '/page/3', 'Go to the next page (Page 3)', 'Next page');
219
+ });
220
+ });
221
+
222
+ describe('six pages where second is the current page', () => {
223
+ const $ = cheerio.load(
224
+ renderComponent('pagination', {
225
+ ...PAGINATION_PREV_NEXT_LABELS,
226
+ pages: [
227
+ { url: '/page/1' },
228
+ { url: '/page/2', current: true },
229
+ { url: '/page/3' },
230
+ { url: '/page/4' },
231
+ { url: '/page/5' },
232
+ { url: '/page/6' },
233
+ ],
234
+ }),
235
+ );
236
+
237
+ it('passes jest-axe checks', async () => {
238
+ const results = await axe($.html());
239
+ expect(results).toHaveNoViolations();
240
+ });
241
+
242
+ it('has `aria-label` attribute indicating position within pagination', () => {
243
+ expect($('.ons-pagination').attr('aria-label')).toBe('Pagination (Page 2 of 6)');
244
+ });
245
+
246
+ it('renders element indicating position within pagination', () => {
247
+ expect(
248
+ $('.ons-pagination__position')
249
+ .text()
250
+ .trim(),
251
+ ).toBe('Page 2 of 6');
252
+ });
253
+
254
+ it('has a 8 list items ("Previous page", "1", "2", "3", "4", "...", "6", "Next page")', () => {
255
+ expect($('li').length).toBe(8);
256
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(1)'), '/page/1', 'Go to the previous page (Page 1)', 'Previous page');
257
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(2)'), '/page/1', 'Go to page 1', '1');
258
+ assertIsCurrentPage($('.ons-pagination__item:nth-child(3)'), '/page/2', 'Current page (Page 2 of 6)', '2');
259
+ assertIsNextPage($('.ons-pagination__item:nth-child(4)'), '/page/3', 'Go to page 3', '3');
260
+ assertIsOtherPage($('.ons-pagination__item:nth-child(5)'), '/page/4', 'Go to page 4', '4');
261
+ assertIsGap($('.ons-pagination__item:nth-child(6)'));
262
+ assertIsOtherPage($('.ons-pagination__item:nth-child(7)'), '/page/6', 'Go to the last page (Page 6)', '6');
263
+ assertIsNextPage($('.ons-pagination__item:nth-child(8)'), '/page/3', 'Go to the next page (Page 3)', 'Next page');
264
+ });
265
+ });
266
+
267
+ describe('eleven pages where fifth is the current page', () => {
268
+ const $ = cheerio.load(
269
+ renderComponent('pagination', {
270
+ ...PAGINATION_PREV_NEXT_LABELS,
271
+ pages: [
272
+ { url: '/page/1' },
273
+ { url: '/page/2' },
274
+ { url: '/page/3' },
275
+ { url: '/page/4' },
276
+ { url: '/page/5', current: true },
277
+ { url: '/page/6' },
278
+ { url: '/page/7' },
279
+ { url: '/page/8' },
280
+ { url: '/page/9' },
281
+ { url: '/page/10' },
282
+ { url: '/page/11' },
283
+ ],
284
+ }),
285
+ );
286
+
287
+ it('passes jest-axe checks', async () => {
288
+ const results = await axe($.html());
289
+ expect(results).toHaveNoViolations();
290
+ });
291
+
292
+ it('has `aria-label` attribute indicating position within pagination', () => {
293
+ expect($('.ons-pagination').attr('aria-label')).toBe('Pagination (Page 5 of 11)');
294
+ });
295
+
296
+ it('renders element indicating position within pagination', () => {
297
+ expect(
298
+ $('.ons-pagination__position')
299
+ .text()
300
+ .trim(),
301
+ ).toBe('Page 5 of 11');
302
+ });
303
+
304
+ it('has a 11 list items ("Previous page", "1", "...", "3", "4", "5", "6", "7", "...", "11", "Next page")', () => {
305
+ expect($('li').length).toBe(11);
306
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(1)'), '/page/4', 'Go to the previous page (Page 4)', 'Previous page');
307
+ assertIsOtherPage($('.ons-pagination__item:nth-child(2)'), '/page/1', 'Go to the first page (Page 1)', '1');
308
+ assertIsGap($('.ons-pagination__item:nth-child(3)'));
309
+ assertIsOtherPage($('.ons-pagination__item:nth-child(4)'), '/page/3', 'Go to page 3', '3');
310
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(5)'), '/page/4', 'Go to page 4', '4');
311
+ assertIsCurrentPage($('.ons-pagination__item:nth-child(6)'), '/page/5', 'Current page (Page 5 of 11)', '5');
312
+ assertIsNextPage($('.ons-pagination__item:nth-child(7)'), '/page/6', 'Go to page 6', '6');
313
+ assertIsOtherPage($('.ons-pagination__item:nth-child(8)'), '/page/7', 'Go to page 7', '7');
314
+ assertIsGap($('.ons-pagination__item:nth-child(9)'));
315
+ assertIsOtherPage($('.ons-pagination__item:nth-child(10)'), '/page/11', 'Go to the last page (Page 11)', '11');
316
+ assertIsNextPage($('.ons-pagination__item:nth-child(11)'), '/page/6', 'Go to the next page (Page 6)', 'Next page');
317
+ });
318
+ });
319
+
320
+ describe('eleven pages where tenth is the current page', () => {
321
+ const $ = cheerio.load(
322
+ renderComponent('pagination', {
323
+ ...PAGINATION_PREV_NEXT_LABELS,
324
+ pages: [
325
+ { url: '/page/1' },
326
+ { url: '/page/2' },
327
+ { url: '/page/3' },
328
+ { url: '/page/4' },
329
+ { url: '/page/5' },
330
+ { url: '/page/6' },
331
+ { url: '/page/7' },
332
+ { url: '/page/8' },
333
+ { url: '/page/9' },
334
+ { url: '/page/10', current: true },
335
+ { url: '/page/11' },
336
+ ],
337
+ }),
338
+ );
339
+
340
+ it('passes jest-axe checks', async () => {
341
+ const results = await axe($.html());
342
+ expect(results).toHaveNoViolations();
343
+ });
344
+
345
+ it('has `aria-label` attribute indicating position within pagination', () => {
346
+ expect($('.ons-pagination').attr('aria-label')).toBe('Pagination (Page 10 of 11)');
347
+ });
348
+
349
+ it('renders element indicating position within pagination', () => {
350
+ expect(
351
+ $('.ons-pagination__position')
352
+ .text()
353
+ .trim(),
354
+ ).toBe('Page 10 of 11');
355
+ });
356
+
357
+ it('has a 9 list items ("Previous page", "1", "...", "7", "8", "9", "10", "11", "Next page")', () => {
358
+ expect($('li').length).toBe(9);
359
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(1)'), '/page/9', 'Go to the previous page (Page 9)', 'Previous page');
360
+ assertIsOtherPage($('.ons-pagination__item:nth-child(2)'), '/page/1', 'Go to the first page (Page 1)', '1');
361
+ assertIsGap($('.ons-pagination__item:nth-child(3)'));
362
+ assertIsOtherPage($('.ons-pagination__item:nth-child(4)'), '/page/7', 'Go to page 7', '7');
363
+ assertIsOtherPage($('.ons-pagination__item:nth-child(5)'), '/page/8', 'Go to page 8', '8');
364
+ assertIsPreviousPage($('.ons-pagination__item:nth-child(6)'), '/page/9', 'Go to page 9', '9');
365
+ assertIsCurrentPage($('.ons-pagination__item:nth-child(7)'), '/page/10', 'Current page (Page 10 of 11)', '10');
366
+ assertIsNextPage($('.ons-pagination__item:nth-child(8)'), '/page/11', 'Go to page 11', '11');
367
+ assertIsNextPage($('.ons-pagination__item:nth-child(9)'), '/page/11', 'Go to the next page (Page 11)', 'Next page');
368
+ });
369
+ });
370
+ });
371
+
372
+ function assertIsCurrentPage(pageItem, url, label, text) {
373
+ expect(pageItem.hasClass('ons-pagination__item--current')).toBe(true);
374
+ expect(pageItem.find('.ons-pagination__link').attr('href')).toBe(url);
375
+ expect(pageItem.find('.ons-pagination__link').attr('aria-current')).toBe('true');
376
+ expect(pageItem.find('.ons-pagination__link').attr('aria-label')).toBe(label);
377
+ expect(
378
+ pageItem
379
+ .find('.ons-pagination__link')
380
+ .text()
381
+ .trim(),
382
+ ).toBe(text);
383
+ }
384
+
385
+ function assertIsOtherPage(pageItem, url, label, text) {
386
+ expect(pageItem.hasClass('ons-pagination__item--current')).toBe(false);
387
+ expect(pageItem.find('.ons-pagination__link').attr('href')).toBe(url);
388
+ expect(pageItem.find('.ons-pagination__link').attr('aria-current')).toBeUndefined();
389
+ expect(pageItem.find('.ons-pagination__link').attr('aria-label')).toBe(label);
390
+ expect(
391
+ pageItem
392
+ .find('.ons-pagination__link')
393
+ .text()
394
+ .trim(),
395
+ ).toBe(text);
396
+ }
397
+
398
+ function assertIsPreviousPage(pageItem, url, label, text) {
399
+ assertIsOtherPage(pageItem, url, label, text);
400
+ expect(pageItem.find('.ons-pagination__link').attr('rel')).toBe('prev');
401
+ }
402
+
403
+ function assertIsNextPage(pageItem, url, label, text) {
404
+ assertIsOtherPage(pageItem, url, label, text);
405
+ expect(pageItem.find('.ons-pagination__link').attr('rel')).toBe('next');
406
+ }
407
+
408
+ function assertIsGap(pageItem) {
409
+ expect(pageItem.hasClass('ons-pagination__item--gap')).toBe(true);
410
+ expect(pageItem.text().trim()).toBe('…');
411
+ }