@afixt/test-utils 1.1.2 → 1.1.4
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 +6 -2
- package/.github/workflows/test.yml +26 -0
- package/BROWSER_TESTING.md +109 -0
- package/CLAUDE.md +22 -0
- package/package.json +6 -8
- package/playwright.config.js +27 -0
- package/src/domUtils.js +1 -1
- package/src/getAccessibleName.js +8 -4
- package/src/getCSSGeneratedContent.js +9 -5
- package/src/getFocusableElements.js +13 -4
- package/src/getImageText.js +4 -1
- package/src/testContrast.js +5 -1
- package/test/__screenshots__/getImageText.test.js/getImageText-should-be-an-async-function-1.png +0 -0
- package/test/__screenshots__/getImageText.test.js/getImageText-should-be-defined-and-exported-from-the-module-1.png +0 -0
- package/test/__screenshots__/getImageText.test.js/getImageText-should-handle-empty-string-input-gracefully-1.png +0 -0
- package/test/__screenshots__/getImageText.test.js/getImageText-should-handle-invalid-image-paths-gracefully-1.png +0 -0
- package/test/__screenshots__/getImageText.test.js/getImageText-should-handle-null-or-undefined-input-gracefully-1.png +0 -0
- package/test/__screenshots__/getImageText.test.js/getImageText-should-log-errors-in-non-test-environments-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-addEventListener-override-should-call-original-addEventListener-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-addEventListener-override-should-track-added-event-listeners-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-addEventListener-override-should-track-listeners-for-different-event-types-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-addEventListener-override-should-track-multiple-listeners-for-the-same-event-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-addEventListener-override-should-track-options-parameter-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-getEventListeners-should-return-all-event-listeners-for-an-element-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-getEventListeners-should-return-empty-object-for-elements-without-listeners-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-getXPath-should-generate-XPath-for-elements-without-id-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-getXPath-should-handle-multiple-siblings-correctly-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-getXPath-should-return-XPath-for-element-with-id-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-listEventListeners-should-list-event-listeners-on-child-elements-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-listEventListeners-should-list-event-listeners-on-root-element-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-listEventListeners-should-list-listeners-from-multiple-elements-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-listEventListeners-should-list-multiple-event-types-on-same-element-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-listEventListeners-should-return-empty-array-when-no-event-listeners-exist-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-listEventListeners-should-use-document-as-default-root-element-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-listEventListeners-should-work-with-custom-root-element-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-removeEventListener-override-should-call-original-removeEventListener-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-removeEventListener-override-should-handle-removing-non-existent-listeners-gracefully-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-removeEventListener-override-should-only-remove-the-specified-listener-1.png +0 -0
- package/test/__screenshots__/listEventListeners.test.js/listEventListeners-removeEventListener-override-should-remove-tracked-event-listeners-1.png +0 -0
- package/test/arrayUtils.test.js +22 -0
- package/test/domUtils.test.js +241 -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 +95 -12
- package/test/getStyleObject.test.js +19 -1
- package/test/hasCSSGeneratedContent.test.js +7 -2
- package/test/hasParent.test.js +116 -0
- package/test/hasValidAriaRole.test.js +64 -2
- 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/isFocusable.test.js +94 -1
- package/test/isValidUrl.test.js +31 -19
- package/test/isVisible.test.js +121 -3
- package/test/playwright/css-pseudo-elements.spec.js +155 -0
- package/test/playwright/fixtures/css-pseudo-elements.html +77 -0
- package/test/setup.js +9 -1
- package/test/stringUtils.test.js +277 -1
- package/test/testContrast.test.js +614 -9
- package/test/testLang.test.js +152 -11
- package/test/testOrder.integration.test.js +369 -0
- package/test/testOrder.test.js +756 -21
- package/todo.md +11 -1
- package/vitest.config.js +8 -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/test/browser-setup.js +0 -68
- package/vitest.config.browser.js +0 -17
package/test/domUtils.test.js
CHANGED
|
@@ -144,4 +144,245 @@ 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
|
+
|
|
264
|
+
it('should return false when element extends beyond left edge', () => {
|
|
265
|
+
const element = document.createElement('div');
|
|
266
|
+
document.body.appendChild(element);
|
|
267
|
+
|
|
268
|
+
element.getBoundingClientRect = vi.fn().mockReturnValue({
|
|
269
|
+
top: 100,
|
|
270
|
+
left: -10, // Beyond left edge
|
|
271
|
+
bottom: 200,
|
|
272
|
+
right: 300
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
expect(domUtils.isFullyVisible(element)).toBe(false);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should return false when element extends beyond bottom edge', () => {
|
|
279
|
+
const element = document.createElement('div');
|
|
280
|
+
document.body.appendChild(element);
|
|
281
|
+
|
|
282
|
+
vi.stubGlobal('innerHeight', 768);
|
|
283
|
+
|
|
284
|
+
element.getBoundingClientRect = vi.fn().mockReturnValue({
|
|
285
|
+
top: 700,
|
|
286
|
+
left: 100,
|
|
287
|
+
bottom: 800, // Beyond bottom edge (768)
|
|
288
|
+
right: 300
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
expect(domUtils.isFullyVisible(element)).toBe(false);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('should return false when element extends beyond right edge', () => {
|
|
295
|
+
const element = document.createElement('div');
|
|
296
|
+
document.body.appendChild(element);
|
|
297
|
+
|
|
298
|
+
vi.stubGlobal('innerWidth', 1024);
|
|
299
|
+
|
|
300
|
+
element.getBoundingClientRect = vi.fn().mockReturnValue({
|
|
301
|
+
top: 100,
|
|
302
|
+
left: 900,
|
|
303
|
+
bottom: 200,
|
|
304
|
+
right: 1100 // Beyond right edge (1024)
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
expect(domUtils.isFullyVisible(element)).toBe(false);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
describe('getXPath edge cases', () => {
|
|
312
|
+
it('should handle elements with multiple siblings of same type', () => {
|
|
313
|
+
document.body.innerHTML = `
|
|
314
|
+
<div>
|
|
315
|
+
<span></span>
|
|
316
|
+
<span></span>
|
|
317
|
+
<span id="target"></span>
|
|
318
|
+
</div>
|
|
319
|
+
`;
|
|
320
|
+
const element = document.getElementById('target');
|
|
321
|
+
const xpath = domUtils.getXPath(element);
|
|
322
|
+
|
|
323
|
+
expect(xpath).toContain('span[3]');
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should handle deeply nested elements', () => {
|
|
327
|
+
document.body.innerHTML = `
|
|
328
|
+
<div>
|
|
329
|
+
<section>
|
|
330
|
+
<article>
|
|
331
|
+
<p id="deep">Deep content</p>
|
|
332
|
+
</article>
|
|
333
|
+
</section>
|
|
334
|
+
</div>
|
|
335
|
+
`;
|
|
336
|
+
const element = document.getElementById('deep');
|
|
337
|
+
const xpath = domUtils.getXPath(element);
|
|
338
|
+
|
|
339
|
+
expect(xpath).toContain('/div');
|
|
340
|
+
expect(xpath).toContain('/section');
|
|
341
|
+
expect(xpath).toContain('/article');
|
|
342
|
+
expect(xpath).toContain('/p');
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
describe('hasFocus edge cases', () => {
|
|
347
|
+
it('should return false when no element has focus', () => {
|
|
348
|
+
const element = document.createElement('div');
|
|
349
|
+
document.body.appendChild(element);
|
|
350
|
+
|
|
351
|
+
// Ensure nothing has focus
|
|
352
|
+
if (document.activeElement) {
|
|
353
|
+
document.activeElement.blur?.();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
expect(domUtils.hasFocus(element)).toBe(false);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
describe('getXPath - non-element nodes', () => {
|
|
361
|
+
it('should handle non-element nodes properly', () => {
|
|
362
|
+
// Test with text node (nodeType 3)
|
|
363
|
+
const textNode = document.createTextNode('test text');
|
|
364
|
+
const xpath = domUtils.getXPath(textNode);
|
|
365
|
+
|
|
366
|
+
expect(xpath).toBe('');
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
describe('attrBegins - array input', () => {
|
|
371
|
+
it('should handle array input correctly', () => {
|
|
372
|
+
document.body.innerHTML = `
|
|
373
|
+
<div id="div1" data-test="value"></div>
|
|
374
|
+
<div id="div2" aria-label="value"></div>
|
|
375
|
+
`;
|
|
376
|
+
|
|
377
|
+
// Test with array instead of NodeList
|
|
378
|
+
const elementsArray = [
|
|
379
|
+
document.getElementById('div1'),
|
|
380
|
+
document.getElementById('div2')
|
|
381
|
+
];
|
|
382
|
+
|
|
383
|
+
const dataElements = domUtils.attrBegins(elementsArray, 'data-');
|
|
384
|
+
expect(dataElements.length).toBe(1);
|
|
385
|
+
expect(dataElements[0].id).toBe('div1');
|
|
386
|
+
});
|
|
387
|
+
});
|
|
147
388
|
});
|
|
@@ -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
|
});
|