Files
bookhoard/web/src/audio-rewind.test.ts
T
John O'Keefe 7b7ce39826 feat(audio-player): apply the resume-rewind setting on open and unpause
The chapters payload now carries resume_rewind_seconds (server-side
per-user setting); the player applies it at two events, each rewinding
once from where playback currently sits — never stacked:

- open-resume: restorePosition starts the rewind early from the saved
  spot (percentage and chapter+offset branches, clamped at the book
  start). Deep links (?loc=) stay exempt — an explicit jump is not a
  resume.
- unpause: a genuine pause→play steps back again (the re-orientation
  gap). Programmatic plays — post-restore autoplay and track-switch
  autoplays — set a suppress flag: their play event is the session
  start the open-rewind already positioned, not an unpause.

Math lives in audio-rewind.ts (pure, unit-tested) after the
audio-scrubber pattern; payload values gate through the 0/5/10
allow-list so stale or foreign servers degrade to exact resume.
2026-11-01 17:21:35 -05:00

42 lines
1.3 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { applyResumeRewind, normalizeResumeRewind } from "./audio-rewind";
describe("applyResumeRewind", () => {
it("steps back by the rewind amount", () => {
expect(applyResumeRewind(754, 5)).toBe(749);
expect(applyResumeRewind(754, 10)).toBe(744);
});
it("clamps at the start of the book", () => {
expect(applyResumeRewind(3, 5)).toBe(0);
expect(applyResumeRewind(0, 10)).toBe(0);
});
it("treats rewind 0 (setting off) as exact resume", () => {
expect(applyResumeRewind(754, 0)).toBe(754);
});
it("tolerates non-finite input", () => {
expect(applyResumeRewind(Number.NaN, 5)).toBe(0);
expect(applyResumeRewind(754, Number.NaN)).toBe(754);
expect(applyResumeRewind(Number.POSITIVE_INFINITY, 5)).toBe(0);
});
});
describe("normalizeResumeRewind", () => {
it("passes the allow-listed amounts", () => {
expect(normalizeResumeRewind(0)).toBe(0);
expect(normalizeResumeRewind(5)).toBe(5);
expect(normalizeResumeRewind(10)).toBe(10);
});
it("maps anything else to off", () => {
expect(normalizeResumeRewind(7)).toBe(0);
expect(normalizeResumeRewind(-5)).toBe(0);
expect(normalizeResumeRewind("12")).toBe(0);
expect(normalizeResumeRewind(undefined)).toBe(0);
expect(normalizeResumeRewind(Number.NaN)).toBe(0);
});
});