test(frontend): cover the lifecycle, the voice and the repaints

Component and store cases for everything in this series, several of
which exist because the thing they pin is invisible everywhere else:

- `view-lifecycle` and `keyboard-reach` — a document listener count
  that does not grow across a simulated navigate cycle, and a tab
  sequence that reaches the sidebar and plays a row without a mouse.
- `notifications`, `notification-store`, `confirm-dialog`,
  `empty-states` — the four levels, the (level, region, key)
  coalescing window, and loading/failed/empty as three states.
- `card-grid-repaint` — fails if `artists-view`'s or `genres-view`'s
  per-render arrow functions are hoisted to stable fields, which is
  the audit's own recommendation and takes the cards from 1 highlighted
  to 0. It exists for no other reason.
- `lazy-track-details` — reads the five sources and fails on a
  returning static import, the same shape as `TestNoDirectRuntimeEmits`
  and for the same reason: the invariant is about what the code does
  *not* say.
- `now-playing` — a position report that changes nothing must not
  touch the DOM again, and a track change must. The first fails
  against the old unconditional `updated()`.
- `playlist-virtualization`, `list-render-cost`, `selection`, `icons`,
  and the store cases for the library-filter race, the never-settling
  waiter and the per-playlist patch.
This commit is contained in:
2026-08-12 01:20:03 -04:00
parent 2518385330
commit 5830b1ba17
25 changed files with 2498 additions and 37 deletions
@@ -197,14 +197,74 @@ describe('shortcut dispatch: scope', () => {
expect(calls('queue.Queue.Play')).toHaveLength(0);
});
it('lets a checkbox through — it is not a text input', () => {
it('leaves Space to a focused checkbox, which owns it', () => {
// The global bindings are unmodified single keys, so the service has
// to yield to a control that means something by the key itself —
// otherwise the checkbox you tabbed to cannot be ticked (H-6).
const input = mount(document.createElement('input'));
input.type = 'checkbox';
input.focus();
expect(press(' ').defaultPrevented).toBe(false);
expect(calls('queue.Queue.Play')).toHaveLength(0);
});
it('still fires a key the focused control does not own', () => {
bindings({ 'player.playPause': 'Space', 'player.next': 'N' });
const button = mount(document.createElement('button'));
button.focus();
press('n');
expect(calls('queue.Queue.Next')).toHaveLength(1);
});
it('leaves the arrow keys to a focused slider', () => {
bindings({ 'player.volumeUp': 'Up' });
const input = mount(document.createElement('input'));
input.type = 'range';
input.focus();
press('ArrowUp');
expect(calls('player.Player.ChangeVolume')).toHaveLength(0);
});
it('leaves every unmodified key to an open dialog', () => {
const dialog = mount(document.createElement('div'));
const button = document.createElement('button');
dialog.setAttribute('role', 'dialog');
dialog.append(button);
button.focus();
press(' ');
expect(calls('queue.Queue.Play')).toHaveLength(1);
expect(calls('queue.Queue.Play')).toHaveLength(0);
});
it('keeps a modified binding even inside a dialog', () => {
bindings({ 'app.selectAll': 'Ctrl+A' });
const dialog = mount(document.createElement('div'));
const button = document.createElement('button');
dialog.setAttribute('role', 'dialog');
dialog.append(button);
button.focus();
let fired = 0;
const listener = (): void => {
fired += 1;
};
document.addEventListener('shortcut:select-all', listener);
press('a', { ctrlKey: true });
document.removeEventListener('shortcut:select-all', listener);
expect(fired).toBe(1);
});
it('blurs the input on Escape, and only on Escape', () => {
@@ -234,8 +294,11 @@ describe('shortcut dispatch: scope', () => {
it('resolves a panel scope from a data-shortcut-scope ancestor', () => {
const panel = mount(document.createElement('div'));
const button = document.createElement('button');
const button = document.createElement('div');
// Focused on a plain focusable, not a button: a button owns Enter
// itself and is meant to keep it.
button.tabIndex = 0;
panel.dataset['shortcutScope'] = 'tracklist';
panel.append(button);
button.focus();
@@ -256,8 +319,9 @@ describe('shortcut dispatch: scope', () => {
const panel = mount(document.createElement('div'));
const inner = document.createElement('div');
const root = inner.attachShadow({ mode: 'open' });
const button = document.createElement('button');
const button = document.createElement('div');
button.tabIndex = 0;
panel.dataset['shortcutScope'] = 'tracklist';
panel.append(inner);
root.append(button);