import { describe, it, expect, vi } from "vitest"; import { render, screen, within } from "@testing-library/react"; import { DiveDetailMain } from "./dive-detail-main"; import type { Dive, Sighting } from "@/lib/api/dives"; import { dive } from "@/test/dive-fixtures"; // These renders read the diver's units, so they need an auth context. vi.mock("@/contexts/AuthContext", () => ({ useAuth: () => ({ user: { uuid: "user-1", units: "metric" } }), })); // A sighting as the detail read carries one: the species' summary, and nothing // counted or written unless a test says so. function sighting( overrides: Partial[number]> = {}, ): NonNullable[number] { return { uuid: "species-1", scientific_name: "Amphiprion ocellaris", common_name: "Ocellaris clownfish", rank: "Species", count: null, abundance: null, notes: "", ...overrides, }; } // What the dive page decides about its species; how one species reads as a // card is `species-card.render.test.tsx`'s. describe("DiveDetailMain species card", () => { const CLOWNFISH = sighting(); const MORAY = sighting({ uuid: "species-2", scientific_name: "Gymnothorax javanicus", common_name: "Giant moray", }); it("draws a card for each species spotted, in spotting order", () => { render(); expect(screen.getByText("Species Spotted")).toBeInTheDocument(); expect( screen .getAllByRole("link") .filter((link) => link.getAttribute("href")?.startsWith("/species/")) .map((link) => link.textContent), ).toEqual(["Giant moray", "Ocellaris clownfish"]); }); it("renders no card at all for a dive with nothing spotted", () => { // Absent and empty alike: the API embeds sightings on the detail response // only, so a list row has no key. render(); expect(screen.queryByText("Species Spotted")).not.toBeInTheDocument(); render(); expect(screen.queryByText("Species Spotted")).not.toBeInTheDocument(); }); }); describe("DiveDetailMain species card counts and notes", () => { const MANTA = sighting({ uuid: "species-manta", scientific_name: "Mobula birostris", common_name: "Giant manta ray", count: 3, notes: "Cleaning station\nat 18 m", }); const TURTLE = sighting({ uuid: "species-turtle", scientific_name: "Chelonia mydas", common_name: "Green sea turtle", }); const cardOf = (name: string) => within(screen.getByRole("link", { name }).closest("li")!); it("shows how many were counted, and the note with its line breaks", () => { render(); const manta = cardOf("Giant manta ray"); expect( manta.getByText("Count", { selector: "dt" }).nextElementSibling, ).toHaveTextContent("3"); expect( manta.getByText((_, element) => element?.textContent === MANTA.notes, { selector: "span", }), ).toHaveClass("whitespace-pre-wrap"); }); it("gives an uncounted sighting no count, never 1", () => { render(); expect( cardOf("Green sea turtle").queryByText("Count", { selector: "dt" }), ).not.toBeInTheDocument(); expect(cardOf("Green sea turtle").queryByRole("term")).toBeNull(); }); it("shows a band with its range, as the one figure", () => { const banded = { ...TURTLE, abundance: "many" as const }; render(); const turtle = cardOf("Green sea turtle"); expect(turtle.getAllByRole("term").map((term) => term.textContent)).toEqual( ["Abundance"], ); expect( turtle.getByText("Abundance", { selector: "dt" }).nextElementSibling, ).toHaveTextContent("Many 11–100"); }); it("shows a band this build has no label for de-snaked, with no range", () => { const unknown = { ...TURTLE, abundance: "teeming" as unknown as Sighting["abundance"], }; render(); expect( cardOf("Green sea turtle").getByText("Abundance", { selector: "dt" }) .nextElementSibling, ).toHaveTextContent(/^Teeming$/); }); });