@afixt/test-utils 1.1.1 → 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.
Files changed (89) hide show
  1. package/.claude/settings.local.json +4 -1
  2. package/CLAUDE.md +12 -0
  3. package/package.json +1 -1
  4. package/src/domUtils.js +2 -2
  5. package/src/getAccessibleName.js +8 -4
  6. package/src/getAriaAttributesByElement.js +2 -2
  7. package/src/getFocusableElements.js +14 -5
  8. package/src/stringUtils.js +1 -1
  9. package/test/domUtils.test.js +117 -0
  10. package/test/getAccessibleName.test.js +182 -0
  11. package/test/getAccessibleText.test.js +350 -79
  12. package/test/getCSSGeneratedContent.test.js +175 -1
  13. package/test/getFocusableElements.test.js +106 -35
  14. package/test/getImageText.test.js +61 -12
  15. package/test/hasParent.test.js +116 -0
  16. package/test/index.test.js +165 -0
  17. package/test/interactiveRoles.test.js +60 -0
  18. package/test/isAriaAttributesValid.test.js +36 -0
  19. package/test/isDataTable.test.js +492 -0
  20. package/test/isValidUrl.test.js +31 -19
  21. package/test/stringUtils.test.js +235 -1
  22. package/test/testContrast.test.js +176 -8
  23. package/test/testOrder.integration.test.js +369 -0
  24. package/test/testOrder.test.js +756 -21
  25. package/todo.md +149 -1
  26. package/coverage/base.css +0 -224
  27. package/coverage/block-navigation.js +0 -87
  28. package/coverage/coverage-final.json +0 -51
  29. package/coverage/favicon.png +0 -0
  30. package/coverage/index.html +0 -161
  31. package/coverage/prettify.css +0 -1
  32. package/coverage/prettify.js +0 -2
  33. package/coverage/sort-arrow-sprite.png +0 -0
  34. package/coverage/sorter.js +0 -196
  35. package/coverage/test-utils/docs/scripts/core.js.html +0 -2263
  36. package/coverage/test-utils/docs/scripts/core.min.js.html +0 -151
  37. package/coverage/test-utils/docs/scripts/index.html +0 -176
  38. package/coverage/test-utils/docs/scripts/resize.js.html +0 -355
  39. package/coverage/test-utils/docs/scripts/search.js.html +0 -880
  40. package/coverage/test-utils/docs/scripts/search.min.js.html +0 -100
  41. package/coverage/test-utils/docs/scripts/third-party/fuse.js.html +0 -109
  42. package/coverage/test-utils/docs/scripts/third-party/hljs-line-num-original.js.html +0 -1192
  43. package/coverage/test-utils/docs/scripts/third-party/hljs-line-num.js.html +0 -85
  44. package/coverage/test-utils/docs/scripts/third-party/hljs-original.js.html +0 -15598
  45. package/coverage/test-utils/docs/scripts/third-party/hljs.js.html +0 -85
  46. package/coverage/test-utils/docs/scripts/third-party/index.html +0 -236
  47. package/coverage/test-utils/docs/scripts/third-party/popper.js.html +0 -100
  48. package/coverage/test-utils/docs/scripts/third-party/tippy.js.html +0 -88
  49. package/coverage/test-utils/docs/scripts/third-party/tocbot.js.html +0 -2098
  50. package/coverage/test-utils/docs/scripts/third-party/tocbot.min.js.html +0 -85
  51. package/coverage/test-utils/index.html +0 -131
  52. package/coverage/test-utils/src/arrayUtils.js.html +0 -283
  53. package/coverage/test-utils/src/domUtils.js.html +0 -622
  54. package/coverage/test-utils/src/getAccessibleName.js.html +0 -1444
  55. package/coverage/test-utils/src/getAccessibleText.js.html +0 -271
  56. package/coverage/test-utils/src/getAriaAttributesByElement.js.html +0 -142
  57. package/coverage/test-utils/src/getCSSGeneratedContent.js.html +0 -265
  58. package/coverage/test-utils/src/getComputedRole.js.html +0 -592
  59. package/coverage/test-utils/src/getFocusableElements.js.html +0 -163
  60. package/coverage/test-utils/src/getGeneratedContent.js.html +0 -130
  61. package/coverage/test-utils/src/getImageText.js.html +0 -160
  62. package/coverage/test-utils/src/getStyleObject.js.html +0 -220
  63. package/coverage/test-utils/src/hasAccessibleName.js.html +0 -166
  64. package/coverage/test-utils/src/hasAttribute.js.html +0 -130
  65. package/coverage/test-utils/src/hasCSSGeneratedContent.js.html +0 -145
  66. package/coverage/test-utils/src/hasHiddenParent.js.html +0 -172
  67. package/coverage/test-utils/src/hasParent.js.html +0 -247
  68. package/coverage/test-utils/src/hasValidAriaAttributes.js.html +0 -175
  69. package/coverage/test-utils/src/hasValidAriaRole.js.html +0 -172
  70. package/coverage/test-utils/src/index.html +0 -611
  71. package/coverage/test-utils/src/index.js.html +0 -274
  72. package/coverage/test-utils/src/interactiveRoles.js.html +0 -145
  73. package/coverage/test-utils/src/isAriaAttributesValid.js.html +0 -304
  74. package/coverage/test-utils/src/isComplexTable.js.html +0 -412
  75. package/coverage/test-utils/src/isDataTable.js.html +0 -799
  76. package/coverage/test-utils/src/isFocusable.js.html +0 -187
  77. package/coverage/test-utils/src/isHidden.js.html +0 -136
  78. package/coverage/test-utils/src/isOffScreen.js.html +0 -133
  79. package/coverage/test-utils/src/isValidUrl.js.html +0 -124
  80. package/coverage/test-utils/src/isVisible.js.html +0 -271
  81. package/coverage/test-utils/src/listEventListeners.js.html +0 -370
  82. package/coverage/test-utils/src/queryCache.js.html +0 -1156
  83. package/coverage/test-utils/src/stringUtils.js.html +0 -535
  84. package/coverage/test-utils/src/testContrast.js.html +0 -784
  85. package/coverage/test-utils/src/testLang.js.html +0 -1810
  86. package/coverage/test-utils/src/testOrder.js.html +0 -355
  87. package/coverage/test-utils/vitest.config.browser.js.html +0 -133
  88. package/coverage/test-utils/vitest.config.js.html +0 -157
  89. package/repairs-needed.md +0 -84
