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:
@@ -15,6 +15,7 @@ import type { LitElement } from 'lit';
|
||||
import '@components/track-list/track-list';
|
||||
import '@components/artists-view/artists-view';
|
||||
import '@components/genres-view/genres-view';
|
||||
import '@components/track-info/track-info';
|
||||
import { emit, stub, flush, resetHarness } from '@test/support/harness';
|
||||
import { Events } from '../../src/events';
|
||||
import { fixture, shadow, shadowAll } from '@test/support/render';
|
||||
@@ -191,3 +192,46 @@ describe('a selectable grid is a listbox, not a row of buttons', () => {
|
||||
expect(list!.getAttribute('aria-multiselectable')).toBe('true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('a clipped value is readable somewhere', () => {
|
||||
beforeEach(async () => {
|
||||
resetHarness();
|
||||
searchStore.setTerm('');
|
||||
stub('library.Library.GetAllTracks', TRACKS);
|
||||
stub('library.Library.GetAllAlbums', []);
|
||||
emit(Events.LibraryScanComplete);
|
||||
});
|
||||
|
||||
it('gives every track-list cell the value it may be clipping', async () => {
|
||||
const el = await fixture<LitElement>('track-list');
|
||||
|
||||
sized(el);
|
||||
await settle(el);
|
||||
|
||||
const titles = shadowAll(el, '.track-row [role="gridcell"].cell').map((c) =>
|
||||
c.getAttribute('title'),
|
||||
);
|
||||
|
||||
// `a11y.24`: `text-overflow: ellipsis` in 40+ places, and the
|
||||
// highest-density lists were the ones without a `title`. The
|
||||
// attribute is on the cell rather than on what is inside it,
|
||||
// because the value may be a link or a highlighted match and a
|
||||
// tooltip is inherited by descendants either way.
|
||||
expect(titles.length).toBeGreaterThan(0);
|
||||
expect(titles).toContain('Departure');
|
||||
expect(titles.every((t) => t !== null && t !== '')).toBe(true);
|
||||
});
|
||||
|
||||
it('gives track-info its own title and secondary line', async () => {
|
||||
const el = await fixture<LitElement>('track-info', {
|
||||
trackTitle: 'An Exhaustively Overlong Track Name',
|
||||
artist: 'Aurora Fields',
|
||||
});
|
||||
|
||||
await el.updateComplete;
|
||||
|
||||
expect(shadow(el, '.title')?.getAttribute('title'))
|
||||
.toBe('An Exhaustively Overlong Track Name');
|
||||
expect(shadow(el, '.secondary')?.getAttribute('title')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user