@afixt/test-utils 1.2.3 → 2.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/.claude/settings.local.json +1 -6
- package/BROWSER_TESTING.md +42 -22
- package/CHANGELOG.md +40 -0
- package/CLAUDE.md +10 -9
- package/package.json +1 -1
- package/src/constants.js +438 -1
- package/src/domUtils.js +17 -38
- package/src/formUtils.js +7 -24
- package/src/getAccessibleName.js +20 -56
- package/src/getCSSGeneratedContent.js +2 -0
- package/src/getFocusableElements.js +12 -21
- package/src/getGeneratedContent.js +18 -11
- package/src/getImageText.js +22 -7
- package/src/hasValidAriaRole.js +11 -19
- package/src/index.js +4 -4
- package/src/interactiveRoles.js +2 -19
- package/src/isA11yVisible.js +95 -0
- package/src/isAriaAttributesValid.js +5 -64
- package/src/isFocusable.js +30 -10
- package/src/isHidden.js +44 -8
- package/src/listEventListeners.js +115 -10
- package/src/stringUtils.js +19 -98
- package/src/tableUtils.js +4 -36
- package/src/testContrast.js +54 -0
- package/test/domUtils.test.js +156 -0
- package/test/formUtils.test.js +0 -47
- package/test/getAccessibleName.test.js +39 -0
- package/test/getGeneratedContent.test.js +305 -241
- package/test/getImageText.test.js +158 -99
- package/test/index.test.js +54 -17
- package/test/{isVisible.test.js → isA11yVisible.test.js} +39 -33
- package/test/isFocusable.test.js +265 -272
- package/test/isHidden.test.js +257 -153
- package/test/listEventListeners.test.js +163 -44
- package/test/playwright/css-pseudo-elements.spec.js +3 -13
- package/test/stringUtils.test.js +55 -228
- package/test/testContrast.test.js +104 -2
- package/todo.md +2 -2
- package/src/isVisible.js +0 -103
|
@@ -1,104 +1,163 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// Basic module mock to prevent tesseract worker initialization
|
|
4
4
|
vi.mock('tesseract.js', () => ({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
default: {
|
|
6
|
+
recognize: vi.fn().mockRejectedValue(new Error('Mocked tesseract error')),
|
|
7
|
+
},
|
|
8
|
+
recognize: vi.fn().mockRejectedValue(new Error('Mocked tesseract error')),
|
|
9
9
|
}));
|
|
10
10
|
|
|
11
11
|
describe('getImageText', () => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
12
|
+
let getImageText;
|
|
13
|
+
let _internal;
|
|
14
|
+
let recognizeSpy;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
const mod = await import('../src/getImageText.js');
|
|
18
|
+
getImageText = mod.getImageText;
|
|
19
|
+
_internal = mod._internal;
|
|
20
|
+
recognizeSpy = vi
|
|
21
|
+
.spyOn(_internal, 'recognize')
|
|
22
|
+
.mockRejectedValue(new Error('Mocked tesseract error'));
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
recognizeSpy.mockRestore();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should be defined and exported from the module', () => {
|
|
30
|
+
expect(typeof getImageText).toBe('function');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should be an async function', () => {
|
|
34
|
+
const result = getImageText('test-path');
|
|
35
|
+
expect(result).toBeInstanceOf(Promise);
|
|
36
|
+
result.catch(() => {});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should handle invalid image paths gracefully', async () => {
|
|
40
|
+
const result = await getImageText('non-existent-file.jpg');
|
|
41
|
+
expect(result).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should handle null or undefined input gracefully', async () => {
|
|
45
|
+
const result1 = await getImageText(null);
|
|
46
|
+
expect(result1).toBe(false);
|
|
47
|
+
|
|
48
|
+
const result2 = await getImageText(undefined);
|
|
49
|
+
expect(result2).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should handle empty string input gracefully', async () => {
|
|
53
|
+
const result = await getImageText('');
|
|
54
|
+
expect(result).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should log errors in non-test environments', async () => {
|
|
58
|
+
const originalEnv = process.env.NODE_ENV;
|
|
59
|
+
const originalError = console.error;
|
|
60
|
+
const errorCalls = [];
|
|
61
|
+
|
|
62
|
+
process.env.NODE_ENV = 'production';
|
|
63
|
+
console.error = (...args) => errorCalls.push(args);
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
await getImageText('invalid-path.jpg');
|
|
67
|
+
expect(errorCalls.length).toBeGreaterThan(0);
|
|
68
|
+
expect(errorCalls[0][0]).toContain('Error processing image');
|
|
69
|
+
} finally {
|
|
70
|
+
process.env.NODE_ENV = originalEnv;
|
|
71
|
+
console.error = originalError;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should default to eng language when no options provided', async () => {
|
|
76
|
+
recognizeSpy.mockResolvedValueOnce({ data: { text: 'hello' } });
|
|
77
|
+
|
|
78
|
+
await getImageText('image.jpg');
|
|
79
|
+
|
|
80
|
+
expect(recognizeSpy).toHaveBeenCalledWith(
|
|
81
|
+
'image.jpg',
|
|
82
|
+
'eng',
|
|
83
|
+
expect.objectContaining({ logger: expect.any(Function) })
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should accept a custom language option', async () => {
|
|
88
|
+
recognizeSpy.mockResolvedValueOnce({ data: { text: 'bonjour' } });
|
|
89
|
+
|
|
90
|
+
await getImageText('image.jpg', { lang: 'fra' });
|
|
91
|
+
|
|
92
|
+
expect(recognizeSpy).toHaveBeenCalledWith(
|
|
93
|
+
'image.jpg',
|
|
94
|
+
'fra',
|
|
95
|
+
expect.objectContaining({ logger: expect.any(Function) })
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should accept multiple languages', async () => {
|
|
100
|
+
recognizeSpy.mockResolvedValueOnce({ data: { text: 'hello welt' } });
|
|
101
|
+
|
|
102
|
+
await getImageText('image.jpg', { lang: 'eng+deu' });
|
|
103
|
+
|
|
104
|
+
expect(recognizeSpy).toHaveBeenCalledWith(
|
|
105
|
+
'image.jpg',
|
|
106
|
+
'eng+deu',
|
|
107
|
+
expect.objectContaining({ logger: expect.any(Function) })
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should accept a custom logger function', async () => {
|
|
112
|
+
recognizeSpy.mockResolvedValueOnce({ data: { text: 'hello' } });
|
|
113
|
+
const customLogger = vi.fn();
|
|
114
|
+
|
|
115
|
+
await getImageText('image.jpg', { logger: customLogger });
|
|
116
|
+
|
|
117
|
+
expect(recognizeSpy).toHaveBeenCalledWith(
|
|
118
|
+
'image.jpg',
|
|
119
|
+
'eng',
|
|
120
|
+
expect.objectContaining({ logger: customLogger })
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should accept null logger to disable logging', async () => {
|
|
125
|
+
recognizeSpy.mockResolvedValueOnce({ data: { text: 'hello' } });
|
|
126
|
+
|
|
127
|
+
await getImageText('image.jpg', { logger: null });
|
|
128
|
+
|
|
129
|
+
expect(recognizeSpy).toHaveBeenCalledWith(
|
|
130
|
+
'image.jpg',
|
|
131
|
+
'eng',
|
|
132
|
+
expect.objectContaining({ logger: null })
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should pass through additional Tesseract options', async () => {
|
|
137
|
+
recognizeSpy.mockResolvedValueOnce({ data: { text: 'hello' } });
|
|
138
|
+
|
|
139
|
+
await getImageText('image.jpg', { lang: 'eng', corePath: '/custom/path' });
|
|
140
|
+
|
|
141
|
+
expect(recognizeSpy).toHaveBeenCalledWith(
|
|
142
|
+
'image.jpg',
|
|
143
|
+
'eng',
|
|
144
|
+
expect.objectContaining({ corePath: '/custom/path', logger: expect.any(Function) })
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should return trimmed text on successful extraction', async () => {
|
|
149
|
+
recognizeSpy.mockResolvedValueOnce({ data: { text: ' hello world ' } });
|
|
150
|
+
|
|
151
|
+
const result = await getImageText('image.jpg');
|
|
152
|
+
|
|
153
|
+
expect(result).toBe('hello world');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should return false for empty or whitespace-only text', async () => {
|
|
157
|
+
recognizeSpy.mockResolvedValueOnce({ data: { text: ' \n\t ' } });
|
|
158
|
+
|
|
159
|
+
const result = await getImageText('image.jpg');
|
|
160
|
+
|
|
161
|
+
expect(result).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
});
|
package/test/index.test.js
CHANGED
|
@@ -62,7 +62,7 @@ describe('index.js exports', () => {
|
|
|
62
62
|
|
|
63
63
|
it('should export visibility utilities', () => {
|
|
64
64
|
expect(utils.isOffScreen).toBeDefined();
|
|
65
|
-
expect(utils.
|
|
65
|
+
expect(utils.isA11yVisible).toBeDefined();
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
it('should export element relationship utilities', () => {
|
|
@@ -109,7 +109,6 @@ describe('index.js exports', () => {
|
|
|
109
109
|
expect(utils.isUpperCase).toBeDefined();
|
|
110
110
|
expect(utils.isAlphaNumeric).toBeDefined();
|
|
111
111
|
expect(utils.getPathFromUrl).toBeDefined();
|
|
112
|
-
expect(utils.getAllText).toBeDefined();
|
|
113
112
|
expect(utils.hasText).toBeDefined();
|
|
114
113
|
});
|
|
115
114
|
|
|
@@ -133,13 +132,28 @@ describe('index.js exports', () => {
|
|
|
133
132
|
|
|
134
133
|
it('should have function exports for utilities', () => {
|
|
135
134
|
const functionExports = [
|
|
136
|
-
'arrayUnique',
|
|
137
|
-
'
|
|
138
|
-
'
|
|
139
|
-
'
|
|
140
|
-
'
|
|
135
|
+
'arrayUnique',
|
|
136
|
+
'arrayRemoveByValue',
|
|
137
|
+
'arrayCount',
|
|
138
|
+
'cleanBlank',
|
|
139
|
+
'hasAttr',
|
|
140
|
+
'attrBegins',
|
|
141
|
+
'getAccessibleText',
|
|
142
|
+
'hasValidAriaAttributes',
|
|
143
|
+
'getCSSGeneratedContent',
|
|
144
|
+
'isComplexTable',
|
|
145
|
+
'isA11yVisible',
|
|
146
|
+
'hasParent',
|
|
147
|
+
'getFocusableElements',
|
|
148
|
+
'getComputedRole',
|
|
149
|
+
'getImageText',
|
|
150
|
+
'testContrast',
|
|
151
|
+
'testLang',
|
|
152
|
+
'isValidUrl',
|
|
153
|
+
'isEmpty',
|
|
154
|
+
'listEventListeners',
|
|
141
155
|
];
|
|
142
|
-
|
|
156
|
+
|
|
143
157
|
functionExports.forEach(funcName => {
|
|
144
158
|
expect(typeof utils[funcName]).toBe('function');
|
|
145
159
|
});
|
|
@@ -147,14 +161,37 @@ describe('index.js exports', () => {
|
|
|
147
161
|
|
|
148
162
|
it('should export all expected utility functions', () => {
|
|
149
163
|
const expectedFunctions = [
|
|
150
|
-
'arrayUnique',
|
|
151
|
-
'
|
|
152
|
-
'
|
|
153
|
-
'
|
|
154
|
-
'
|
|
155
|
-
'
|
|
156
|
-
'
|
|
157
|
-
'
|
|
164
|
+
'arrayUnique',
|
|
165
|
+
'arrayRemoveByValue',
|
|
166
|
+
'arrayCount',
|
|
167
|
+
'cleanBlank',
|
|
168
|
+
'hasAttr',
|
|
169
|
+
'attrBegins',
|
|
170
|
+
'containsNoCase',
|
|
171
|
+
'getAttributes',
|
|
172
|
+
'getAccessibleText',
|
|
173
|
+
'hasValidAriaAttributes',
|
|
174
|
+
'hasValidAriaRole',
|
|
175
|
+
'getCSSGeneratedContent',
|
|
176
|
+
'getGeneratedContent',
|
|
177
|
+
'getStyleObject',
|
|
178
|
+
'isComplexTable',
|
|
179
|
+
'isDataTable',
|
|
180
|
+
'isOffScreen',
|
|
181
|
+
'isA11yVisible',
|
|
182
|
+
'hasParent',
|
|
183
|
+
'hasAttribute',
|
|
184
|
+
'getFocusableElements',
|
|
185
|
+
'isFocusable',
|
|
186
|
+
'getComputedRole',
|
|
187
|
+
'getImageText',
|
|
188
|
+
'testContrast',
|
|
189
|
+
'testLang',
|
|
190
|
+
'testOrder',
|
|
191
|
+
'isValidUrl',
|
|
192
|
+
'isEmpty',
|
|
193
|
+
'isString',
|
|
194
|
+
'listEventListeners',
|
|
158
195
|
];
|
|
159
196
|
|
|
160
197
|
expectedFunctions.forEach(funcName => {
|
|
@@ -162,4 +199,4 @@ describe('index.js exports', () => {
|
|
|
162
199
|
expect(typeof utils[funcName]).toBe('function');
|
|
163
200
|
});
|
|
164
201
|
});
|
|
165
|
-
});
|
|
202
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { isA11yVisible } from '../src/isA11yVisible';
|
|
3
3
|
|
|
4
|
-
describe('
|
|
4
|
+
describe('isA11yVisible', () => {
|
|
5
5
|
beforeEach(() => {
|
|
6
6
|
document.body.innerHTML = '';
|
|
7
7
|
// Reset computed styles
|
|
@@ -15,12 +15,12 @@ describe('isVisible', () => {
|
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
it('should return false for null or undefined elements', () => {
|
|
18
|
-
expect(
|
|
19
|
-
expect(
|
|
18
|
+
expect(isA11yVisible(null)).toBe(false);
|
|
19
|
+
expect(isA11yVisible(undefined)).toBe(false);
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
it('should handle inherently non-visible elements correctly', () => {
|
|
23
|
-
// The behavior of
|
|
23
|
+
// The behavior of isA11yVisible for inherently non-visible elements is to return *false* by default
|
|
24
24
|
// This is a mock test just to make it pass until we can properly test the functionality
|
|
25
25
|
|
|
26
26
|
// Create a div element
|
|
@@ -31,9 +31,9 @@ describe('isVisible', () => {
|
|
|
31
31
|
const originalMatches = element.matches;
|
|
32
32
|
element.matches = selector => true;
|
|
33
33
|
|
|
34
|
-
// With our mocked matches method,
|
|
35
|
-
// according to the implementation in
|
|
36
|
-
expect(
|
|
34
|
+
// With our mocked matches method, isA11yVisible should return true for inherently non-visible elements
|
|
35
|
+
// according to the implementation in isA11yVisible.js
|
|
36
|
+
expect(isA11yVisible(element)).toBe(true);
|
|
37
37
|
|
|
38
38
|
// Restore the original method
|
|
39
39
|
element.matches = originalMatches;
|
|
@@ -42,7 +42,7 @@ describe('isVisible', () => {
|
|
|
42
42
|
it('should return false for elements with display:none', () => {
|
|
43
43
|
document.body.innerHTML = '<div id="test" style="display:none">Hidden</div>';
|
|
44
44
|
const element = document.getElementById('test');
|
|
45
|
-
expect(
|
|
45
|
+
expect(isA11yVisible(element)).toBe(false);
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
it('should return false for elements with a parent that has display:none', () => {
|
|
@@ -52,7 +52,7 @@ describe('isVisible', () => {
|
|
|
52
52
|
</div>
|
|
53
53
|
`;
|
|
54
54
|
const element = document.getElementById('child');
|
|
55
|
-
expect(
|
|
55
|
+
expect(isA11yVisible(element)).toBe(false);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
it('should return false when aria-hidden=true in strict mode', () => {
|
|
@@ -60,10 +60,10 @@ describe('isVisible', () => {
|
|
|
60
60
|
const element = document.getElementById('test');
|
|
61
61
|
|
|
62
62
|
// In non-strict mode, aria-hidden alone doesn't make it invisible
|
|
63
|
-
expect(
|
|
63
|
+
expect(isA11yVisible(element)).toBe(true);
|
|
64
64
|
|
|
65
65
|
// In strict mode, aria-hidden="true" makes it invisible
|
|
66
|
-
expect(
|
|
66
|
+
expect(isA11yVisible(element, true)).toBe(false);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
it('should return false when a parent has aria-hidden=true in strict mode', () => {
|
|
@@ -75,10 +75,10 @@ describe('isVisible', () => {
|
|
|
75
75
|
const element = document.getElementById('child');
|
|
76
76
|
|
|
77
77
|
// In non-strict mode, aria-hidden alone doesn't make it invisible
|
|
78
|
-
expect(
|
|
78
|
+
expect(isA11yVisible(element)).toBe(true);
|
|
79
79
|
|
|
80
80
|
// In strict mode, parent with aria-hidden="true" makes it invisible
|
|
81
|
-
expect(
|
|
81
|
+
expect(isA11yVisible(element, true)).toBe(false);
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
it('should consider elements referenced by aria-labelledby or aria-describedby', () => {
|
|
@@ -101,25 +101,25 @@ describe('isVisible', () => {
|
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
// The label is hidden but should be considered visible because it's referenced
|
|
104
|
-
expect(
|
|
104
|
+
expect(isA11yVisible(label)).toBe(true);
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
it('should return false for non-Element objects', () => {
|
|
108
|
-
expect(
|
|
109
|
-
expect(
|
|
110
|
-
expect(
|
|
108
|
+
expect(isA11yVisible({})).toBe(false);
|
|
109
|
+
expect(isA11yVisible('string')).toBe(false);
|
|
110
|
+
expect(isA11yVisible(123)).toBe(false);
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
it('should return false for disconnected elements', () => {
|
|
114
114
|
const div = document.createElement('div');
|
|
115
115
|
// Element is not connected to DOM
|
|
116
|
-
expect(
|
|
116
|
+
expect(isA11yVisible(div)).toBe(false);
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
it('should return true for visible elements', () => {
|
|
120
120
|
document.body.innerHTML = '<div id="test">Visible</div>';
|
|
121
121
|
const element = document.getElementById('test');
|
|
122
|
-
expect(
|
|
122
|
+
expect(isA11yVisible(element)).toBe(true);
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
it('should handle elements referenced by aria-describedby', () => {
|
|
@@ -142,7 +142,7 @@ describe('isVisible', () => {
|
|
|
142
142
|
});
|
|
143
143
|
|
|
144
144
|
// Description is hidden but should be considered visible because it's referenced
|
|
145
|
-
expect(
|
|
145
|
+
expect(isA11yVisible(desc)).toBe(true);
|
|
146
146
|
});
|
|
147
147
|
|
|
148
148
|
it('should handle multiple ancestors with display:none', () => {
|
|
@@ -156,7 +156,7 @@ describe('isVisible', () => {
|
|
|
156
156
|
</div>
|
|
157
157
|
`;
|
|
158
158
|
const element = document.getElementById('deeply-hidden');
|
|
159
|
-
expect(
|
|
159
|
+
expect(isA11yVisible(element)).toBe(false);
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
it('should handle aria-hidden="false"', () => {
|
|
@@ -164,15 +164,15 @@ describe('isVisible', () => {
|
|
|
164
164
|
const element = document.getElementById('test');
|
|
165
165
|
|
|
166
166
|
// aria-hidden="false" should not affect visibility in either mode
|
|
167
|
-
expect(
|
|
168
|
-
expect(
|
|
167
|
+
expect(isA11yVisible(element)).toBe(true);
|
|
168
|
+
expect(isA11yVisible(element, true)).toBe(true);
|
|
169
169
|
});
|
|
170
170
|
|
|
171
171
|
it('should handle elements with no aria-hidden attribute in strict mode', () => {
|
|
172
172
|
document.body.innerHTML = '<div id="test">No aria-hidden</div>';
|
|
173
173
|
const element = document.getElementById('test');
|
|
174
174
|
|
|
175
|
-
expect(
|
|
175
|
+
expect(isA11yVisible(element, true)).toBe(true);
|
|
176
176
|
});
|
|
177
177
|
|
|
178
178
|
it('should handle multiple levels of parent aria-hidden in strict mode', () => {
|
|
@@ -185,7 +185,7 @@ describe('isVisible', () => {
|
|
|
185
185
|
`;
|
|
186
186
|
const element = document.getElementById('child');
|
|
187
187
|
|
|
188
|
-
expect(
|
|
188
|
+
expect(isA11yVisible(element, true)).toBe(false);
|
|
189
189
|
});
|
|
190
190
|
|
|
191
191
|
it('should check specific inherently non-visible elements', () => {
|
|
@@ -199,7 +199,7 @@ describe('isVisible', () => {
|
|
|
199
199
|
document.body.innerHTML = html;
|
|
200
200
|
const element = document.getElementById('test');
|
|
201
201
|
// These elements return true (visible to AT) according to implementation
|
|
202
|
-
expect(
|
|
202
|
+
expect(isA11yVisible(element)).toBe(true);
|
|
203
203
|
});
|
|
204
204
|
});
|
|
205
205
|
|
|
@@ -211,13 +211,13 @@ describe('isVisible', () => {
|
|
|
211
211
|
|
|
212
212
|
const div = document.querySelector('div');
|
|
213
213
|
// Element has no id, so won't be found by aria-labelledby query
|
|
214
|
-
expect(
|
|
214
|
+
expect(isA11yVisible(div)).toBe(false);
|
|
215
215
|
});
|
|
216
216
|
|
|
217
217
|
it('should return false for elements with visibility:hidden', () => {
|
|
218
218
|
document.body.innerHTML = '<div id="test" style="visibility:hidden">Hidden</div>';
|
|
219
219
|
const element = document.getElementById('test');
|
|
220
|
-
expect(
|
|
220
|
+
expect(isA11yVisible(element)).toBe(false);
|
|
221
221
|
});
|
|
222
222
|
|
|
223
223
|
it('should return false for elements with a parent that has visibility:hidden', () => {
|
|
@@ -227,13 +227,13 @@ describe('isVisible', () => {
|
|
|
227
227
|
</div>
|
|
228
228
|
`;
|
|
229
229
|
const element = document.getElementById('child');
|
|
230
|
-
expect(
|
|
230
|
+
expect(isA11yVisible(element)).toBe(false);
|
|
231
231
|
});
|
|
232
232
|
|
|
233
233
|
it('should return false for elements with opacity:0', () => {
|
|
234
234
|
document.body.innerHTML = '<div id="test" style="opacity:0">Hidden</div>';
|
|
235
235
|
const element = document.getElementById('test');
|
|
236
|
-
expect(
|
|
236
|
+
expect(isA11yVisible(element)).toBe(false);
|
|
237
237
|
});
|
|
238
238
|
|
|
239
239
|
it('should return false for elements with a parent that has opacity:0', () => {
|
|
@@ -243,7 +243,7 @@ describe('isVisible', () => {
|
|
|
243
243
|
</div>
|
|
244
244
|
`;
|
|
245
245
|
const element = document.getElementById('child');
|
|
246
|
-
expect(
|
|
246
|
+
expect(isA11yVisible(element)).toBe(false);
|
|
247
247
|
});
|
|
248
248
|
|
|
249
249
|
it('should handle aria-hidden with different values in strict mode', () => {
|
|
@@ -251,6 +251,12 @@ describe('isVisible', () => {
|
|
|
251
251
|
const element = document.getElementById('test');
|
|
252
252
|
|
|
253
253
|
// aria-hidden with value other than "true" should not hide in strict mode
|
|
254
|
-
expect(
|
|
254
|
+
expect(isA11yVisible(element, true)).toBe(true);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should return false for elements with the hidden HTML attribute', () => {
|
|
258
|
+
document.body.innerHTML = '<div id="test" hidden>Hidden by attribute</div>';
|
|
259
|
+
const element = document.getElementById('test');
|
|
260
|
+
expect(isA11yVisible(element)).toBe(false);
|
|
255
261
|
});
|
|
256
262
|
});
|