import { describe, it, expect } from "vitest"; import { computeHandoffPosition, planHandoffReturn, initialHandoffState, shouldEnterBackgroundAudio, shouldExitBackgroundAudio, shouldResumeOnForeground, type BackgroundAudioState, } from "./backgroundAudioHandoff"; // TRACES: UR-040 | DR-052 | UT-060 describe("backgroundAudioHandoff", () => { describe("computeHandoffPosition", () => { it("sums element time and transcode seekOffset (absolute position)", () => { // Transcoded HLS resets element time to 0 after a reload; seekOffset carries // the cumulative offset. The audio stream must resume at the absolute pos. expect(computeHandoffPosition(12, 180)).toBe(192); }); it("handles a direct stream with no offset", () => { expect(computeHandoffPosition(45, 0)).toBe(45); }); it("never returns a negative position", () => { expect(computeHandoffPosition(-5, 0)).toBe(0); }); }); describe("shouldEnterBackgroundAudio", () => { it("enters when toggle is on and not already handed off", () => { expect(shouldEnterBackgroundAudio(true, initialHandoffState)).toBe(true); }); it("does not enter when the toggle is off", () => { expect(shouldEnterBackgroundAudio(false, initialHandoffState)).toBe(false); }); it("does not double-enter when already active", () => { const active: BackgroundAudioState = { active: true, wasPlaying: true }; expect(shouldEnterBackgroundAudio(true, active)).toBe(false); }); }); describe("shouldExitBackgroundAudio", () => { it("exits when a handoff is active", () => { const active: BackgroundAudioState = { active: true, wasPlaying: false }; expect(shouldExitBackgroundAudio(active)).toBe(true); }); it("does not exit when no handoff happened", () => { expect(shouldExitBackgroundAudio(initialHandoffState)).toBe(false); }); it("exits even if the toggle was turned off while backgrounded", () => { // shouldExit ignores the toggle by design, so turning it off mid-background // still returns cleanly to video on foreground. const active: BackgroundAudioState = { active: true, wasPlaying: true }; expect(shouldExitBackgroundAudio(active)).toBe(true); }); }); describe("shouldResumeOnForeground", () => { it("resumes when it was playing and the native audio still is", () => { expect(shouldResumeOnForeground(true, "playing")).toBe(true); }); it("stays paused when the lockscreen paused the native audio", () => { // The whole point of the lockscreen pause: coming back to the app must not // undo it just because the video was playing when we handed off. expect(shouldResumeOnForeground(true, "paused")).toBe(false); }); it("stays paused when the video was already paused at handoff", () => { expect(shouldResumeOnForeground(false, "playing")).toBe(false); }); it("falls back to the captured state when native state is unknown", () => { // Loading/seeking/idle say nothing about intent — the handoff snapshot is // the best evidence we have, so a playing video still resumes. expect(shouldResumeOnForeground(true, "loading")).toBe(true); expect(shouldResumeOnForeground(true, undefined)).toBe(true); }); }); // Returning from background audio has to restart whatever is actually // rendering. The webview