@afixt/test-utils 2.3.0 → 2.5.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.
@@ -300,6 +300,32 @@ describe('getAccessibleText', () => {
300
300
  });
301
301
  });
302
302
 
303
+ describe('child role="img" with aria-label in subtree', () => {
304
+ it('should get aria-label from child elements with role="img"', () => {
305
+ const container = document.createElement('div');
306
+ container.innerHTML = '<div role="img" aria-label="Company Logo"></div>';
307
+ document.body.appendChild(container);
308
+
309
+ expect(getAccessibleText(container)).toBe('Company Logo');
310
+ });
311
+
312
+ it('should skip role="img" elements with empty aria-label', () => {
313
+ const container = document.createElement('div');
314
+ container.innerHTML = 'Label <div role="img" aria-label=""></div>';
315
+ document.body.appendChild(container);
316
+
317
+ expect(getAccessibleText(container)).toBe('Label');
318
+ });
319
+
320
+ it('should skip role="img" elements without aria-label', () => {
321
+ const container = document.createElement('div');
322
+ container.innerHTML = 'Label <div role="img"></div>';
323
+ document.body.appendChild(container);
324
+
325
+ expect(getAccessibleText(container)).toBe('Label');
326
+ });
327
+ });
328
+
303
329
  describe('visibleOnly option', () => {
304
330
  it('should skip aria-label when visibleOnly is true', () => {
305
331
  const div = document.createElement('div');
@@ -2,159 +2,278 @@ import { describe, it, expect, beforeEach } from 'vitest';
2
2
  import { hasValidAriaRole } from '../src/hasValidAriaRole.js';
3
3
 
4
4
  describe('hasValidAriaRole', () => {
5
- beforeEach(() => {
6
- document.body.innerHTML = '';
7
- });
8
-
9
- it('should return true for an element with a valid ARIA role', () => {
10
- // Arrange
11
- const element = document.createElement('div');
12
- element.setAttribute('role', 'button');
13
- document.body.appendChild(element);
14
-
15
- // Act
16
- const result = hasValidAriaRole(element);
17
-
18
- // Assert
19
- expect(result).toBe(true);
20
- });
21
-
22
- it('should return false for an element with an invalid ARIA role', () => {
23
- // Arrange
24
- const element = document.createElement('div');
25
- element.setAttribute('role', 'invalid-role');
26
- document.body.appendChild(element);
27
-
28
- // Act
29
- const result = hasValidAriaRole(element);
30
-
31
- // Assert
32
- expect(result).toBe(false);
33
- });
34
-
35
- it('should return false for an element without a role attribute', () => {
36
- // Arrange
37
- const element = document.createElement('div');
38
- document.body.appendChild(element);
39
-
40
- // Act
41
- const result = hasValidAriaRole(element);
42
-
43
- // Assert
44
- expect(result).toBe(false);
45
- });
46
-
47
- it('should return false for null or non-element input', () => {
48
- // Act & Assert
49
- expect(hasValidAriaRole(null)).toBe(false);
50
- expect(hasValidAriaRole(undefined)).toBe(false);
51
- expect(hasValidAriaRole({})).toBe(false);
52
- expect(hasValidAriaRole('')).toBe(false);
53
- });
54
-
55
- it('should correctly handle elements with multiple roles (should use the first one)', () => {
56
- // Arrange
57
- const validMultipleRoles = document.createElement('div');
58
- validMultipleRoles.setAttribute('role', 'button presentation');
59
-
60
- const invalidMultipleRoles = document.createElement('div');
61
- invalidMultipleRoles.setAttribute('role', 'invalid-role button');
62
-
63
- document.body.appendChild(validMultipleRoles);
64
- document.body.appendChild(invalidMultipleRoles);
65
-
66
- // Act & Assert
67
- expect(hasValidAriaRole(validMultipleRoles)).toBe(true);
68
- expect(hasValidAriaRole(invalidMultipleRoles)).toBe(false);
69
- });
70
-
71
- it('should handle roles with extra whitespace', () => {
72
- // Arrange
73
- const element = document.createElement('div');
74
- element.setAttribute('role', ' button ');
75
- document.body.appendChild(element);
76
-
77
- // Act
78
- const result = hasValidAriaRole(element);
79
-
80
- // Assert
81
- expect(result).toBe(true);
82
- });
83
-
84
- it('should recognize various valid roles', () => {
85
- // Test a sample of different valid roles
86
- const validRoles = ['alert', 'button', 'checkbox', 'dialog', 'navigation', 'main', 'region'];
87
-
88
- validRoles.forEach(role => {
89
- // Arrange
90
- const element = document.createElement('div');
91
- element.setAttribute('role', role);
92
- document.body.appendChild(element);
93
-
94
- // Act & Assert
95
- expect(hasValidAriaRole(element)).toBe(true);
5
+ beforeEach(() => {
6
+ document.body.innerHTML = '';
96
7
  });
97
- });
98
-
99
- it('should recognize all widget roles', () => {
100
- const widgetRoles = [
101
- 'alertdialog', 'gridcell', 'link', 'log', 'marquee', 'menuitem',
102
- 'menuitemcheckbox', 'menuitemradio', 'option', 'progressbar', 'radio',
103
- 'scrollbar', 'searchbox', 'slider', 'spinbutton', 'status', 'switch',
104
- 'tab', 'tabpanel', 'textbox', 'tooltip', 'treeitem'
105
- ];
106
-
107
- widgetRoles.forEach(role => {
108
- const element = document.createElement('div');
109
- element.setAttribute('role', role);
110
- expect(hasValidAriaRole(element)).toBe(true);
8
+
9
+ it('should return true for an element with a valid ARIA role', () => {
10
+ // Arrange
11
+ const element = document.createElement('div');
12
+ element.setAttribute('role', 'button');
13
+ document.body.appendChild(element);
14
+
15
+ // Act
16
+ const result = hasValidAriaRole(element);
17
+
18
+ // Assert
19
+ expect(result).toBe(true);
20
+ });
21
+
22
+ it('should return false for an element with an invalid ARIA role', () => {
23
+ // Arrange
24
+ const element = document.createElement('div');
25
+ element.setAttribute('role', 'invalid-role');
26
+ document.body.appendChild(element);
27
+
28
+ // Act
29
+ const result = hasValidAriaRole(element);
30
+
31
+ // Assert
32
+ expect(result).toBe(false);
33
+ });
34
+
35
+ it('should return false for an element without a role attribute', () => {
36
+ // Arrange
37
+ const element = document.createElement('div');
38
+ document.body.appendChild(element);
39
+
40
+ // Act
41
+ const result = hasValidAriaRole(element);
42
+
43
+ // Assert
44
+ expect(result).toBe(false);
111
45
  });
112
- });
113
-
114
- it('should recognize all composite widget roles', () => {
115
- const compositeRoles = [
116
- 'combobox', 'grid', 'listbox', 'menu', 'menubar', 'radiogroup',
117
- 'tablist', 'tree', 'treegrid'
118
- ];
119
-
120
- compositeRoles.forEach(role => {
121
- const element = document.createElement('div');
122
- element.setAttribute('role', role);
123
- expect(hasValidAriaRole(element)).toBe(true);
46
+
47
+ it('should return false for null or non-element input', () => {
48
+ // Act & Assert
49
+ expect(hasValidAriaRole(null)).toBe(false);
50
+ expect(hasValidAriaRole(undefined)).toBe(false);
51
+ expect(hasValidAriaRole({})).toBe(false);
52
+ expect(hasValidAriaRole('')).toBe(false);
124
53
  });
125
- });
126
-
127
- it('should recognize all document structure roles', () => {
128
- const structureRoles = [
129
- 'article', 'cell', 'columnheader', 'definition', 'directory', 'document',
130
- 'feed', 'figure', 'group', 'heading', 'img', 'list', 'listitem', 'math',
131
- 'none', 'note', 'presentation', 'row', 'rowgroup', 'rowheader',
132
- 'separator', 'table', 'term', 'toolbar'
133
- ];
134
-
135
- structureRoles.forEach(role => {
136
- const element = document.createElement('div');
137
- element.setAttribute('role', role);
138
- expect(hasValidAriaRole(element)).toBe(true);
54
+
55
+ it('should correctly handle elements with multiple roles (should use the first one)', () => {
56
+ // Arrange
57
+ const validMultipleRoles = document.createElement('div');
58
+ validMultipleRoles.setAttribute('role', 'button presentation');
59
+
60
+ const invalidMultipleRoles = document.createElement('div');
61
+ invalidMultipleRoles.setAttribute('role', 'invalid-role button');
62
+
63
+ document.body.appendChild(validMultipleRoles);
64
+ document.body.appendChild(invalidMultipleRoles);
65
+
66
+ // Act & Assert
67
+ expect(hasValidAriaRole(validMultipleRoles)).toBe(true);
68
+ expect(hasValidAriaRole(invalidMultipleRoles)).toBe(false);
139
69
  });
140
- });
141
-
142
- it('should recognize all landmark roles', () => {
143
- const landmarkRoles = [
144
- 'application', 'banner', 'complementary', 'contentinfo', 'form',
145
- 'search'
146
- ];
147
-
148
- landmarkRoles.forEach(role => {
149
- const element = document.createElement('div');
150
- element.setAttribute('role', role);
151
- expect(hasValidAriaRole(element)).toBe(true);
70
+
71
+ it('should handle roles with extra whitespace', () => {
72
+ // Arrange
73
+ const element = document.createElement('div');
74
+ element.setAttribute('role', ' button ');
75
+ document.body.appendChild(element);
76
+
77
+ // Act
78
+ const result = hasValidAriaRole(element);
79
+
80
+ // Assert
81
+ expect(result).toBe(true);
82
+ });
83
+
84
+ it('should recognize various valid roles', () => {
85
+ // Test a sample of different valid roles
86
+ const validRoles = [
87
+ 'alert',
88
+ 'button',
89
+ 'checkbox',
90
+ 'dialog',
91
+ 'navigation',
92
+ 'main',
93
+ 'region',
94
+ ];
95
+
96
+ validRoles.forEach(role => {
97
+ // Arrange
98
+ const element = document.createElement('div');
99
+ element.setAttribute('role', role);
100
+ document.body.appendChild(element);
101
+
102
+ // Act & Assert
103
+ expect(hasValidAriaRole(element)).toBe(true);
104
+ });
105
+ });
106
+
107
+ it('should recognize all widget roles', () => {
108
+ const widgetRoles = [
109
+ 'alertdialog',
110
+ 'gridcell',
111
+ 'link',
112
+ 'log',
113
+ 'marquee',
114
+ 'menuitem',
115
+ 'menuitemcheckbox',
116
+ 'menuitemradio',
117
+ 'option',
118
+ 'progressbar',
119
+ 'radio',
120
+ 'scrollbar',
121
+ 'searchbox',
122
+ 'slider',
123
+ 'spinbutton',
124
+ 'status',
125
+ 'switch',
126
+ 'tab',
127
+ 'tabpanel',
128
+ 'textbox',
129
+ 'tooltip',
130
+ 'treeitem',
131
+ ];
132
+
133
+ widgetRoles.forEach(role => {
134
+ const element = document.createElement('div');
135
+ element.setAttribute('role', role);
136
+ expect(hasValidAriaRole(element)).toBe(true);
137
+ });
138
+ });
139
+
140
+ it('should recognize all composite widget roles', () => {
141
+ const compositeRoles = [
142
+ 'combobox',
143
+ 'grid',
144
+ 'listbox',
145
+ 'menu',
146
+ 'menubar',
147
+ 'radiogroup',
148
+ 'tablist',
149
+ 'tree',
150
+ 'treegrid',
151
+ ];
152
+
153
+ compositeRoles.forEach(role => {
154
+ const element = document.createElement('div');
155
+ element.setAttribute('role', role);
156
+ expect(hasValidAriaRole(element)).toBe(true);
157
+ });
158
+ });
159
+
160
+ it('should recognize all document structure roles', () => {
161
+ const structureRoles = [
162
+ 'article',
163
+ 'cell',
164
+ 'columnheader',
165
+ 'definition',
166
+ 'directory',
167
+ 'document',
168
+ 'feed',
169
+ 'figure',
170
+ 'group',
171
+ 'heading',
172
+ 'img',
173
+ 'list',
174
+ 'listitem',
175
+ 'math',
176
+ 'none',
177
+ 'note',
178
+ 'presentation',
179
+ 'row',
180
+ 'rowgroup',
181
+ 'rowheader',
182
+ 'separator',
183
+ 'table',
184
+ 'term',
185
+ 'toolbar',
186
+ ];
187
+
188
+ structureRoles.forEach(role => {
189
+ const element = document.createElement('div');
190
+ element.setAttribute('role', role);
191
+ expect(hasValidAriaRole(element)).toBe(true);
192
+ });
193
+ });
194
+
195
+ it('should recognize all landmark roles', () => {
196
+ const landmarkRoles = [
197
+ 'application',
198
+ 'banner',
199
+ 'complementary',
200
+ 'contentinfo',
201
+ 'form',
202
+ 'search',
203
+ ];
204
+
205
+ landmarkRoles.forEach(role => {
206
+ const element = document.createElement('div');
207
+ element.setAttribute('role', role);
208
+ expect(hasValidAriaRole(element)).toBe(true);
209
+ });
210
+ });
211
+
212
+ it('should recognize timer role', () => {
213
+ const element = document.createElement('div');
214
+ element.setAttribute('role', 'timer');
215
+ expect(hasValidAriaRole(element)).toBe(true);
216
+ });
217
+
218
+ it('should recognize WAI-ARIA Graphics Module roles', () => {
219
+ const graphicsRoles = ['graphics-document', 'graphics-object', 'graphics-symbol'];
220
+
221
+ graphicsRoles.forEach(role => {
222
+ const element = document.createElement('svg');
223
+ element.setAttribute('role', role);
224
+ expect(hasValidAriaRole(element)).toBe(true);
225
+ });
226
+ });
227
+
228
+ it('should recognize DPub-ARIA roles', () => {
229
+ const dpubRoles = [
230
+ 'doc-abstract',
231
+ 'doc-acknowledgments',
232
+ 'doc-afterword',
233
+ 'doc-appendix',
234
+ 'doc-backlink',
235
+ 'doc-biblioentry',
236
+ 'doc-bibliography',
237
+ 'doc-biblioref',
238
+ 'doc-chapter',
239
+ 'doc-colophon',
240
+ 'doc-conclusion',
241
+ 'doc-cover',
242
+ 'doc-credit',
243
+ 'doc-credits',
244
+ 'doc-dedication',
245
+ 'doc-endnote',
246
+ 'doc-endnotes',
247
+ 'doc-epigraph',
248
+ 'doc-epilogue',
249
+ 'doc-errata',
250
+ 'doc-example',
251
+ 'doc-footnote',
252
+ 'doc-foreword',
253
+ 'doc-glossary',
254
+ 'doc-glossref',
255
+ 'doc-index',
256
+ 'doc-introduction',
257
+ 'doc-noteref',
258
+ 'doc-notice',
259
+ 'doc-pagebreak',
260
+ 'doc-pagefooter',
261
+ 'doc-pageheader',
262
+ 'doc-pagelist',
263
+ 'doc-part',
264
+ 'doc-preface',
265
+ 'doc-prologue',
266
+ 'doc-pullquote',
267
+ 'doc-qna',
268
+ 'doc-subtitle',
269
+ 'doc-tip',
270
+ 'doc-toc',
271
+ ];
272
+
273
+ dpubRoles.forEach(role => {
274
+ const element = document.createElement('div');
275
+ element.setAttribute('role', role);
276
+ expect(hasValidAriaRole(element)).toBe(true);
277
+ });
152
278
  });
153
- });
154
-
155
- it('should recognize timer role', () => {
156
- const element = document.createElement('div');
157
- element.setAttribute('role', 'timer');
158
- expect(hasValidAriaRole(element)).toBe(true);
159
- });
160
- });
279
+ });
@@ -73,6 +73,7 @@ describe('index.js exports', () => {
73
73
  it('should export focus management utilities', () => {
74
74
  expect(utils.getFocusableElements).toBeDefined();
75
75
  expect(utils.isFocusable).toBeDefined();
76
+ expect(utils.detectFocusTrap).toBeDefined();
76
77
  });
77
78
 
78
79
  it('should export role computation utilities', () => {
@@ -145,6 +146,7 @@ describe('index.js exports', () => {
145
146
  'isA11yVisible',
146
147
  'hasParent',
147
148
  'getFocusableElements',
149
+ 'detectFocusTrap',
148
150
  'getComputedRole',
149
151
  'getImageText',
150
152
  'testContrast',
@@ -183,6 +185,7 @@ describe('index.js exports', () => {
183
185
  'hasAttribute',
184
186
  'getFocusableElements',
185
187
  'isFocusable',
188
+ 'detectFocusTrap',
186
189
  'getComputedRole',
187
190
  'getImageText',
188
191
  'testContrast',