// TRACES: UR-067, UR-068 | DR-117, DR-119 | UT-105, UT-106 import { describe, it, expect, beforeEach } from "vitest"; import { get } from "svelte/store"; import type { MediaItem } from "$lib/api/types"; import { favoriteOverrides, setFavorite, clearFavorite, clearAllFavorites, resolveIsFavorite, isFavoriteNow, retainFavorites, } from "./favorites"; function item(id: string, isFavorite?: boolean): MediaItem { return { id, name: `Item ${id}`, type: "Movie", kind: "movie", isFolder: false, serverId: "s1", userData: isFavorite === undefined ? undefined : { isFavorite }, } as unknown as MediaItem; } describe("favorites store", () => { beforeEach(() => clearAllFavorites()); describe("resolveIsFavorite (UT-105)", () => { it("falls back to the server's userData when nothing was toggled here", () => { expect(resolveIsFavorite(item("a", true), new Map())).toBe(true); expect(resolveIsFavorite(item("a", false), new Map())).toBe(false); }); it("treats an item with no userData as not favourited", () => { expect(resolveIsFavorite(item("a"), new Map())).toBe(false); }); it("lets a session override win over userData", () => { // The whole point: after tapping the heart on a card, the item object // still carries the server's stale value until the next fetch. expect(resolveIsFavorite(item("a", false), new Map([["a", true]]))).toBe(true); expect(resolveIsFavorite(item("a", true), new Map([["a", false]]))).toBe(false); }); it("is false for a missing item rather than throwing", () => { expect(resolveIsFavorite(null, new Map())).toBe(false); expect(resolveIsFavorite(undefined, new Map())).toBe(false); }); }); describe("overrides", () => { it("publishes a toggle to subscribers", () => { setFavorite("a", true); expect(get(favoriteOverrides).get("a")).toBe(true); expect(isFavoriteNow(item("a", false))).toBe(true); setFavorite("a", false); expect(isFavoriteNow(item("a", true))).toBe(false); }); it("clearing an override hands authority back to the item's userData", () => { setFavorite("a", false); expect(isFavoriteNow(item("a", true))).toBe(false); clearFavorite("a"); expect(isFavoriteNow(item("a", true))).toBe(true); }); it("replaces the map so Svelte sees a new reference", () => { const before = get(favoriteOverrides); setFavorite("a", true); expect(get(favoriteOverrides)).not.toBe(before); }); }); describe("retainFavorites (UT-106)", () => { it("drops an item un-favourited during this session", () => { const items = [item("a", true), item("b", true)]; const kept = retainFavorites(items, new Map([["a", false]])); expect(kept.map((i) => i.id)).toEqual(["b"]); }); it("keeps everything when nothing was toggled", () => { const items = [item("a", true), item("b", true)]; expect(retainFavorites(items, new Map())).toHaveLength(2); }); it("keeps an item favourited during this session even if the server said otherwise", () => { const items = [item("a", false)]; expect(retainFavorites(items, new Map([["a", true]]))).toHaveLength(1); }); it("drops items the server never marked as favourites", () => { // A listing fetched with a stale scope should not keep non-favourites. expect(retainFavorites([item("a")], new Map())).toHaveLength(0); }); }); });