import { describe, it, expect, vi, beforeEach } from "vitest"; import { screen } from "@testing-library/react"; import { renderWithProviders } from "../test/helpers"; import { BandPage } from "./BandPage"; // ── Mocks ───────────────────────────────────────────────────────────────────── vi.mock("../api/bands", () => ({ getBand: vi.fn().mockResolvedValue({ id: "band-1", name: "Loud Hands", slug: "loud-hands", genre_tags: ["post-rock"], nc_folder_path: null, }), })); vi.mock("../api/client", () => ({ api: { get: vi.fn().mockImplementation((url: string) => { if (url.includes("/sessions")) { return Promise.resolve([ { id: "s1", date: "2026-03-31", label: "Late Night Jam", recording_count: 3 }, ]); } if (url.includes("/songs/search")) { return Promise.resolve([]); } return Promise.resolve([]); }), post: vi.fn(), patch: vi.fn(), delete: vi.fn(), }, isLoggedIn: vi.fn().mockReturnValue(true), })); const renderBandPage = () => renderWithProviders(, { path: "/bands/:bandId", route: "/bands/band-1", }); // ── Tests ───────────────────────────────────────────────────────────────────── describe("BandPage — Library view (TC-01 to TC-09)", () => { beforeEach(() => { vi.clearAllMocks(); }); it("TC-01: does not render a member list", async () => { renderBandPage(); await new Promise((r) => setTimeout(r, 50)); expect(screen.queryByText(/members/i)).toBeNull(); }); it("TC-02: does not render an invite button", async () => { renderBandPage(); await new Promise((r) => setTimeout(r, 50)); expect(screen.queryByText(/\+ invite/i)).toBeNull(); }); it("TC-03: does not render the Nextcloud folder config widget", async () => { renderBandPage(); await new Promise((r) => setTimeout(r, 50)); expect(screen.queryByText(/scan path/i)).toBeNull(); expect(screen.queryByText(/nextcloud scan folder/i)).toBeNull(); }); it("TC-04: renders sessions grouped by date", async () => { renderBandPage(); const sessionEl = await screen.findByText("Late Night Jam"); expect(sessionEl).toBeTruthy(); }); it("TC-05: renders the Scan Nextcloud action button", async () => { renderBandPage(); const btn = await screen.findByText(/scan nextcloud/i); expect(btn).toBeTruthy(); }); it("TC-06: renders the + Upload button", async () => { renderBandPage(); const btn = await screen.findByText(/\+ upload/i); expect(btn).toBeTruthy(); }); it("TC-07: does not render By Date / Search tabs", async () => { renderBandPage(); await new Promise((r) => setTimeout(r, 50)); expect(screen.queryByText(/by date/i)).toBeNull(); expect(screen.queryByText(/^search$/i)).toBeNull(); }); it("TC-08: renders the Library heading", async () => { renderBandPage(); const heading = await screen.findByText("Library"); expect(heading).toBeTruthy(); }); it("TC-09: renders filter pills including All and Guitar", async () => { renderBandPage(); const allPill = await screen.findByText("all"); const guitarPill = await screen.findByText("guitar"); expect(allPill).toBeTruthy(); expect(guitarPill).toBeTruthy(); }); });