@afixt/test-utils 1.1.4 → 1.1.6
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/package.json
CHANGED
package/src/getAccessibleName.js
CHANGED
|
@@ -319,6 +319,67 @@ function getAccessibleName(element) {
|
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
+
// STEP 11-3: object element
|
|
323
|
+
// Per ACT Rule 8fc3b6, object elements rendering non-text content
|
|
324
|
+
// can receive accessible name from aria-labelledby, aria-label (handled above),
|
|
325
|
+
// title attribute, or fallback content (handled at end via getAccessibleText)
|
|
326
|
+
// STEP 11-3.1: use title attribute
|
|
327
|
+
// STEP 11-3.2: fallback content is handled at the end via getAccessibleText
|
|
328
|
+
if (element.tagName.toLowerCase() === "object") {
|
|
329
|
+
if (element.hasAttribute("title")) {
|
|
330
|
+
const titleValue = element.getAttribute("title");
|
|
331
|
+
if (strlen(titleValue) > 0) {
|
|
332
|
+
return titleValue;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// Fallback content will be handled by getAccessibleText at the end
|
|
336
|
+
// So we don't return false here - let it fall through
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// STEP 11-4: meter element (native or role="meter")
|
|
340
|
+
// Per Axe aria-meter-name rule, meter elements need accessible name from
|
|
341
|
+
// aria-labelledby, aria-label (handled above), title, or associated label
|
|
342
|
+
// Text content inside meter is NOT a valid accessible name (it's fallback content)
|
|
343
|
+
// STEP 11-4.1: use title attribute
|
|
344
|
+
// STEP 11-4.2: for native meter, use associated label
|
|
345
|
+
// STEP 11-4.3: return false (don't use text content)
|
|
346
|
+
if (element.tagName.toLowerCase() === "meter" || element.getAttribute("role") === "meter") {
|
|
347
|
+
if (element.hasAttribute("title")) {
|
|
348
|
+
const titleValue = element.getAttribute("title");
|
|
349
|
+
if (strlen(titleValue) > 0) {
|
|
350
|
+
return titleValue;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// For native meter elements, check for associated label
|
|
355
|
+
if (element.tagName.toLowerCase() === "meter") {
|
|
356
|
+
// Check for label with for attribute
|
|
357
|
+
if (element.id) {
|
|
358
|
+
const label = document.querySelector('label[for="' + element.id + '"]');
|
|
359
|
+
if (label && strlen(getAccessibleText(label)) > 0) {
|
|
360
|
+
return getAccessibleText(label);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Check for wrapping label
|
|
365
|
+
const parentLabel = element.closest("label");
|
|
366
|
+
if (parentLabel) {
|
|
367
|
+
// Get label text excluding the meter's own content
|
|
368
|
+
const clone = parentLabel.cloneNode(true);
|
|
369
|
+
const meterInClone = clone.querySelector("meter");
|
|
370
|
+
if (meterInClone) {
|
|
371
|
+
meterInClone.remove();
|
|
372
|
+
}
|
|
373
|
+
if (strlen(clone.textContent) > 0) {
|
|
374
|
+
return clone.textContent.trim();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Meter text content is not an accessible name, return false
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
|
|
322
383
|
// STEP 12: table element
|
|
323
384
|
// STEP 12.1: caption element
|
|
324
385
|
// STEP 12.2: use the title attribute
|
|
@@ -292,4 +292,76 @@ describe('getAccessibleName', () => {
|
|
|
292
292
|
const select = document.querySelector('select');
|
|
293
293
|
expect(getAccessibleName(select)).toBe(false);
|
|
294
294
|
});
|
|
295
|
+
|
|
296
|
+
it('should handle object element with title attribute', () => {
|
|
297
|
+
document.body.innerHTML = `<object data="chart.pdf" type="application/pdf" title="Q4 Sales Report"></object>`;
|
|
298
|
+
const obj = document.querySelector('object');
|
|
299
|
+
expect(getAccessibleName(obj)).toBe('Q4 Sales Report');
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('should handle object element with fallback content', () => {
|
|
303
|
+
document.body.innerHTML = `<object data="diagram.svg" type="image/svg+xml"><p>Network architecture diagram</p></object>`;
|
|
304
|
+
const obj = document.querySelector('object');
|
|
305
|
+
expect(getAccessibleName(obj)).toBe('Network architecture diagram');
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('should handle object element with aria-label', () => {
|
|
309
|
+
document.body.innerHTML = `<object data="chart.pdf" aria-label="Annual Revenue Chart"></object>`;
|
|
310
|
+
const obj = document.querySelector('object');
|
|
311
|
+
expect(getAccessibleName(obj)).toBe('Annual Revenue Chart');
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('should return false for object element without accessible name', () => {
|
|
315
|
+
document.body.innerHTML = `<object data="chart.pdf" type="application/pdf"></object>`;
|
|
316
|
+
const obj = document.querySelector('object');
|
|
317
|
+
expect(getAccessibleName(obj)).toBe(false);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('should handle object element with empty title', () => {
|
|
321
|
+
document.body.innerHTML = `<object data="chart.pdf" title=""></object>`;
|
|
322
|
+
const obj = document.querySelector('object');
|
|
323
|
+
expect(getAccessibleName(obj)).toBe(false);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should handle ARIA meter with aria-label', () => {
|
|
327
|
+
document.body.innerHTML = `<div role="meter" aria-label="Disk usage" aria-valuenow="75"></div>`;
|
|
328
|
+
const meter = document.querySelector('[role="meter"]');
|
|
329
|
+
expect(getAccessibleName(meter)).toBe('Disk usage');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('should handle ARIA meter with title attribute', () => {
|
|
333
|
+
document.body.innerHTML = `<div role="meter" title="Battery level" aria-valuenow="50"></div>`;
|
|
334
|
+
const meter = document.querySelector('[role="meter"]');
|
|
335
|
+
expect(getAccessibleName(meter)).toBe('Battery level');
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('should handle native meter with associated label', () => {
|
|
339
|
+
document.body.innerHTML = `<label for="cpu">CPU usage</label><meter id="cpu" value="0.6">60%</meter>`;
|
|
340
|
+
const meter = document.querySelector('meter');
|
|
341
|
+
expect(getAccessibleName(meter)).toBe('CPU usage');
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('should handle native meter wrapped in label', () => {
|
|
345
|
+
document.body.innerHTML = `<label>Memory: <meter value="0.8">80%</meter></label>`;
|
|
346
|
+
const meter = document.querySelector('meter');
|
|
347
|
+
expect(getAccessibleName(meter)).toBe('Memory:');
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it('should return false for meter without accessible name', () => {
|
|
351
|
+
document.body.innerHTML = `<div role="meter" aria-valuenow="50">50%</div>`;
|
|
352
|
+
const meter = document.querySelector('[role="meter"]');
|
|
353
|
+
expect(getAccessibleName(meter)).toBe(false);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should return false for native meter without label', () => {
|
|
357
|
+
document.body.innerHTML = `<meter value="0.5">50%</meter>`;
|
|
358
|
+
const meter = document.querySelector('meter');
|
|
359
|
+
expect(getAccessibleName(meter)).toBe(false);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('should handle meter with aria-labelledby', () => {
|
|
363
|
+
document.body.innerHTML = `<span id="signal-label">Signal strength</span><div role="meter" aria-labelledby="signal-label" aria-valuenow="4"></div>`;
|
|
364
|
+
const meter = document.querySelector('[role="meter"]');
|
|
365
|
+
expect(getAccessibleName(meter)).toBe('Signal strength');
|
|
366
|
+
});
|
|
295
367
|
});
|