* Get accessible name for element (simplified from roleUtils.ts lines 504-528)
(element)
| 248 | * Get accessible name for element (simplified from roleUtils.ts lines 504-528) |
| 249 | */ |
| 250 | function getElementAccessibleName(element) { |
| 251 | if (!element) return ''; |
| 252 | |
| 253 | // Check aria-labelledby |
| 254 | const labelledBy = element.getAttribute('aria-labelledby'); |
| 255 | if (labelledBy) { |
| 256 | const ids = labelledBy.split(' ').filter(id => id); |
| 257 | const texts = ids.map(id => { |
| 258 | const el = document.getElementById(id); |
| 259 | return el ? elementText(el).normalized : ''; |
| 260 | }).filter(t => t); |
| 261 | if (texts.length) return texts.join(' '); |
| 262 | } |
| 263 | |
| 264 | // Check aria-label |
| 265 | const ariaLabel = element.getAttribute('aria-label'); |
| 266 | if (ariaLabel && ariaLabel.trim()) return ariaLabel.trim(); |
| 267 | |
| 268 | // For inputs, check labels |
| 269 | const labels = getElementLabels(element); |
| 270 | if (labels.length) { |
| 271 | return labels.map(l => l.normalized).join(' '); |
| 272 | } |
| 273 | |
| 274 | // For buttons and links, use text content |
| 275 | const role = getAriaRole(element); |
| 276 | if (['button', 'link', 'menuitem', 'option', 'tab'].includes(role)) { |
| 277 | return elementText(element).normalized; |
| 278 | } |
| 279 | |
| 280 | // Check alt for images |
| 281 | if (element.nodeName === 'IMG') { |
| 282 | const alt = element.getAttribute('alt'); |
| 283 | if (alt) return alt; |
| 284 | } |
| 285 | |
| 286 | // Check title as fallback |
| 287 | const title = element.getAttribute('title'); |
| 288 | if (title) return title; |
| 289 | |
| 290 | return ''; |
| 291 | } |
| 292 | |
| 293 | /** |
| 294 | * Count how many elements on the page match a given selector candidate |
no test coverage detected