The catalog surface now speaks milliseconds, the app's neutral time unit.
Ticks no longer reach library/home components.
Rust:
- UserData gains playback_position_ms (dual-carry), populated from ticks
at the offline mapping seam via domain::ticks_to_ms.
Frontend:
- formatDuration(duration.ts) and the two local copies now take ms, not
ticks; all callers pass item.durationMs.
- Progress bars (EpisodeRow, EpisodeFocusView, MediaCard, LibraryListView)
compute playbackPositionMs / durationMs — unit-consistent, no tick math.
- PlaylistDetailView totalDuration sums durationMs.
- duration.test.ts + TrackList.test.ts fixtures updated to ms.
Deferred: player/session/reporting tick math (Queue, SessionCard,
RemoteControls, playbackReporting, playerEvents) — those cross the
storage/Jellyfin command boundary in ticks and need command-signature
changes (phase 3b). Display {item.type} badge -> kind label (phase 4).
Rust 456, frontend 644, check + check:boundary clean.
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
/**
|
|
* Duration formatting utility tests
|
|
*
|
|
* TRACES: UR-005 | DR-028
|
|
*/
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import { formatDuration, formatSecondsDuration } from "./duration";
|
|
|
|
describe("formatDuration", () => {
|
|
it("should format duration from milliseconds (mm:ss format)", () => {
|
|
expect(formatDuration(1000)).toBe("0:01");
|
|
expect(formatDuration(6000)).toBe("0:06");
|
|
expect(formatDuration(60000)).toBe("1:00");
|
|
expect(formatDuration(600000)).toBe("10:00");
|
|
expect(formatDuration(3661000)).toBe("61:01");
|
|
});
|
|
|
|
it("should format duration with hh:mm:ss format", () => {
|
|
// 1 hour = 3600 seconds = 3,600,000 ms
|
|
expect(formatDuration(3600000, "hh:mm:ss")).toBe("1:00:00");
|
|
expect(formatDuration(3610000, "hh:mm:ss")).toBe("1:00:10");
|
|
expect(formatDuration(3661000, "hh:mm:ss")).toBe("1:01:01");
|
|
});
|
|
|
|
it("should return empty string for undefined or 0 duration", () => {
|
|
expect(formatDuration(undefined)).toBe("");
|
|
expect(formatDuration(0)).toBe("");
|
|
});
|
|
|
|
it("should pad seconds with leading zero", () => {
|
|
expect(formatDuration(500)).toBe("0:00");
|
|
expect(formatDuration(5000)).toBe("0:05");
|
|
expect(formatDuration(15000)).toBe("0:15");
|
|
});
|
|
|
|
it("should handle large durations", () => {
|
|
// 2 hours 30 minutes 45 seconds = 9045 seconds = 9,045,000 ms
|
|
expect(formatDuration(9045000, "hh:mm:ss")).toBe("2:30:45");
|
|
});
|
|
});
|
|
|
|
describe("formatSecondsDuration", () => {
|
|
it("should format duration from seconds (mm:ss format)", () => {
|
|
expect(formatSecondsDuration(1)).toBe("0:01");
|
|
expect(formatSecondsDuration(60)).toBe("1:00");
|
|
expect(formatSecondsDuration(61)).toBe("1:01");
|
|
expect(formatSecondsDuration(3661)).toBe("61:01");
|
|
});
|
|
|
|
it("should format duration with hh:mm:ss format", () => {
|
|
expect(formatSecondsDuration(3600, "hh:mm:ss")).toBe("1:00:00");
|
|
expect(formatSecondsDuration(3661, "hh:mm:ss")).toBe("1:01:01");
|
|
expect(formatSecondsDuration(7325, "hh:mm:ss")).toBe("2:02:05");
|
|
});
|
|
|
|
it("should pad minutes and seconds with leading zeros", () => {
|
|
expect(formatSecondsDuration(5, "hh:mm:ss")).toBe("0:00:05");
|
|
expect(formatSecondsDuration(65, "hh:mm:ss")).toBe("0:01:05");
|
|
});
|
|
});
|