feat(web): use searchable combobox for term/authority fields on the object form (#27)

This commit is contained in:
2026-06-06 10:41:28 +02:00
parent 0188e730e8
commit c84b84b153
3 changed files with 64 additions and 66 deletions
+56 -7
View File
@@ -1,10 +1,13 @@
import { expect, test } from "vitest";
import { screen } from "@testing-library/react";
import { screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { useForm } from "react-hook-form";
import { renderApp } from "../test/render";
import { FieldInput } from "./field-input";
import { fieldDefinitions } from "../test/fixtures";
type FormValues = { fields: Record<string, unknown> };
function Harness({ defKey }: { defKey: string }) {
const def = fieldDefinitions.find((d) => d.key === defKey)!;
const form = useForm({ defaultValues: { fields: {} as Record<string, unknown> } });
@@ -12,6 +15,24 @@ function Harness({ defKey }: { defKey: string }) {
return <FieldInput definition={def} form={form} />;
}
function FormHarness({
defKey,
onSubmit,
}: {
defKey: string;
onSubmit: (values: FormValues) => void;
}) {
const def = fieldDefinitions.find((d) => d.key === defKey)!;
const form = useForm<FormValues>({ defaultValues: { fields: {} as Record<string, unknown> } });
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
<FieldInput definition={def} form={form} />
<button type="submit">Submit</button>
</form>
);
}
test("text field renders a text input labelled in the active locale", async () => {
renderApp(<Harness defKey="inscription" />);
expect(await screen.findByLabelText("Inscription")).toBeInTheDocument();
@@ -27,12 +48,40 @@ test("localized_text renders a single input for the default language", async ()
expect(await screen.findByLabelText(/^title/i)).toBeInTheDocument();
});
test("term field renders a select populated from the vocabulary", async () => {
renderApp(<Harness defKey="material" />);
expect(await screen.findByText("Bronze")).toBeInTheDocument();
test("term field filters and selects from the vocabulary combobox", async () => {
const user = userEvent.setup();
const submitted: FormValues[] = [];
renderApp(<FormHarness defKey="material" onSubmit={(v) => submitted.push(v)} />);
const input = await screen.findByPlaceholderText("— select —");
await user.click(input);
await user.type(input, "bro");
const body = within(document.body);
await user.click(await body.findByText("Bronze"));
await user.click(screen.getByRole("button", { name: "Submit" }));
expect(submitted[0]?.fields.material).toBe("t-bronze");
});
test("authority field renders a select populated by kind", async () => {
renderApp(<Harness defKey="maker" />);
expect(await screen.findByText("Ada Lovelace")).toBeInTheDocument();
test("authority field filters and selects from the authority combobox", async () => {
const user = userEvent.setup();
const submitted: FormValues[] = [];
renderApp(<FormHarness defKey="maker" onSubmit={(v) => submitted.push(v)} />);
const input = await screen.findByPlaceholderText("— select —");
await user.click(input);
await user.type(input, "ada");
const body = within(document.body);
await user.click(await body.findByText("Ada Lovelace"));
await user.click(screen.getByRole("button", { name: "Submit" }));
expect(submitted[0]?.fields.maker).toBe("a-ada");
});