From 26d021af4826f4e8d16800ee833eb4a93623f776 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Fri, 30 Oct 2026 15:50:32 +0100 Subject: [PATCH] fix(plugins): test hardcover lookup and all status mappings Co-Authored-By: Claude Sonnet 5.5 --- plugins/hardcover/index.test.ts | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/plugins/hardcover/index.test.ts b/plugins/hardcover/index.test.ts index 46fbcac..643b6e6 100644 --- a/plugins/hardcover/index.test.ts +++ b/plugins/hardcover/index.test.ts @@ -102,3 +102,54 @@ describe("hardcover pullChanges", () => { test("manifest", () => { expect(plugin.manifest).toMatchObject({ id: "hardcover", capabilities: ["pull", "pullChanges", "lookup"], mediaTypes: ["book"], attribution: "Book data from Hardcover." }); }); + +describe("hardcover lookup", () => { + const search = (results: unknown) => { + const calls: unknown[] = []; + const f = (async (_i: unknown, init?: RequestInit) => { + calls.push(JSON.parse(String(init?.body))); + return Response.json({ data: { search: { results } } }); + }) as typeof fetch; + return { ctx: createTestContext({ fetch: f, config: { token: "tok" } }), calls }; + }; + + test("maps hits to WorkHints", async () => { + const { ctx, calls } = search({ + hits: [ + { document: { id: 10, title: "Dune", release_year: 1965, author_names: ["Frank Herbert"], image: { url: "https://img/dune.jpg" } } }, + { document: { id: "11", title: "Bare" } }, + ], + }); + const out = await plugin.lookup!(ctx, { title: "dune" }); + expect(out).toEqual([ + { title: "Dune", mediaType: "book", year: 1965, creators: [{ name: "Frank Herbert" }], externalIds: { hardcover_book: "10" }, coverUrl: "https://img/dune.jpg" }, + { title: "Bare", mediaType: "book", externalIds: { hardcover_book: "11" } }, + ]); + expect((calls[0] as { variables: { q: string } }).variables.q).toBe("dune"); + }); + + test("null results returns []", async () => { + expect(await plugin.lookup!(search(null).ctx, { title: "x" })).toEqual([]); + }); + + test("non-book mediaType returns [] without a request", async () => { + const { ctx, calls } = search({ hits: [] }); + expect(await plugin.lookup!(ctx, { title: "x", mediaType: "movie" })).toEqual([]); + expect(calls).toHaveLength(0); + }); +}); + +describe("status mapping", () => { + const cases: [number | null, string][] = [[1, "planned"], [2, "in_progress"], [3, "completed"], [4, "paused"], [5, "dropped"], [6, "none"], [null, "none"]]; + for (const [id, want] of cases) { + test(`status_id ${id} -> ${want}`, async () => { + const row = { ...short.data.me[0].user_books[1], status_id: id, merged_at: null }; + const ctx = createTestContext({ + fetch: (async () => Response.json({ data: { me: [{ user_books: [row], lists: [] }] } })) as unknown as typeof fetch, + }); + const e = (await collect(plugin.pull!(ctx))).find((r) => r.key === "ub:2"); + if (e?.kind !== "entry") throw new Error(); + expect(e.entry.status).toBe(want as never); + }); + } +});