/** * Regression tests for the `/player/[id]` surface decision. * * The bug these pin down: a video that was left and re-entered rendered in the * AUDIO player. Exiting a webview-rendered video does not stop the Rust * controller (`onReportStop` deliberately emits no `stopped` state, so the * autoplay handoff survives), so the backend still reports that episode/movie as * the loaded media. Re-entering the route therefore took the "already playing, * just show the UI" shortcut, which returns *before* a stream URL is fetched — * and the render then fell through to `` because it treated * "video without a stream URL" as audio. * * TRACES: UR-005 | DR-100 | UT-092, UT-093 */ import { describe, it, expect } from "vitest"; import { shouldReuseActivePlayback, resolvePlayerSurface } from "./playerSurface"; describe("shouldReuseActivePlayback", () => { it("reuses playback when the same audio track is already loaded", () => { expect( shouldReuseActivePlayback({ requestedId: "track-1", activeMediaId: "track-1", isVideo: false, forceRestart: false, }) ).toBe(true); }); it("does NOT reuse playback for video, even when the backend reports it loaded", () => { // Video needs a full load: the shortcut skips fetching the stream URL, and // cannot render without one. expect( shouldReuseActivePlayback({ requestedId: "episode-1", activeMediaId: "episode-1", isVideo: true, forceRestart: false, }) ).toBe(false); }); it("does not reuse playback for a different item", () => { expect( shouldReuseActivePlayback({ requestedId: "track-2", activeMediaId: "track-1", isVideo: false, forceRestart: false, }) ).toBe(false); }); it("does not reuse playback when nothing is loaded", () => { expect( shouldReuseActivePlayback({ requestedId: "track-1", activeMediaId: null, isVideo: false, forceRestart: false, }) ).toBe(false); }); it("does not reuse playback when an explicit start position is requested", () => { expect( shouldReuseActivePlayback({ requestedId: "track-1", activeMediaId: "track-1", isVideo: false, startPosition: 42, forceRestart: false, }) ).toBe(false); }); it("does not reuse playback when restarting (next-episode advance)", () => { expect( shouldReuseActivePlayback({ requestedId: "episode-2", activeMediaId: "episode-2", isVideo: true, forceRestart: true, }) ).toBe(false); }); }); describe("resolvePlayerSurface", () => { it("renders the video surface for video with a stream URL", () => { expect(resolvePlayerSurface({ isVideo: true, streamUrl: "http://s/master.m3u8" })).toBe( "video" ); }); it("renders the audio surface for audio content", () => { expect(resolvePlayerSurface({ isVideo: false, streamUrl: null })).toBe("audio"); }); it("never renders video content in the audio surface when the stream URL is missing", () => { // A video whose stream URL has not resolved yet is pending, not audio — // otherwise the movie/episode shows up in the audio player. expect(resolvePlayerSurface({ isVideo: true, streamUrl: null })).toBe("pending"); expect(resolvePlayerSurface({ isVideo: true, streamUrl: "" })).toBe("pending"); }); });