import { renderToStaticMarkup } from "react-dom/server"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { ReactNode } from "react"; const mocks = vi.hoisted(() => ({ useSearchItemMatchCandidates: vi.fn(), useApplyItemMatch: vi.fn(), useCatalogItemDetail: vi.fn(), })); vi.mock("@/hooks/queries/items", () => ({ useSearchItemMatchCandidates: (...args: unknown[]) => mocks.useSearchItemMatchCandidates(...args), useApplyItemMatch: (...args: unknown[]) => mocks.useApplyItemMatch(...args), })); vi.mock("@/hooks/queries/catalogRead", () => ({ useCatalogItemDetail: (...args: unknown[]) => mocks.useCatalogItemDetail(...args), })); // Mock Dialog components to render inline (Radix portals don't render in SSR) vi.mock("@/components/ui/dialog", () => ({ Dialog: ({ children, open }: { children: ReactNode; open: boolean }) => open ?
{children}
: null, DialogContent: ({ children }: { children: ReactNode }) =>
{children}
, DialogHeader: ({ children }: { children: ReactNode }) =>
{children}
, DialogTitle: ({ children }: { children: ReactNode }) =>

{children}

, })); import MatchItemDialog from "./MatchItemDialog"; const baseItem = { content_id: "movie-1", title: "Inception", year: 2010, type: "movie" as const, }; describe("MatchItemDialog", () => { beforeEach(() => { const mutate = vi.fn(); mocks.useSearchItemMatchCandidates.mockReturnValue({ mutate, isPending: false, isSuccess: false, data: null, }); mocks.useApplyItemMatch.mockReturnValue({ mutate, isPending: false, }); mocks.useCatalogItemDetail.mockReturnValue({ data: undefined, isLoading: false, }); }); it("renders title, year, IMDb, TMDB, and TVDB inputs", () => { const markup = renderToStaticMarkup( {}} />, ); expect(markup).toContain('id="match-title"'); expect(markup).toContain('id="match-year"'); expect(markup).toContain('id="match-imdb"'); expect(markup).toContain('id="match-tmdb"'); expect(markup).toContain('id="match-tvdb"'); }); it("renders a search button", () => { const markup = renderToStaticMarkup( {}} />, ); expect(markup).toContain("Search"); }); it("renders candidate list when search returns results", () => { mocks.useSearchItemMatchCandidates.mockReturnValue({ mutate: vi.fn(), isPending: false, isSuccess: true, data: { candidates: [ { title: "Inception", year: 2010, content_type: "movie", overview: "A thief who steals secrets...", image_url: "https://image.tmdb.org/poster.jpg", provider_ids: { tmdb: "27205", imdb: "tt1375666" }, sources: ["tmdb", "tvdb"], agreement_hints: ["agreed_by_tmdb_and_tvdb"], }, { title: "Inception (TV)", year: 2012, content_type: "series", overview: "An unrelated series", image_url: "", provider_ids: { tvdb: "999" }, sources: ["tvdb"], agreement_hints: [], }, ], }, }); const markup = renderToStaticMarkup( {}} />, ); expect(markup).toContain("Inception"); expect(markup).toContain("Inception (TV)"); expect(markup).toContain("tmdb"); expect(markup).toContain("2 sources agree"); expect(markup).toContain('data-testid="match-candidate"'); }); it("shows no results message when search returns empty", () => { mocks.useSearchItemMatchCandidates.mockReturnValue({ mutate: vi.fn(), isPending: false, isSuccess: true, data: { candidates: [] }, }); const markup = renderToStaticMarkup( {}} />, ); expect(markup).toContain("No candidates found"); }); it("displays current item summary with title, year, and type badge", () => { const markup = renderToStaticMarkup( {}} />, ); expect(markup).toContain("Inception"); expect(markup).toContain("(2010)"); expect(markup).toContain("movie"); }); it("renders local media rows when file paths are available", () => { const markup = renderToStaticMarkup( {}} />, ); expect(markup).toContain("Local media"); expect(markup).toContain("Inception (2010)/"); expect(markup).toContain("Inception.4K.mkv"); expect(markup).toContain("2160p"); }); });