Files
Psychotoxical-psysonic/src/store/loudnessPrefetch.test.ts
T
Frank Stellmacher 9fac6eb490 refactor(player): E.42 — migrate playerStore re-exports to direct imports (#607)
Migrates ~74 call sites away from the playerStore re-export shims that
were kept during M0–E.41 to avoid touching 30+ imports per PR. Now
that the bigger refactor work is done, each helper goes back to its
real home:

- `initAudioListeners`, `installQueueUndoHotkey`, `flushPlayQueuePosition`
  → from their own store modules
- `getPlaybackProgressSnapshot`, `subscribePlaybackProgress`,
  `PlaybackProgressSnapshot` → from `playbackProgress`
- `resolveReplayGainDb`, `shuffleArray`, `songToTrack`
  → from `utils/*`
- `_resetQueueUndoStacksForTest`, `consumePendingQueueListScrollTop`,
  `registerQueueListScrollTopReader` → from `queueUndo`
- `PlayerState`, `Track` types → from `playerStoreTypes`

Drops the corresponding 13 re-export stubs from `playerStore.ts` and
the now-unused imports. Also drops dead section banners + per-wrapper
comments above one-line action delegates. Trims one stale "(separate
PR)" note in `transportLightActions.ts` since that follow-up landed
in E.39.

`playerStore.ts`: 180 → 112 LOC (−68). Down from Phase E's starting
3732 LOC.

`bootstrap.test.ts` mock target updated from `../store/playerStore`
to `../store/queueUndoHotkey` to keep the spy reachable after the
import change.
2026-05-12 22:46:13 +02:00

76 lines
2.9 KiB
TypeScript

/**
* `prefetchLoudnessForEnqueuedTracks` warms the loudness cache for the
* current + next-N tracks after a bulk enqueue. Tests pin the engine
* guard, the window collection, and the no-sync-engine flag on each
* refresh call.
*/
import type { Track } from './playerStoreTypes';
import { beforeEach, describe, expect, it, vi } from 'vitest';
const hoisted = vi.hoisted(() => {
const auth = { normalizationEngine: 'loudness' as 'off' | 'replaygain' | 'loudness' };
const player = { currentTrack: null as Track | null };
return {
auth,
player,
refreshMock: vi.fn(async () => undefined),
collectMock: vi.fn((_q: Track[], _i: number, _c: Track | null): string[] => []),
};
});
vi.mock('./authStore', () => ({ useAuthStore: { getState: () => hoisted.auth } }));
vi.mock('./playerStore', () => ({
usePlayerStore: { getState: () => hoisted.player },
}));
vi.mock('./loudnessRefresh', () => ({
refreshLoudnessForTrack: hoisted.refreshMock,
}));
vi.mock('./loudnessBackfillWindow', () => ({
collectLoudnessBackfillWindowTrackIds: hoisted.collectMock,
}));
import { prefetchLoudnessForEnqueuedTracks } from './loudnessPrefetch';
function track(id: string): Track {
return { id, title: id, artist: 'A', album: 'X', albumId: 'X', duration: 100 };
}
beforeEach(() => {
hoisted.auth.normalizationEngine = 'loudness';
hoisted.player.currentTrack = null;
hoisted.refreshMock.mockClear();
hoisted.collectMock.mockReset();
hoisted.collectMock.mockReturnValue([]);
});
describe('prefetchLoudnessForEnqueuedTracks', () => {
it("is a no-op when engine isn't loudness", () => {
hoisted.auth.normalizationEngine = 'off';
hoisted.collectMock.mockReturnValueOnce(['t1']);
prefetchLoudnessForEnqueuedTracks([track('t1')], 0);
expect(hoisted.refreshMock).not.toHaveBeenCalled();
expect(hoisted.collectMock).not.toHaveBeenCalled();
});
it('forwards each window id to refreshLoudnessForTrack with syncPlayingEngine=false', () => {
hoisted.collectMock.mockReturnValueOnce(['t1', 't2', 't3']);
prefetchLoudnessForEnqueuedTracks([track('t1'), track('t2'), track('t3')], 0);
expect(hoisted.refreshMock).toHaveBeenCalledTimes(3);
expect(hoisted.refreshMock).toHaveBeenCalledWith('t1', { syncPlayingEngine: false });
expect(hoisted.refreshMock).toHaveBeenCalledWith('t2', { syncPlayingEngine: false });
expect(hoisted.refreshMock).toHaveBeenCalledWith('t3', { syncPlayingEngine: false });
});
it('passes the queue + currentTrack through to the window collector', () => {
hoisted.player.currentTrack = track('cur');
const q = [track('cur'), track('next')];
prefetchLoudnessForEnqueuedTracks(q, 0);
expect(hoisted.collectMock).toHaveBeenCalledWith(q, 0, hoisted.player.currentTrack);
});
it('handles empty window list gracefully', () => {
hoisted.collectMock.mockReturnValueOnce([]);
prefetchLoudnessForEnqueuedTracks([], 0);
expect(hoisted.refreshMock).not.toHaveBeenCalled();
});
});