@afixt/test-utils 1.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/.editorconfig +13 -0
- package/.eslintrc +78 -0
- package/.gitattributes +5 -0
- package/.nvmrc +1 -0
- package/CLAUDE.md +33 -0
- package/README.md +72 -0
- package/docs/arrayUtils.js.html +69 -0
- package/docs/data/search.json +1 -0
- package/docs/domUtils.js.html +182 -0
- package/docs/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/getAccessibleName.js.html +456 -0
- package/docs/getAccessibleText.js.html +65 -0
- package/docs/getAriaAttributesByElement.js.html +22 -0
- package/docs/getCSSGeneratedContent.js.html +62 -0
- package/docs/getComputedRole.js.html +172 -0
- package/docs/getFocusableElements.js.html +29 -0
- package/docs/getGeneratedContent.js.html +18 -0
- package/docs/getImageText.js.html +28 -0
- package/docs/getStyleObject.js.html +48 -0
- package/docs/global.html +3 -0
- package/docs/hasAccessibleName.js.html +30 -0
- package/docs/hasAttribute.js.html +18 -0
- package/docs/hasCSSGeneratedContent.js.html +23 -0
- package/docs/hasHiddenParent.js.html +32 -0
- package/docs/hasParent.js.html +57 -0
- package/docs/hasValidAriaAttributes.js.html +33 -0
- package/docs/hasValidAriaRole.js.html +32 -0
- package/docs/index.html +3 -0
- package/docs/index.js.html +66 -0
- package/docs/isAriaAttributesValid.js.html +76 -0
- package/docs/isComplexTable.js.html +112 -0
- package/docs/isDataTable.js.html +241 -0
- package/docs/isFocusable.js.html +37 -0
- package/docs/isHidden.js.html +20 -0
- package/docs/isOffScreen.js.html +19 -0
- package/docs/isValidUrl.js.html +16 -0
- package/docs/isVisible.js.html +65 -0
- package/docs/module-afixt-test-utils.html +3 -0
- package/docs/scripts/core.js +726 -0
- package/docs/scripts/core.min.js +23 -0
- package/docs/scripts/resize.js +90 -0
- package/docs/scripts/search.js +265 -0
- package/docs/scripts/search.min.js +6 -0
- package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
- package/docs/scripts/third-party/fuse.js +9 -0
- package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
- package/docs/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/scripts/third-party/hljs-original.js +5171 -0
- package/docs/scripts/third-party/hljs.js +1 -0
- package/docs/scripts/third-party/popper.js +5 -0
- package/docs/scripts/third-party/tippy.js +1 -0
- package/docs/scripts/third-party/tocbot.js +672 -0
- package/docs/scripts/third-party/tocbot.min.js +1 -0
- package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
- package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
- package/docs/styles/clean-jsdoc-theme-light.css +482 -0
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
- package/docs/styles/clean-jsdoc-theme.min.css +1 -0
- package/docs/testContrast.js.html +236 -0
- package/docs/testLang.js.html +578 -0
- package/docs/testOrder.js.html +93 -0
- package/jsdoc.json +67 -0
- package/package.json +32 -0
- package/src/arrayUtils.js +67 -0
- package/src/domUtils.js +179 -0
- package/src/getAccessibleName.js +454 -0
- package/src/getAccessibleText.js +63 -0
- package/src/getAriaAttributesByElement.js +19 -0
- package/src/getCSSGeneratedContent.js +60 -0
- package/src/getComputedRole.js +169 -0
- package/src/getFocusableElements.js +26 -0
- package/src/getGeneratedContent.js +15 -0
- package/src/getImageText.js +25 -0
- package/src/getStyleObject.js +45 -0
- package/src/hasAccessibleName.js +28 -0
- package/src/hasAttribute.js +15 -0
- package/src/hasCSSGeneratedContent.js +20 -0
- package/src/hasHiddenParent.js +29 -0
- package/src/hasParent.js +54 -0
- package/src/hasValidAriaAttributes.js +30 -0
- package/src/hasValidAriaRole.js +29 -0
- package/src/index.js +64 -0
- package/src/interactiveRoles.js +20 -0
- package/src/isAriaAttributesValid.js +74 -0
- package/src/isComplexTable.js +109 -0
- package/src/isDataTable.js +239 -0
- package/src/isFocusable.js +34 -0
- package/src/isHidden.js +17 -0
- package/src/isOffScreen.js +16 -0
- package/src/isValidUrl.js +13 -0
- package/src/isVisible.js +62 -0
- package/src/stringUtils.js +150 -0
- package/src/testContrast.js +233 -0
- package/src/testLang.js +575 -0
- package/src/testOrder.js +90 -0
- package/test/_template.test.js +21 -0
- package/test/arrayUtils.test.js +84 -0
- package/test/domUtils.test.js +147 -0
- package/test/generate-test-stubs.js +37 -0
- package/test/getAccessibleName.test.js +113 -0
- package/test/getAccessibleText.test.js +94 -0
- package/test/getAriaAttributesByElement.test.js +112 -0
- package/test/getCSSGeneratedContent.test.js +102 -0
- package/test/getComputedRole.test.js +180 -0
- package/test/getFocusableElements.test.js +134 -0
- package/test/getGeneratedContent.test.js +321 -0
- package/test/getImageText.test.js +21 -0
- package/test/getStyleObject.test.js +134 -0
- package/test/hasAccessibleName.test.js +59 -0
- package/test/hasAttribute.test.js +132 -0
- package/test/hasCSSGeneratedContent.test.js +143 -0
- package/test/hasHiddenParent.test.js +176 -0
- package/test/hasParent.test.js +266 -0
- package/test/hasValidAriaAttributes.test.js +79 -0
- package/test/hasValidAriaRole.test.js +98 -0
- package/test/isAriaAttributesValid.test.js +83 -0
- package/test/isComplexTable.test.js +363 -0
- package/test/isDataTable.test.js +948 -0
- package/test/isFocusable.test.js +182 -0
- package/test/isHidden.test.js +157 -0
- package/test/isOffScreen.test.js +249 -0
- package/test/isValidUrl.test.js +63 -0
- package/test/isVisible.test.js +104 -0
- package/test/setup.js +11 -0
- package/test/stringUtils.test.js +106 -0
- package/test/testContrast.test.js +77 -0
- package/test/testLang.test.js +21 -0
- package/test/testOrder.test.js +157 -0
- package/vitest.config.js +25 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { hasParent } from '../src/hasParent.js';
|
|
3
|
+
|
|
4
|
+
describe('hasParent', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('should return true when element has parent matching a tag selector', () => {
|
|
10
|
+
// Arrange
|
|
11
|
+
const structure = `
|
|
12
|
+
<div>
|
|
13
|
+
<section>
|
|
14
|
+
<p id="target">Test</p>
|
|
15
|
+
</section>
|
|
16
|
+
</div>
|
|
17
|
+
`;
|
|
18
|
+
document.body.innerHTML = structure;
|
|
19
|
+
const target = document.getElementById('target');
|
|
20
|
+
|
|
21
|
+
// Act
|
|
22
|
+
const result = hasParent(target, ['section']);
|
|
23
|
+
|
|
24
|
+
// Assert
|
|
25
|
+
expect(result).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should return true when element has parent matching a class selector', () => {
|
|
29
|
+
// Arrange
|
|
30
|
+
const structure = `
|
|
31
|
+
<div>
|
|
32
|
+
<section class="test-class">
|
|
33
|
+
<p id="target">Test</p>
|
|
34
|
+
</section>
|
|
35
|
+
</div>
|
|
36
|
+
`;
|
|
37
|
+
document.body.innerHTML = structure;
|
|
38
|
+
const target = document.getElementById('target');
|
|
39
|
+
|
|
40
|
+
// Act
|
|
41
|
+
const result = hasParent(target, ['.test-class']);
|
|
42
|
+
|
|
43
|
+
// Assert
|
|
44
|
+
expect(result).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should return true when element has parent matching an ID selector', () => {
|
|
48
|
+
// Arrange
|
|
49
|
+
const structure = `
|
|
50
|
+
<div>
|
|
51
|
+
<section id="test-id">
|
|
52
|
+
<p id="target">Test</p>
|
|
53
|
+
</section>
|
|
54
|
+
</div>
|
|
55
|
+
`;
|
|
56
|
+
document.body.innerHTML = structure;
|
|
57
|
+
const target = document.getElementById('target');
|
|
58
|
+
|
|
59
|
+
// Act
|
|
60
|
+
const result = hasParent(target, ['#test-id']);
|
|
61
|
+
|
|
62
|
+
// Assert
|
|
63
|
+
expect(result).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should return true when element has parent matching an attribute selector', () => {
|
|
67
|
+
// Arrange
|
|
68
|
+
const structure = `
|
|
69
|
+
<div>
|
|
70
|
+
<section data-test="value">
|
|
71
|
+
<p id="target">Test</p>
|
|
72
|
+
</section>
|
|
73
|
+
</div>
|
|
74
|
+
`;
|
|
75
|
+
document.body.innerHTML = structure;
|
|
76
|
+
const target = document.getElementById('target');
|
|
77
|
+
|
|
78
|
+
// Act
|
|
79
|
+
const result = hasParent(target, ['[data-test="value"]']);
|
|
80
|
+
|
|
81
|
+
// Assert
|
|
82
|
+
expect(result).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should return true when element has grandparent matching a selector', () => {
|
|
86
|
+
// Arrange
|
|
87
|
+
const structure = `
|
|
88
|
+
<div class="grandparent">
|
|
89
|
+
<section>
|
|
90
|
+
<p id="target">Test</p>
|
|
91
|
+
</section>
|
|
92
|
+
</div>
|
|
93
|
+
`;
|
|
94
|
+
document.body.innerHTML = structure;
|
|
95
|
+
const target = document.getElementById('target');
|
|
96
|
+
|
|
97
|
+
// Act
|
|
98
|
+
const result = hasParent(target, ['.grandparent']);
|
|
99
|
+
|
|
100
|
+
// Assert
|
|
101
|
+
expect(result).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should return true when any of multiple selectors matches', () => {
|
|
105
|
+
// Arrange
|
|
106
|
+
const structure = `
|
|
107
|
+
<div>
|
|
108
|
+
<section class="parent-class">
|
|
109
|
+
<p id="target">Test</p>
|
|
110
|
+
</section>
|
|
111
|
+
</div>
|
|
112
|
+
`;
|
|
113
|
+
document.body.innerHTML = structure;
|
|
114
|
+
const target = document.getElementById('target');
|
|
115
|
+
|
|
116
|
+
// Act
|
|
117
|
+
const result = hasParent(target, ['article', '.parent-class', '#non-existent']);
|
|
118
|
+
|
|
119
|
+
// Assert
|
|
120
|
+
expect(result).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should return false when no selectors match any parent', () => {
|
|
124
|
+
// Arrange
|
|
125
|
+
const structure = `
|
|
126
|
+
<div>
|
|
127
|
+
<section>
|
|
128
|
+
<p id="target">Test</p>
|
|
129
|
+
</section>
|
|
130
|
+
</div>
|
|
131
|
+
`;
|
|
132
|
+
document.body.innerHTML = structure;
|
|
133
|
+
const target = document.getElementById('target');
|
|
134
|
+
|
|
135
|
+
// Act
|
|
136
|
+
const result = hasParent(target, ['article', '.non-existent', '#missing']);
|
|
137
|
+
|
|
138
|
+
// Assert
|
|
139
|
+
expect(result).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should return false when element has no parent elements', () => {
|
|
143
|
+
// Arrange
|
|
144
|
+
const element = document.createElement('div');
|
|
145
|
+
document.body.appendChild(element);
|
|
146
|
+
|
|
147
|
+
// Act
|
|
148
|
+
const result = hasParent(element, ['div', 'section']);
|
|
149
|
+
|
|
150
|
+
// Assert
|
|
151
|
+
expect(result).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should handle case-insensitive tag name matching', () => {
|
|
155
|
+
// Arrange
|
|
156
|
+
const structure = `
|
|
157
|
+
<div>
|
|
158
|
+
<SECTION>
|
|
159
|
+
<p id="target">Test</p>
|
|
160
|
+
</SECTION>
|
|
161
|
+
</div>
|
|
162
|
+
`;
|
|
163
|
+
document.body.innerHTML = structure;
|
|
164
|
+
const target = document.getElementById('target');
|
|
165
|
+
|
|
166
|
+
// Act
|
|
167
|
+
const resultLower = hasParent(target, ['section']);
|
|
168
|
+
const resultUpper = hasParent(target, ['SECTION']);
|
|
169
|
+
|
|
170
|
+
// Assert
|
|
171
|
+
expect(resultLower).toBe(true);
|
|
172
|
+
expect(resultUpper).toBe(true);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should return false for null or undefined elements', () => {
|
|
176
|
+
// Act & Assert
|
|
177
|
+
expect(hasParent(null, ['div'])).toBe(false);
|
|
178
|
+
expect(hasParent(undefined, ['div'])).toBe(false);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should return false for non-Element objects', () => {
|
|
182
|
+
// Arrange
|
|
183
|
+
const nonElements = [{}, [], 123, 'string', () => {}];
|
|
184
|
+
|
|
185
|
+
// Act & Assert
|
|
186
|
+
nonElements.forEach(item => {
|
|
187
|
+
expect(hasParent(item, ['div'])).toBe(false);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should return false for null, undefined, or empty selectors array', () => {
|
|
192
|
+
// Arrange
|
|
193
|
+
const element = document.createElement('div');
|
|
194
|
+
document.body.appendChild(element);
|
|
195
|
+
|
|
196
|
+
// Act & Assert
|
|
197
|
+
expect(hasParent(element, null)).toBe(false);
|
|
198
|
+
expect(hasParent(element, undefined)).toBe(false);
|
|
199
|
+
expect(hasParent(element, [])).toBe(false);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should handle invalid selectors gracefully', () => {
|
|
203
|
+
// Arrange
|
|
204
|
+
const structure = `
|
|
205
|
+
<div>
|
|
206
|
+
<section>
|
|
207
|
+
<p id="target">Test</p>
|
|
208
|
+
</section>
|
|
209
|
+
</div>
|
|
210
|
+
`;
|
|
211
|
+
document.body.innerHTML = structure;
|
|
212
|
+
const target = document.getElementById('target');
|
|
213
|
+
|
|
214
|
+
// Act
|
|
215
|
+
// Use a selector that might cause a DOMException, but we still have a valid one
|
|
216
|
+
const result = hasParent(target, ['section', '>>>:invalid:selector:::']);
|
|
217
|
+
|
|
218
|
+
// Assert
|
|
219
|
+
expect(result).toBe(true); // Should still find the valid 'section' selector
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should handle complex nested DOM structures', () => {
|
|
223
|
+
// Arrange
|
|
224
|
+
const structure = `
|
|
225
|
+
<div id="root" class="root-class">
|
|
226
|
+
<article>
|
|
227
|
+
<section class="level1">
|
|
228
|
+
<div class="level2" data-test="nested">
|
|
229
|
+
<p id="target">Test</p>
|
|
230
|
+
</div>
|
|
231
|
+
</section>
|
|
232
|
+
</article>
|
|
233
|
+
</div>
|
|
234
|
+
`;
|
|
235
|
+
document.body.innerHTML = structure;
|
|
236
|
+
const target = document.getElementById('target');
|
|
237
|
+
|
|
238
|
+
// Act & Assert
|
|
239
|
+
expect(hasParent(target, ['.level2'])).toBe(true);
|
|
240
|
+
expect(hasParent(target, ['section'])).toBe(true);
|
|
241
|
+
expect(hasParent(target, ['article'])).toBe(true);
|
|
242
|
+
expect(hasParent(target, ['#root'])).toBe(true);
|
|
243
|
+
expect(hasParent(target, ['.root-class'])).toBe(true);
|
|
244
|
+
expect(hasParent(target, ['[data-test="nested"]'])).toBe(true);
|
|
245
|
+
expect(hasParent(target, ['span'])).toBe(false); // No span parent
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should find first matching parent when multiple matches exist', () => {
|
|
249
|
+
// Arrange
|
|
250
|
+
const structure = `
|
|
251
|
+
<div class="match">
|
|
252
|
+
<section class="match">
|
|
253
|
+
<p id="target">Test</p>
|
|
254
|
+
</section>
|
|
255
|
+
</div>
|
|
256
|
+
`;
|
|
257
|
+
document.body.innerHTML = structure;
|
|
258
|
+
const target = document.getElementById('target');
|
|
259
|
+
|
|
260
|
+
// Act
|
|
261
|
+
const result = hasParent(target, ['.match']);
|
|
262
|
+
|
|
263
|
+
// Assert
|
|
264
|
+
expect(result).toBe(true); // Should find the immediate .match parent first
|
|
265
|
+
});
|
|
266
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { hasValidAriaAttributes } from '../src/hasValidAriaAttributes';
|
|
3
|
+
|
|
4
|
+
describe('hasValidAriaAttributes', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('should return false for null element', () => {
|
|
10
|
+
expect(hasValidAriaAttributes(null)).toBe(false);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should return false for non-DOM elements', () => {
|
|
14
|
+
expect(hasValidAriaAttributes({})).toBe(false);
|
|
15
|
+
expect(hasValidAriaAttributes([])).toBe(false);
|
|
16
|
+
expect(hasValidAriaAttributes('string')).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should return false for elements with no attributes', () => {
|
|
20
|
+
const div = document.createElement('div');
|
|
21
|
+
document.body.appendChild(div);
|
|
22
|
+
|
|
23
|
+
expect(hasValidAriaAttributes(div)).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should return false for elements with no ARIA attributes', () => {
|
|
27
|
+
const div = document.createElement('div');
|
|
28
|
+
div.setAttribute('id', 'test');
|
|
29
|
+
div.setAttribute('class', 'test-class');
|
|
30
|
+
div.setAttribute('data-test', 'value');
|
|
31
|
+
document.body.appendChild(div);
|
|
32
|
+
|
|
33
|
+
expect(hasValidAriaAttributes(div)).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should return false for elements with invalid ARIA attributes', () => {
|
|
37
|
+
const div = document.createElement('div');
|
|
38
|
+
div.setAttribute('aria-foo', 'bar');
|
|
39
|
+
div.setAttribute('aria-invalid-attr', 'value');
|
|
40
|
+
document.body.appendChild(div);
|
|
41
|
+
|
|
42
|
+
expect(hasValidAriaAttributes(div)).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should return true for elements with valid ARIA attributes', () => {
|
|
46
|
+
const div = document.createElement('div');
|
|
47
|
+
div.setAttribute('aria-label', 'Test Label');
|
|
48
|
+
document.body.appendChild(div);
|
|
49
|
+
|
|
50
|
+
expect(hasValidAriaAttributes(div)).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should return true when element has both valid and invalid attributes', () => {
|
|
54
|
+
const div = document.createElement('div');
|
|
55
|
+
div.setAttribute('aria-foo', 'invalid');
|
|
56
|
+
div.setAttribute('aria-hidden', 'true');
|
|
57
|
+
document.body.appendChild(div);
|
|
58
|
+
|
|
59
|
+
expect(hasValidAriaAttributes(div)).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should be case-insensitive for attribute names', () => {
|
|
63
|
+
const div = document.createElement('div');
|
|
64
|
+
div.setAttribute('ARIA-LABEL', 'Test Label');
|
|
65
|
+
document.body.appendChild(div);
|
|
66
|
+
|
|
67
|
+
expect(hasValidAriaAttributes(div)).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should check multiple valid ARIA attributes', () => {
|
|
71
|
+
const button = document.createElement('button');
|
|
72
|
+
button.setAttribute('aria-expanded', 'false');
|
|
73
|
+
button.setAttribute('aria-controls', 'panel-1');
|
|
74
|
+
button.setAttribute('aria-pressed', 'false');
|
|
75
|
+
document.body.appendChild(button);
|
|
76
|
+
|
|
77
|
+
expect(hasValidAriaAttributes(button)).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { hasValidAriaRole } from '../src/hasValidAriaRole.js';
|
|
3
|
+
|
|
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);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { isAriaAttributeValid } from '../src/isAriaAttributesValid';
|
|
3
|
+
|
|
4
|
+
describe('isAriaAttributeValid', () => {
|
|
5
|
+
it('should return false for null or undefined input', () => {
|
|
6
|
+
expect(isAriaAttributeValid(null)).toBe(false);
|
|
7
|
+
expect(isAriaAttributeValid(undefined)).toBe(false);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should return false for non-string input', () => {
|
|
11
|
+
expect(isAriaAttributeValid(123)).toBe(false);
|
|
12
|
+
expect(isAriaAttributeValid({})).toBe(false);
|
|
13
|
+
expect(isAriaAttributeValid([])).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return false for non-aria attributes', () => {
|
|
17
|
+
expect(isAriaAttributeValid('id')).toBe(false);
|
|
18
|
+
expect(isAriaAttributeValid('class')).toBe(false);
|
|
19
|
+
expect(isAriaAttributeValid('data-test')).toBe(false);
|
|
20
|
+
expect(isAriaAttributeValid('role')).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should return false for invalid aria attributes', () => {
|
|
24
|
+
expect(isAriaAttributeValid('aria-foo')).toBe(false);
|
|
25
|
+
expect(isAriaAttributeValid('aria-testing')).toBe(false);
|
|
26
|
+
expect(isAriaAttributeValid('aria')).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should return true for valid aria attributes', () => {
|
|
30
|
+
expect(isAriaAttributeValid('aria-label')).toBe(true);
|
|
31
|
+
expect(isAriaAttributeValid('aria-hidden')).toBe(true);
|
|
32
|
+
expect(isAriaAttributeValid('aria-expanded')).toBe(true);
|
|
33
|
+
expect(isAriaAttributeValid('aria-pressed')).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should be case-insensitive', () => {
|
|
37
|
+
expect(isAriaAttributeValid('ARIA-LABEL')).toBe(true);
|
|
38
|
+
expect(isAriaAttributeValid('Aria-Hidden')).toBe(true);
|
|
39
|
+
expect(isAriaAttributeValid('aria-EXPANDED')).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should validate all standard ARIA attributes', () => {
|
|
43
|
+
const standardAttributes = [
|
|
44
|
+
'aria-activedescendant',
|
|
45
|
+
'aria-atomic',
|
|
46
|
+
'aria-autocomplete',
|
|
47
|
+
'aria-busy',
|
|
48
|
+
'aria-checked',
|
|
49
|
+
'aria-controls',
|
|
50
|
+
'aria-describedby',
|
|
51
|
+
'aria-disabled',
|
|
52
|
+
'aria-expanded',
|
|
53
|
+
'aria-haspopup',
|
|
54
|
+
'aria-hidden',
|
|
55
|
+
'aria-invalid',
|
|
56
|
+
'aria-label',
|
|
57
|
+
'aria-labelledby',
|
|
58
|
+
'aria-level',
|
|
59
|
+
'aria-live',
|
|
60
|
+
'aria-multiline',
|
|
61
|
+
'aria-multiselectable',
|
|
62
|
+
'aria-orientation',
|
|
63
|
+
'aria-owns',
|
|
64
|
+
'aria-placeholder',
|
|
65
|
+
'aria-posinset',
|
|
66
|
+
'aria-pressed',
|
|
67
|
+
'aria-readonly',
|
|
68
|
+
'aria-relevant',
|
|
69
|
+
'aria-required',
|
|
70
|
+
'aria-selected',
|
|
71
|
+
'aria-setsize',
|
|
72
|
+
'aria-sort',
|
|
73
|
+
'aria-valuemax',
|
|
74
|
+
'aria-valuemin',
|
|
75
|
+
'aria-valuenow',
|
|
76
|
+
'aria-valuetext'
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
standardAttributes.forEach(attr => {
|
|
80
|
+
expect(isAriaAttributeValid(attr)).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|