fix(a11y): let a clipped value be read, and name a row's own buttons
a11y.24: `text-overflow: ellipsis` in 40+ places, and the four highest-density lists were the ones with no `title` — the queue panel (whose width is user-resizable down to MIN_WIDTH), track-info, every track-list cell, and the playlist sidebar. In track-list the attribute is on the *cell*, not on what is inside it: the value may be a link, a highlighted search match or plain text, and a tooltip is inherited by descendants either way. One binding rather than three, and the same value the accessor already computed. a11y.32: every queue row's remove button was named "Remove from queue", so a list whose entire purpose is which track is where had four identically named controls.
This commit is contained in:
@@ -19,7 +19,7 @@ import { describe, expect, it, beforeEach } from 'vitest';
|
||||
import '@components/queue-panel/queue-panel';
|
||||
import type { QueuePanel } from '@components/queue-panel/queue-panel';
|
||||
import { Events } from '../../src/events';
|
||||
import { emit, calls, flush, lastArgs } from '@test/support/harness';
|
||||
import { emit, calls, flush, lastArgs, resetHarness } from '@test/support/harness';
|
||||
import { fixture, shadow, shadowAll } from '@test/support/render';
|
||||
import type { QueueTrack } from '@store/queue-store';
|
||||
|
||||
@@ -170,3 +170,36 @@ describe('<queue-panel> keyboard reorder', () => {
|
||||
expect(calls().some((c) => c.path.includes('Move'))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('a queue row says which track its controls act on', () => {
|
||||
beforeEach(() => {
|
||||
resetHarness();
|
||||
});
|
||||
|
||||
it('names each remove button after its own track', async () => {
|
||||
const el = await panelWithQueue();
|
||||
|
||||
const labels = shadowAll(el, '.remove-button').map((b) =>
|
||||
b.getAttribute('aria-label'),
|
||||
);
|
||||
|
||||
// `a11y.32`: `title="Remove from queue"` on every row is a name
|
||||
// that never identifies which track — four identical buttons in a
|
||||
// list whose whole purpose is the order.
|
||||
expect(labels.slice(0, 4)).toEqual([
|
||||
'Remove First from queue',
|
||||
'Remove Second from queue',
|
||||
'Remove Third from queue',
|
||||
'Remove Fourth from queue',
|
||||
]);
|
||||
});
|
||||
|
||||
it('gives the title and artist a tooltip, since the panel is resizable', async () => {
|
||||
const el = await panelWithQueue();
|
||||
|
||||
// `a11y.24` calls this one acute: MIN_WIDTH is narrow enough that
|
||||
// both lines clip routinely, and nothing else can show the value.
|
||||
expect(shadow(el, '.track-title')?.getAttribute('title')).toBe('First');
|
||||
expect(shadow(el, '.track-artist')?.getAttribute('title')).toBe('Artist');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user