// PLEX_SUB_URL encode/decode round-trip + guards. Extracted from PlexBrowse for this test (a // code review's deferred gap). Pure — no DOM, no history. import { describe, it, expect } from "vitest"; import { PLEX_SUB_URL as U, type Sub } from "./plexSubUrl"; describe("PLEX_SUB_URL encode", () => { it("mirrors each bookmarkable sub-view to ?v=:", () => { expect(U.encode({ kind: "grid" })).toBe("browse"); // the flat "Browse all" grid expect(U.encode({ kind: "playlists" })).toBe("playlists"); // browse-all-playlists (Piece 2) expect(U.encode({ kind: "collections" })).toBe("collections"); // browse-all-collections (Piece 2) expect(U.encode({ kind: "show", id: "s1" })).toBe("show:s1"); expect(U.encode({ kind: "season", showId: "s1", seasonId: "se2" })).toBe("season:s1:se2"); expect(U.encode({ kind: "info", id: "m9" })).toBe("info:m9"); expect(U.encode({ kind: "person", name: "Jane Doe" })).toBe("person:Jane Doe"); expect(U.encode({ kind: "playlist", id: 12 })).toBe("playlist:12"); expect(U.encode({ kind: "collection", id: "c5" })).toBe("collection:c5"); }); it("does NOT mirror the root Discover landing or the ephemeral player (encode → null)", () => { expect(U.encode({ kind: "discover" })).toBeNull(); expect(U.encode({ kind: "player", id: "m9" })).toBeNull(); }); }); describe("PLEX_SUB_URL round-trip", () => { const cases: Sub[] = [ { kind: "grid" }, { kind: "playlists" }, { kind: "collections" }, { kind: "show", id: "s1" }, { kind: "season", showId: "s1", seasonId: "se2" }, { kind: "info", id: "m9" }, { kind: "person", name: "Jane Doe" }, { kind: "playlist", id: 12 }, { kind: "collection", id: "c5" }, ]; it.each(cases)("encode→decode is identity for %o", (view) => { const raw = U.encode(view); expect(raw).not.toBeNull(); expect(U.decode(raw as string)).toEqual(view); }); it("a person name containing ':' round-trips (tail after the first colon)", () => { const view: Sub = { kind: "person", name: "Dr: Strange: Origins" }; expect(U.decode(U.encode(view) as string)).toEqual(view); }); }); describe("PLEX_SUB_URL decode guards", () => { it("rejects a playlist id that is not a positive integer", () => { expect(U.decode("playlist:")).toBeNull(); // Number("")===0, not >0 expect(U.decode("playlist:0")).toBeNull(); expect(U.decode("playlist:-1")).toBeNull(); expect(U.decode("playlist:1.5")).toBeNull(); expect(U.decode("playlist:abc")).toBeNull(); expect(U.decode("playlist:12")).toEqual({ kind: "playlist", id: 12 }); }); it("requires both ids for a season", () => { expect(U.decode("season:s1")).toBeNull(); expect(U.decode("season:")).toBeNull(); expect(U.decode("season:s1:se2")).toEqual({ kind: "season", showId: "s1", seasonId: "se2" }); }); it("requires a non-empty arg for show / info / person / collection", () => { expect(U.decode("show:")).toBeNull(); expect(U.decode("info:")).toBeNull(); expect(U.decode("person:")).toBeNull(); expect(U.decode("collection:")).toBeNull(); }); it("rejects an unknown kind or garbage", () => { expect(U.decode("grid")).toBeNull(); expect(U.decode("player:m9")).toBeNull(); // player is not URL-restorable expect(U.decode("bogus")).toBeNull(); expect(U.decode("")).toBeNull(); }); }); describe("PLEX_SUB_URL entry", () => { // The Restart click must not replay on a reload / Forward onto the player entry. it("keeps the player without its one-shot fromStart, and every other view whole", () => { const entry = U.entry!; expect(entry({ kind: "player", id: "7", queue: ["7", "8"], fromStart: true })).toEqual({ kind: "player", id: "7", queue: ["7", "8"], fromStart: undefined, }); const info = { kind: "info", id: "7" } as const; expect(entry(info)).toBe(info); }); });