138 lines
5.6 KiB
TypeScript
138 lines
5.6 KiB
TypeScript
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 (
|
|
<Routes>
|
|
<Route path="/authorities/:kind" element={<AuthoritiesPage />} />
|
|
</Routes>
|
|
);
|
|
}
|
|
|
|
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();
|
|
});
|