@@ -14,7 +14,10 @@
14
14
  "Bash(git stash:*)",
15
15
  "Bash(npm publish:*)",
16
16
  "Bash(git commit:*)",
17
- "Bash(git push:*)"
17
+ "Bash(git push:*)",
18
+ "Bash(node:*)",
19
+ "Bash(npx vitest run:*)",
20
+ "Bash(1)"
18
21
  ]
19
22
  },
20
23
  "enableAllProjectMcpServers": false
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afixt/test-utils",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Various utilities for accessibility testing",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/domUtils.js CHANGED
@@ -3,7 +3,7 @@ const domUtils = {
3
3
  * Checks if the specified element has the given attribute.
4
4
  *
5
5
  * @param {HTMLElement} element - The DOM element to check.
6
- * @param {string} name - The name of the attribute to look for.
6
+ * @param {string} attrName - The name of the attribute to look for.
7
7
  * @returns {boolean} True if the element has the attribute, false otherwise.
8
8
  */
9
9
  hasAttr(element, attrName) {
@@ -58,7 +58,7 @@ const domUtils = {
58
58
  */
59
59
  getAttributesAsString(element) {
60
60
  const attrs = domUtils.getAttributes(element);
61
- return attrs ? JSON.stringify(attrs) : false;
61
+ return Object.keys(attrs).length > 0 ? JSON.stringify(attrs) : false;
62
62
  },
63
63
 
64
64
  /**
@@ -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", input type="password", input type="search", input type="tel", input type="url" and textarea element
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 labels or misnaming one
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 string there is no accessible name
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,7 +4,7 @@
4
4
  * @param {Element} element - The DOM element from which to extract ARIA attributes.
5
5
  * @returns {string[]} An array of ARIA attribute names present on the element.
6
6
  */
7
- const getAriaAttributes = (element) => {
7
+ const getAriaAttributesByElement = (element) => {
8
8
  let result = [];
9
9
  const attrs = element.attributes;
10
10
 
@@ -16,4 +16,4 @@ const getAriaAttributes = (element) => {
16
16
  return result;
17
17
  };
18
18
 
19
- module.exports = getAriaAttributes;
19
+ module.exports = getAriaAttributesByElement;
@@ -1,9 +1,13 @@
1
1
  /**
2
- *
2
+ * Gets all focusable elements within the specified container element.
3
3
  * @param {Element} el - the element to be tested
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
- return (
22
- (tabindex === null || parseInt(tabindex, 10) >= 0) &&
23
- element.offsetParent !== null // Checks visibility
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
 
@@ -72,7 +72,7 @@ const stringUtils = (function () {
72
72
  * @returns {boolean}
73
73
  */
74
74
  function isAlphaNumeric(str) {
75
- const pattern = "/^[a-zA-Z0-9]+$/";
75
+ const pattern = /^[a-zA-Z0-9]+$/;
76
76
  return pattern.test(str);
77
77
  }
78
78
 
@@ -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
  });