test(player): pin the desktop timer gate, drop a leaked queue
CI / check (push) Skipped
CI / e2e (push) Skipped
CI / check (pull_request) Successful in 2m32s
CI / e2e (pull_request) Successful in 9m14s

Two gaps a review found. The this.phone gate on the interpolation interval is what CLAUDE.md says earns the matchMedia call, and every test passed without it — so it is asserted on the timer count now, since a desktop render is empty either way and cannot tell the two apart. Watched failing with the gate removed.

The e2e spec left LONG_TRACK playing in a workers: 1 suite against one long-lived app, immediately before four other phone-* specs. Nine specs clear the queue in afterEach for that reason and phone-transport.spec.ts records the flake it caused.
This commit is contained in:
2026-08-21 10:45:15 -04:00
parent fba608fdbd
commit deea6ad06d
2 changed files with 46 additions and 2 deletions
+14
View File
@@ -79,6 +79,20 @@ test.describe('the progress line sits on the border between the bars', () => {
await play(app);
});
/*
* Every test here starts a LONG_TRACK and the suite is workers: 1,
* fullyParallel: false against one long-lived app — so without this
* the four phone-* specs that follow alphabetically inherit a playing
* queue. phone-transport.spec.ts records where that lesson came from:
* the fault first showed up as a flake in a spec about something else.
*/
test.afterEach(async ({ app }) => {
await callBinding(app, 'queue.Queue.Clear').catch(() => {
/* already empty */
});
await app.setViewportSize(DESKTOP);
});
test('spans the width, between the mini player and the tab bar', async ({
app,
}) => {
+32 -2
View File
@@ -7,8 +7,8 @@
* backend reported rather than a count of its own, and that it is
* neither announced nor touchable. It cannot see where it sits — that
* is the shell's grid, and it is asserted in
* `e2e/specs/phone-transport.spec.ts` where there is a real bar with a
* real tab bar under it.
* `e2e/specs/phone-progress-line.spec.ts` where there is a real bar
* with a real tab bar under it.
*/
import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest';
@@ -168,6 +168,36 @@ describe('<player-progress-line>', () => {
expect(scale(el)).toBeCloseTo(41 / 90, 3);
});
/*
* The reason this component asks `matchMedia` instead of letting a
* stylesheet hide it: a media query cannot stop a 1 Hz interval
* running for the life of every desktop session. That claim is
* load-bearing in CLAUDE.md, so it is asserted rather than
* described — the timer count, because a desktop render is empty
* either way and so cannot tell the two apart.
*/
it('runs no interpolation timer above the breakpoint', async () => {
pretendPhone(false);
vi.useFakeTimers();
const el = await fixture('player-progress-line');
emit(Events.TrackChanged, { ...TRACK, trackChangeId: 9 });
emit(Events.PlaybackStateChanged, { state: 'playing' });
emit(Events.PlaybackPositionChanged, {
positionSeconds: 3,
trackLength: 90,
trackChangeId: 9,
seq: 9,
playing: true,
});
await vi.advanceTimersByTimeAsync(5000);
await el.updateComplete;
expect(scale(el)).toBeNull();
expect(vi.getTimerCount()).toBe(0);
});
it('ignores a report about a track that is no longer loaded', async () => {
pretendPhone(true);