import { expect, test } from "vitest"; import { screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { http, HttpResponse } from "msw"; import { Routes, Route } from "react-router-dom"; import { server } from "../test/server"; import { renderApp } from "../test/render"; import { AuthoritiesPage } from "./authorities-page"; function tree() { return ( } /> ); } test("lists authorities for the kind and creates one", async () => { let body: unknown; server.use( http.post("/api/admin/authorities", async ({ request }) => { body = await request.json(); return HttpResponse.json({ id: "a-c" }, { status: 201 }); }), ); renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument(); await userEvent.type(screen.getByLabelText(/^label$/i), "Carl von Linné"); await userEvent.click(screen.getByRole("button", { name: /create/i })); await waitFor(() => expect((body as { kind: string })?.kind).toBe("person")); expect((body as { labels: { label: string }[] }).labels[0].label).toBe("Carl von Linné"); }); test("kind tabs link to the other kinds", async () => { renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByRole("link", { name: /place/i })).toHaveAttribute("href", "/authorities/place"); }); test("aria-current marks the active kind link", async () => { renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByRole("link", { name: /^person$/i })).toHaveAttribute("aria-current", "page"); expect(screen.getByRole("link", { name: /^place$/i })).not.toHaveAttribute("aria-current"); }); test("create without EN label shows required alert and does not POST", async () => { let posted = false; server.use( http.post("/api/admin/authorities", () => { posted = true; return HttpResponse.json({ id: "a-x" }, { status: 201 }); }), ); renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument(); await userEvent.click(screen.getByRole("button", { name: /create/i })); expect(screen.getByRole("alert")).toBeInTheDocument(); expect(posted).toBe(false); }); test("authorities endpoint error shows loadError", async () => { server.use( http.get("/api/admin/authorities", () => new HttpResponse(null, { status: 500 })), ); renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByText(/could not load/i)).toBeInTheDocument(); }); test("unknown kind redirects to person list", async () => { renderApp(tree(), { route: "/authorities/banana" }); expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument(); }); test("authorities render sorted by label", async () => { server.use( http.get("/api/admin/authorities", () => HttpResponse.json([ { id: "a-zoe", kind: "person", external_uri: null, labels: [{ lang: "en", label: "Zoe" }] }, { id: "a-adam", kind: "person", external_uri: null, labels: [{ lang: "en", label: "Adam" }] }, ]), ), ); renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByText("Adam")).toBeInTheDocument(); const items = screen.getAllByRole("listitem"); const texts = items.map((item) => item.textContent ?? ""); const adam = texts.findIndex((text) => text.includes("Adam")); const zoe = texts.findIndex((text) => text.includes("Zoe")); expect(adam).toBeLessThan(zoe); }); test("filter narrows the authority list", async () => { server.use( http.get("/api/admin/authorities", () => HttpResponse.json([ { id: "a-ada", kind: "person", external_uri: null, labels: [{ lang: "en", label: "Ada Lovelace" }] }, { id: "a-grace", kind: "person", external_uri: null, labels: [{ lang: "en", label: "Grace Hopper" }] }, ]), ), ); renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument(); expect(screen.getByText("Grace Hopper")).toBeInTheDocument(); await userEvent.type(screen.getByRole("textbox", { name: /filter/i }), "grace"); expect(screen.getByText("Grace Hopper")).toBeInTheDocument(); expect(screen.queryByText("Ada Lovelace")).not.toBeInTheDocument(); }); test("create posts the entered external_uri", async () => { let body: unknown; server.use( http.post("/api/admin/authorities", async ({ request }) => { body = await request.json(); return HttpResponse.json({ id: "a-c" }, { status: 201 }); }), ); renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument(); await userEvent.type(screen.getByLabelText(/^label$/i), "Carl von Linné"); await userEvent.type(screen.getByLabelText(/external uri/i), "https://viaf.org/456"); await userEvent.click(screen.getByRole("button", { name: /create/i })); await waitFor(() => expect((body as { external_uri: string })?.external_uri).toBe("https://viaf.org/456"), ); }); test("read row shows its external_uri as a link", async () => { server.use( http.get("/api/admin/authorities", () => HttpResponse.json([ { id: "a-ada", kind: "person", external_uri: "https://viaf.org/123", labels: [{ lang: "en", label: "Ada Lovelace" }] }, ]), ), ); renderApp(tree(), { route: "/authorities/person" }); expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument(); expect(screen.getByRole("link", { name: /viaf\.org/ })).toBeInTheDocument(); });