import { expect, test } from "vitest"; import { screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { http, HttpResponse } from "msw"; import { Route, Routes } from "react-router-dom"; import { server } from "../test/server"; import { renderApp } from "../test/render"; import { FieldsPage } from "./fields-page"; function tree() { return ( } /> ); } async function choose(triggerName: RegExp, optionName: RegExp) { await userEvent.click(screen.getByRole("combobox", { name: triggerName })); await userEvent.click(await within(document.body).findByRole("option", { name: optionName })); } test("lists field definitions grouped, with an Other heading for ungrouped", async () => { renderApp(tree(), { route: "/fields" }); expect(await screen.findByText("Inscription")).toBeInTheDocument(); expect(screen.getByText(/^Description$/i)).toBeInTheDocument(); expect(screen.getByText(/^Other$/i)).toBeInTheDocument(); }); test("creates a text field — posts the body and clears the key input", async () => { let body: { key: string; data_type: string } | undefined; server.use( http.post("/api/admin/field-definitions", async ({ request }) => { body = (await request.json()) as { key: string; data_type: string }; return HttpResponse.json({ key: "notes" }, { status: 201 }); }), ); renderApp(tree(), { route: "/fields" }); await userEvent.type(screen.getByLabelText(/^key$/i), "notes"); await userEvent.type(screen.getByLabelText(/^label$/i), "Notes"); await userEvent.click(screen.getByRole("button", { name: /create field/i })); await waitFor(() => expect(body?.key).toBe("notes")); expect(body?.data_type).toBe("text"); await waitFor(() => expect(screen.getByLabelText(/^key$/i)).toHaveValue("")); }); test("selecting Authority reveals the kind picker and posts the chosen kind", async () => { let body: { authority_kind: string | null } | undefined; server.use( http.post("/api/admin/field-definitions", async ({ request }) => { body = (await request.json()) as { authority_kind: string | null }; return HttpResponse.json({ key: "maker" }, { status: 201 }); }), ); renderApp(tree(), { route: "/fields" }); await userEvent.type(screen.getByLabelText(/^key$/i), "maker"); await userEvent.type(screen.getByLabelText(/^label$/i), "Maker"); await choose(/^type$/i, /^authority$/i); await screen.findByLabelText(/authority kind/i); await choose(/authority kind/i, /^person$/i); await userEvent.click(screen.getByRole("button", { name: /create field/i })); await waitFor(() => expect(body?.authority_kind).toBe("person")); }); test("selecting Term reveals the vocabulary picker and blocks submit until chosen", async () => { let posted = false; server.use( http.post("/api/admin/field-definitions", () => { posted = true; return HttpResponse.json({ key: "x" }, { status: 201 }); }), ); renderApp(tree(), { route: "/fields" }); await userEvent.type(screen.getByLabelText(/^key$/i), "material"); await userEvent.type(screen.getByLabelText(/^label$/i), "Material"); await choose(/^type$/i, /^term$/i); const vocab = await screen.findByLabelText(/^vocabulary$/i); expect(vocab).toBeInTheDocument(); await userEvent.click(screen.getByRole("button", { name: /create field/i })); expect(await screen.findByRole("alert")).toBeInTheDocument(); expect(posted).toBe(false); await choose(/^vocabulary$/i, /^material$/i); await userEvent.click(screen.getByRole("button", { name: /create field/i })); await waitFor(() => expect(posted).toBe(true)); });