// @vitest-environment jsdom // // The Home surface's slice builds its own query strings, and the Home DOM tests mock this module — // so nothing else in the suite ever looks at the URL that actually goes out. That gap hid a live // parameter once already: the reroll's `start` reached `api.discoverPick` and stopped there. import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { discoverApi } from "./discover"; const fetchMock = vi.fn(); beforeEach(() => { fetchMock.mockReset().mockResolvedValue({ ok: true, status: 200, headers: new Headers({ "content-type": "application/json" }), json: async () => ({}), text: async () => "{}", }); vi.stubGlobal("fetch", fetchMock); }); afterEach(() => vi.unstubAllGlobals()); // Indexed, not `.at(-1)`: the e2e tsconfig's lib target predates it, and the gate typechecks three // projects. const lastUrl = (): string => { const calls = fetchMock.mock.calls; return String(calls[calls.length - 1]?.[0]); }; describe("discoverApi query strings", () => { it("sends the press count as `start` — the tier rotation lives on the wire", async () => { await discoverApi.discoverPick("medium", 42, [], 3); expect(lastUrl()).toContain("start=3"); expect(lastUrl()).toContain("budget=medium"); expect(lastUrl()).toContain("seed=42"); }); it("sends the press count even on the first press, so `start` is never implied", async () => { await discoverApi.discoverPick("any", 7); expect(lastUrl()).toContain("start=0"); }); it("encodes the exclusion list, whose keys carry a colon", async () => { await discoverApi.discoverPick("any", 1, ["youtube:abc", "plex:99"], 2); expect(lastUrl()).toContain(`exclude=${encodeURIComponent("youtube:abc,plex:99")}`); }); it("omits `exclude` entirely when there is nothing to exclude", async () => { await discoverApi.discoverPick("any", 1, [], 0); expect(lastUrl()).not.toContain("exclude="); }); });