@afixt/test-utils 1.1.2 → 1.1.3
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 +4 -1
- package/CLAUDE.md +12 -0
- package/package.json +1 -1
- package/src/domUtils.js +1 -1
- package/src/getAccessibleName.js +8 -4
- package/src/getFocusableElements.js +13 -4
- package/test/domUtils.test.js +117 -0
- package/test/getAccessibleName.test.js +182 -0
- package/test/getAccessibleText.test.js +350 -79
- package/test/getCSSGeneratedContent.test.js +175 -1
- package/test/getFocusableElements.test.js +106 -35
- package/test/getImageText.test.js +61 -12
- package/test/hasParent.test.js +116 -0
- package/test/index.test.js +165 -0
- package/test/interactiveRoles.test.js +60 -0
- package/test/isAriaAttributesValid.test.js +36 -0
- package/test/isDataTable.test.js +492 -0
- package/test/isValidUrl.test.js +31 -19
- package/test/stringUtils.test.js +235 -1
- package/test/testContrast.test.js +176 -8
- package/test/testOrder.integration.test.js +369 -0
- package/test/testOrder.test.js +756 -21
- package/todo.md +150 -1
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/coverage-final.json +0 -51
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -161
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -196
- package/coverage/test-utils/docs/scripts/core.js.html +0 -2263
- package/coverage/test-utils/docs/scripts/core.min.js.html +0 -151
- package/coverage/test-utils/docs/scripts/index.html +0 -176
- package/coverage/test-utils/docs/scripts/resize.js.html +0 -355
- package/coverage/test-utils/docs/scripts/search.js.html +0 -880
- package/coverage/test-utils/docs/scripts/search.min.js.html +0 -100
- package/coverage/test-utils/docs/scripts/third-party/fuse.js.html +0 -109
- package/coverage/test-utils/docs/scripts/third-party/hljs-line-num-original.js.html +0 -1192
- package/coverage/test-utils/docs/scripts/third-party/hljs-line-num.js.html +0 -85
- package/coverage/test-utils/docs/scripts/third-party/hljs-original.js.html +0 -15598
- package/coverage/test-utils/docs/scripts/third-party/hljs.js.html +0 -85
- package/coverage/test-utils/docs/scripts/third-party/index.html +0 -236
- package/coverage/test-utils/docs/scripts/third-party/popper.js.html +0 -100
- package/coverage/test-utils/docs/scripts/third-party/tippy.js.html +0 -88
- package/coverage/test-utils/docs/scripts/third-party/tocbot.js.html +0 -2098
- package/coverage/test-utils/docs/scripts/third-party/tocbot.min.js.html +0 -85
- package/coverage/test-utils/index.html +0 -131
- package/coverage/test-utils/src/arrayUtils.js.html +0 -283
- package/coverage/test-utils/src/domUtils.js.html +0 -622
- package/coverage/test-utils/src/getAccessibleName.js.html +0 -1444
- package/coverage/test-utils/src/getAccessibleText.js.html +0 -271
- package/coverage/test-utils/src/getAriaAttributesByElement.js.html +0 -142
- package/coverage/test-utils/src/getCSSGeneratedContent.js.html +0 -265
- package/coverage/test-utils/src/getComputedRole.js.html +0 -592
- package/coverage/test-utils/src/getFocusableElements.js.html +0 -163
- package/coverage/test-utils/src/getGeneratedContent.js.html +0 -130
- package/coverage/test-utils/src/getImageText.js.html +0 -160
- package/coverage/test-utils/src/getStyleObject.js.html +0 -220
- package/coverage/test-utils/src/hasAccessibleName.js.html +0 -166
- package/coverage/test-utils/src/hasAttribute.js.html +0 -130
- package/coverage/test-utils/src/hasCSSGeneratedContent.js.html +0 -145
- package/coverage/test-utils/src/hasHiddenParent.js.html +0 -172
- package/coverage/test-utils/src/hasParent.js.html +0 -247
- package/coverage/test-utils/src/hasValidAriaAttributes.js.html +0 -175
- package/coverage/test-utils/src/hasValidAriaRole.js.html +0 -172
- package/coverage/test-utils/src/index.html +0 -611
- package/coverage/test-utils/src/index.js.html +0 -274
- package/coverage/test-utils/src/interactiveRoles.js.html +0 -145
- package/coverage/test-utils/src/isAriaAttributesValid.js.html +0 -304
- package/coverage/test-utils/src/isComplexTable.js.html +0 -412
- package/coverage/test-utils/src/isDataTable.js.html +0 -799
- package/coverage/test-utils/src/isFocusable.js.html +0 -187
- package/coverage/test-utils/src/isHidden.js.html +0 -136
- package/coverage/test-utils/src/isOffScreen.js.html +0 -133
- package/coverage/test-utils/src/isValidUrl.js.html +0 -124
- package/coverage/test-utils/src/isVisible.js.html +0 -271
- package/coverage/test-utils/src/listEventListeners.js.html +0 -370
- package/coverage/test-utils/src/queryCache.js.html +0 -1156
- package/coverage/test-utils/src/stringUtils.js.html +0 -535
- package/coverage/test-utils/src/testContrast.js.html +0 -784
- package/coverage/test-utils/src/testLang.js.html +0 -1810
- package/coverage/test-utils/src/testOrder.js.html +0 -355
- package/coverage/test-utils/vitest.config.browser.js.html +0 -133
- package/coverage/test-utils/vitest.config.js.html +0 -157
package/CLAUDE.md
CHANGED
|
@@ -22,6 +22,18 @@
|
|
|
22
22
|
- **No jQuery**: All code should be vanilla javascript. No jQuery should be used
|
|
23
23
|
- **No duplication**: In any case where a function already exists elsewhere, that function should be imported and used, rather than being duplicated
|
|
24
24
|
|
|
25
|
+
## Git Workflow
|
|
26
|
+
|
|
27
|
+
- **Branching Strategy**: Git Flow must be used for all development
|
|
28
|
+
- **main/master**: Production-ready code only
|
|
29
|
+
- **develop**: Integration branch for features
|
|
30
|
+
- **feature/***: New features (branch from develop, merge back to develop)
|
|
31
|
+
- **release/***: Release preparation (branch from develop, merge to main and develop)
|
|
32
|
+
- **hotfix/***: Emergency fixes (branch from main, merge to main and develop)
|
|
33
|
+
- **Branch Naming**: Use descriptive names (e.g., `feature/add-aria-validation`, `hotfix/fix-focus-trap`)
|
|
34
|
+
- **Commits**: Write clear, concise commit messages following conventional commits when possible
|
|
35
|
+
- **Pull Requests**: All features must go through PR review before merging to develop
|
|
36
|
+
|
|
25
37
|
## Testing
|
|
26
38
|
|
|
27
39
|
- Test files should be placed in the `/test` directory with a `.test.js` extension
|
package/package.json
CHANGED
package/src/domUtils.js
CHANGED
package/src/getAccessibleName.js
CHANGED
|
@@ -78,7 +78,9 @@ function getAccessibleName(element) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// STEP 4: is the tag one of:
|
|
81
|
-
// input without any type, input type="text", input type="email",
|
|
81
|
+
// input without any type, input type="text", input type="email",
|
|
82
|
+
// input type="password", input type="search", input type="tel",
|
|
83
|
+
// input type="url" and textarea element
|
|
82
84
|
// STEP 4.1 use the associated label
|
|
83
85
|
// STEP 4.3 Otherwise use the title attribute
|
|
84
86
|
// STEP 4.4 - return false. If none of the above yield a usable text string there is no accessible name
|
|
@@ -91,7 +93,8 @@ function getAccessibleName(element) {
|
|
|
91
93
|
if (element.id && document.querySelector('label[for="' + element.id + '"]')) {
|
|
92
94
|
id = element.id;
|
|
93
95
|
// Use only the *first* label that matches this ID.
|
|
94
|
-
// Sometimes JS libraries screw this up by hiding one of the
|
|
96
|
+
// Sometimes JS libraries screw this up by hiding one of the
|
|
97
|
+
// labels or misnaming one
|
|
95
98
|
label = document.querySelector('label[for="' + id + '"]');
|
|
96
99
|
if (label) {
|
|
97
100
|
return getAccessibleText(label);
|
|
@@ -195,7 +198,8 @@ function getAccessibleName(element) {
|
|
|
195
198
|
// STEP 8: Other form elements
|
|
196
199
|
// STEP 8.1: use label element
|
|
197
200
|
// STEP 8.2: use title attribute
|
|
198
|
-
// STEP 8.3: return false. If none of the above yield a usable text
|
|
201
|
+
// STEP 8.3: return false. If none of the above yield a usable text
|
|
202
|
+
// string there is no accessible name
|
|
199
203
|
if (
|
|
200
204
|
matchesSelector(element,
|
|
201
205
|
'select, input[type="checkbox"], input[type="color"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="file"], input[type="month"], input[type="number"], input[type="radio"], input[type="range"], input[type="time"], input[type="week"]'
|
|
@@ -449,4 +453,4 @@ function strlen(str) {
|
|
|
449
453
|
}
|
|
450
454
|
|
|
451
455
|
// Export the function for CommonJS module usage
|
|
452
|
-
module.exports = getAccessibleName;
|
|
456
|
+
module.exports = getAccessibleName;
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* @returns {Array} - Array of focusable elements
|
|
5
5
|
*/
|
|
6
6
|
function getFocusableElements(el) {
|
|
7
|
+
if (!el) {
|
|
8
|
+
throw new Error('Container element is required');
|
|
9
|
+
}
|
|
10
|
+
|
|
7
11
|
const focusableSelectors = [
|
|
8
12
|
"a[href]",
|
|
9
13
|
"area",
|
|
@@ -18,10 +22,15 @@ function getFocusableElements(el) {
|
|
|
18
22
|
el.querySelectorAll(focusableSelectors.join(", "))
|
|
19
23
|
).filter((element) => {
|
|
20
24
|
const tabindex = element.getAttribute("tabindex");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const hasValidTabindex = tabindex === null || parseInt(tabindex, 10) >= 0;
|
|
26
|
+
|
|
27
|
+
// Check visibility - handle JSDOM environment where offsetParent might not work correctly
|
|
28
|
+
const isVisible = element.offsetParent !== null ||
|
|
29
|
+
(typeof window !== 'undefined' &&
|
|
30
|
+
window.navigator &&
|
|
31
|
+
window.navigator.userAgent.includes('jsdom'));
|
|
32
|
+
|
|
33
|
+
return hasValidTabindex && isVisible;
|
|
25
34
|
});
|
|
26
35
|
}
|
|
27
36
|
|
package/test/domUtils.test.js
CHANGED
|
@@ -144,4 +144,121 @@ describe('domUtils', () => {
|
|
|
144
144
|
expect(domUtils.hasFocus(element2)).toBe(false);
|
|
145
145
|
});
|
|
146
146
|
});
|
|
147
|
+
|
|
148
|
+
describe('getAttributesAsString', () => {
|
|
149
|
+
it('should return attributes as JSON string when element has attributes', () => {
|
|
150
|
+
document.body.innerHTML = `<div id="test" class="container" data-value="123"></div>`;
|
|
151
|
+
const element = document.getElementById('test');
|
|
152
|
+
|
|
153
|
+
const attrsString = domUtils.getAttributesAsString(element);
|
|
154
|
+
const parsed = JSON.parse(attrsString);
|
|
155
|
+
|
|
156
|
+
expect(parsed.id).toBe('test');
|
|
157
|
+
expect(parsed.class).toBe('container');
|
|
158
|
+
expect(parsed['data-value']).toBe('123');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should return false for elements with no attributes', () => {
|
|
162
|
+
const element = document.createElement('div');
|
|
163
|
+
expect(domUtils.getAttributesAsString(element)).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('getDocumentSize', () => {
|
|
168
|
+
it('should return the size of the document HTML', () => {
|
|
169
|
+
const size = domUtils.getDocumentSize();
|
|
170
|
+
expect(typeof size).toBe('number');
|
|
171
|
+
expect(size).toBeGreaterThan(0);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('getElementsWithDuplicateIds', () => {
|
|
176
|
+
it('should find elements with duplicate IDs', () => {
|
|
177
|
+
document.body.innerHTML = `
|
|
178
|
+
<div id="duplicate">First</div>
|
|
179
|
+
<span id="duplicate">Second</span>
|
|
180
|
+
<p id="unique">Unique</p>
|
|
181
|
+
`;
|
|
182
|
+
|
|
183
|
+
const duplicates = domUtils.getElementsWithDuplicateIds();
|
|
184
|
+
expect(duplicates.length).toBeGreaterThan(0);
|
|
185
|
+
expect(duplicates[0].id).toBe('duplicate');
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should return empty array when no duplicate IDs exist', () => {
|
|
189
|
+
document.body.innerHTML = `
|
|
190
|
+
<div id="first">First</div>
|
|
191
|
+
<span id="second">Second</span>
|
|
192
|
+
<p id="third">Third</p>
|
|
193
|
+
`;
|
|
194
|
+
|
|
195
|
+
const duplicates = domUtils.getElementsWithDuplicateIds();
|
|
196
|
+
expect(duplicates.length).toBe(0);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('getOuterHTML', () => {
|
|
201
|
+
it('should return the outer HTML of an element', () => {
|
|
202
|
+
document.body.innerHTML = `<div id="test" class="container">Content</div>`;
|
|
203
|
+
const element = document.getElementById('test');
|
|
204
|
+
|
|
205
|
+
const outerHTML = domUtils.getOuterHTML(element);
|
|
206
|
+
expect(outerHTML).toBe('<div id="test" class="container">Content</div>');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe('isFullyVisible', () => {
|
|
211
|
+
it('should check if element is fully visible in viewport', () => {
|
|
212
|
+
document.body.innerHTML = `<div id="test" style="width: 100px; height: 100px;">Test</div>`;
|
|
213
|
+
const element = document.getElementById('test');
|
|
214
|
+
|
|
215
|
+
// Mock getBoundingClientRect to simulate visible element
|
|
216
|
+
element.getBoundingClientRect = () => ({
|
|
217
|
+
top: 10,
|
|
218
|
+
left: 10,
|
|
219
|
+
bottom: 110,
|
|
220
|
+
right: 110
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Mock window dimensions
|
|
224
|
+
Object.defineProperty(window, 'innerHeight', {
|
|
225
|
+
writable: true,
|
|
226
|
+
configurable: true,
|
|
227
|
+
value: 800
|
|
228
|
+
});
|
|
229
|
+
Object.defineProperty(window, 'innerWidth', {
|
|
230
|
+
writable: true,
|
|
231
|
+
configurable: true,
|
|
232
|
+
value: 1200
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
expect(domUtils.isFullyVisible(element)).toBe(true);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('should return false if element is not fully visible', () => {
|
|
239
|
+
document.body.innerHTML = `<div id="test" style="width: 100px; height: 100px;">Test</div>`;
|
|
240
|
+
const element = document.getElementById('test');
|
|
241
|
+
|
|
242
|
+
// Mock getBoundingClientRect to simulate partially visible element
|
|
243
|
+
element.getBoundingClientRect = () => ({
|
|
244
|
+
top: -50,
|
|
245
|
+
left: 10,
|
|
246
|
+
bottom: 50,
|
|
247
|
+
right: 110
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
Object.defineProperty(window, 'innerHeight', {
|
|
251
|
+
writable: true,
|
|
252
|
+
configurable: true,
|
|
253
|
+
value: 800
|
|
254
|
+
});
|
|
255
|
+
Object.defineProperty(window, 'innerWidth', {
|
|
256
|
+
writable: true,
|
|
257
|
+
configurable: true,
|
|
258
|
+
value: 1200
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
expect(domUtils.isFullyVisible(element)).toBe(false);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
147
264
|
});
|
|
@@ -110,4 +110,186 @@ describe('getAccessibleName', () => {
|
|
|
110
110
|
const dialog = document.querySelector('[role="dialog"]');
|
|
111
111
|
expect(getAccessibleName(dialog)).toBe('Confirmation Are you sure you want to continue?');
|
|
112
112
|
});
|
|
113
|
+
|
|
114
|
+
it('should handle text-level elements with content', () => {
|
|
115
|
+
// Test various text-level elements
|
|
116
|
+
const textLevelElements = ['em', 'strong', 'small', 'cite', 'code', 'var', 'kbd', 'sub', 'sup', 'i', 'b', 'u', 'mark'];
|
|
117
|
+
|
|
118
|
+
textLevelElements.forEach(tagName => {
|
|
119
|
+
document.body.innerHTML = `<${tagName}>Important text</${tagName}>`;
|
|
120
|
+
const element = document.querySelector(tagName);
|
|
121
|
+
expect(getAccessibleName(element)).toBe('Important text');
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should handle text-level elements with title fallback', () => {
|
|
126
|
+
document.body.innerHTML = `<em title="Emphasis title"></em>`;
|
|
127
|
+
const em = document.querySelector('em');
|
|
128
|
+
expect(getAccessibleName(em)).toBe('Emphasis title');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should return false for text-level elements without content or title', () => {
|
|
132
|
+
document.body.innerHTML = `<strong></strong>`;
|
|
133
|
+
const strong = document.querySelector('strong');
|
|
134
|
+
expect(getAccessibleName(strong)).toBe(false);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should handle elements with role-based text content', () => {
|
|
138
|
+
const textRoles = ['button', 'checkbox', 'link', 'menuitem', 'option', 'tab'];
|
|
139
|
+
|
|
140
|
+
textRoles.forEach(role => {
|
|
141
|
+
document.body.innerHTML = `<div role="${role}">Role content</div>`;
|
|
142
|
+
const element = document.querySelector('div');
|
|
143
|
+
expect(getAccessibleName(element)).toBe('Role content');
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should return false for elements with roles but no text content', () => {
|
|
148
|
+
document.body.innerHTML = `<div role="button"></div>`;
|
|
149
|
+
const element = document.querySelector('div');
|
|
150
|
+
expect(getAccessibleName(element)).toBe(false);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should handle input type="button" with value', () => {
|
|
154
|
+
document.body.innerHTML = `<input type="button" value="Cancel">`;
|
|
155
|
+
const button = document.querySelector('input');
|
|
156
|
+
expect(getAccessibleName(button)).toBe('Cancel');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should handle input type="button" with title fallback', () => {
|
|
160
|
+
document.body.innerHTML = `<input type="button" title="Close Dialog">`;
|
|
161
|
+
const button = document.querySelector('input');
|
|
162
|
+
expect(getAccessibleName(button)).toBe('Close Dialog');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should return false for input type="button" without value or title', () => {
|
|
166
|
+
document.body.innerHTML = `<input type="button">`;
|
|
167
|
+
const button = document.querySelector('input');
|
|
168
|
+
expect(getAccessibleName(button)).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should handle input type="reset" with title', () => {
|
|
172
|
+
document.body.innerHTML = `<input type="reset" title="Clear Form">`;
|
|
173
|
+
const reset = document.querySelector('input');
|
|
174
|
+
expect(getAccessibleName(reset)).toBe('Clear Form');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should return default "Reset" for input type="reset" without title', () => {
|
|
178
|
+
document.body.innerHTML = `<input type="reset">`;
|
|
179
|
+
const reset = document.querySelector('input');
|
|
180
|
+
expect(getAccessibleName(reset)).toBe('Reset');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should handle input type="image" with alt attribute', () => {
|
|
184
|
+
document.body.innerHTML = `<input type="image" alt="Submit Button">`;
|
|
185
|
+
const image = document.querySelector('input');
|
|
186
|
+
expect(getAccessibleName(image)).toBe('Submit Button');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should handle input type="image" with value fallback', () => {
|
|
190
|
+
document.body.innerHTML = `<input type="image" value="Send Message">`;
|
|
191
|
+
const image = document.querySelector('input');
|
|
192
|
+
expect(getAccessibleName(image)).toBe('Send Message');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should handle input type="image" with title fallback', () => {
|
|
196
|
+
document.body.innerHTML = `<input type="image" title="Upload File">`;
|
|
197
|
+
const image = document.querySelector('input');
|
|
198
|
+
expect(getAccessibleName(image)).toBe('Upload File');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should return false for input type="image" without alt, value, or title', () => {
|
|
202
|
+
document.body.innerHTML = `<input type="image">`;
|
|
203
|
+
const image = document.querySelector('input');
|
|
204
|
+
expect(getAccessibleName(image)).toBe(false);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should handle button element with title fallback', () => {
|
|
208
|
+
document.body.innerHTML = `<button title="Submit Form"></button>`;
|
|
209
|
+
const button = document.querySelector('button');
|
|
210
|
+
expect(getAccessibleName(button)).toBe('Submit Form');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should return false for button element without content or title', () => {
|
|
214
|
+
document.body.innerHTML = `<button></button>`;
|
|
215
|
+
const button = document.querySelector('button');
|
|
216
|
+
expect(getAccessibleName(button)).toBe(false);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should handle empty aria-label gracefully', () => {
|
|
220
|
+
document.body.innerHTML = `<button aria-label="">Click Me</button>`;
|
|
221
|
+
const button = document.querySelector('button');
|
|
222
|
+
expect(getAccessibleName(button)).toBe('Click Me');
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should return false for aria-labelledby with non-existent reference', () => {
|
|
226
|
+
document.body.innerHTML = `<button aria-labelledby="non-existent">Click Me</button>`;
|
|
227
|
+
const button = document.querySelector('button');
|
|
228
|
+
expect(getAccessibleName(button)).toBe(false);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should handle disconnected elements', () => {
|
|
232
|
+
const div = document.createElement('div');
|
|
233
|
+
div.textContent = 'Not connected';
|
|
234
|
+
expect(getAccessibleName(div)).toBe(false);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should handle invisible elements', () => {
|
|
238
|
+
document.body.innerHTML = `<div style="display: none;">Hidden content</div>`;
|
|
239
|
+
const div = document.querySelector('div');
|
|
240
|
+
expect(getAccessibleName(div)).toBe(false);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('should handle elements with aria-hidden="true"', () => {
|
|
244
|
+
document.body.innerHTML = `<div aria-hidden="true">Hidden from AT</div>`;
|
|
245
|
+
const div = document.querySelector('div');
|
|
246
|
+
expect(getAccessibleName(div)).toBe(false);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should handle unlabellable elements', () => {
|
|
250
|
+
document.body.innerHTML = `<hr>`;
|
|
251
|
+
const hr = document.querySelector('hr');
|
|
252
|
+
expect(getAccessibleName(hr)).toBe(false);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should use fallback accessible text for general elements', () => {
|
|
256
|
+
document.body.innerHTML = `<span>Fallback text content</span>`;
|
|
257
|
+
const span = document.querySelector('span');
|
|
258
|
+
expect(getAccessibleName(span)).toBe('Fallback text content');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should return false when no accessible name can be determined', () => {
|
|
262
|
+
document.body.innerHTML = `<div></div>`;
|
|
263
|
+
const div = document.querySelector('div');
|
|
264
|
+
expect(getAccessibleName(div)).toBe(false);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should handle input element with empty title', () => {
|
|
268
|
+
document.body.innerHTML = `<input type="text" title="">`;
|
|
269
|
+
const input = document.querySelector('input');
|
|
270
|
+
expect(getAccessibleName(input)).toBe(false);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should handle form elements with label', () => {
|
|
274
|
+
document.body.innerHTML = `
|
|
275
|
+
<label for="select-id">Choose option</label>
|
|
276
|
+
<select id="select-id">
|
|
277
|
+
<option>Option 1</option>
|
|
278
|
+
</select>
|
|
279
|
+
`;
|
|
280
|
+
const select = document.querySelector('select');
|
|
281
|
+
expect(getAccessibleName(select)).toBe('Choose option');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should handle form elements without label but with title', () => {
|
|
285
|
+
document.body.innerHTML = `<select title="Dropdown menu"><option>Option 1</option></select>`;
|
|
286
|
+
const select = document.querySelector('select');
|
|
287
|
+
expect(getAccessibleName(select)).toBe('Dropdown menu');
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('should return false for form elements without label or title', () => {
|
|
291
|
+
document.body.innerHTML = `<select><option>Option 1</option></select>`;
|
|
292
|
+
const select = document.querySelector('select');
|
|
293
|
+
expect(getAccessibleName(select)).toBe(false);
|
|
294
|
+
});
|
|
113
295
|
});
|