metadataapi/tagapi/bulkeditapi als Backend-Voraussetzung. MetadataForm passt sich der Felddefinition an und warnt vor Verwerfen ungespeicherter Aenderungen, TagInput schlaegt Tags vor und ist per Pfeiltasten/Enter bedienbar, Massenbearbeitung wendet Tags auf beliebig grosse Auswahlen in einem Aufruf an. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
63 lines
3.0 KiB
TypeScript
63 lines
3.0 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
import { MetadataForm } from "./MetadataForm";
|
|
import { FieldDTO } from "../lib/metadataApi";
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
const fields: FieldDTO[] = [
|
|
{ id: "f1", key: "betrag", label: "Betrag", type: "number", required: true, default_value: null },
|
|
{ id: "f2", key: "faelligkeit", label: "Fälligkeit", type: "date", required: false, default_value: null },
|
|
];
|
|
|
|
// Akzeptanzkriterium 1: Formular passt sich der Felddefinition automatisch an.
|
|
it("rendert ein Eingabefeld je Felddefinition mit korrektem Typ", () => {
|
|
render(<MetadataForm fields={fields} initialValues={{}} onSave={vi.fn()} />);
|
|
const betrag = screen.getByLabelText("Betrag *") as HTMLInputElement;
|
|
const faelligkeit = screen.getByLabelText("Fälligkeit") as HTMLInputElement;
|
|
expect(betrag.type).toBe("number");
|
|
expect(faelligkeit.type).toBe("date");
|
|
});
|
|
|
|
// Pflichtpruefung 2: Formular per Tastatur vollstaendig ausfuellbar — jedes
|
|
// Feld ist ueber sein Label erreichbar und per Tastatur-Eingabe (change,
|
|
// kein Mausklick noetig) befuellbar.
|
|
it("ist ueber Labels erreichbar und ohne Maus befuellbar", () => {
|
|
render(<MetadataForm fields={fields} initialValues={{}} onSave={vi.fn()} />);
|
|
const betrag = screen.getByLabelText("Betrag *");
|
|
fireEvent.change(betrag, { target: { value: "150" } });
|
|
expect((betrag as HTMLInputElement).value).toBe("150");
|
|
});
|
|
|
|
it("speichert per Speichern-Button", async () => {
|
|
const onSave = vi.fn().mockResolvedValue(undefined);
|
|
render(<MetadataForm fields={fields} initialValues={{}} onSave={onSave} />);
|
|
fireEvent.change(screen.getByLabelText("Betrag *"), { target: { value: "99" } });
|
|
fireEvent.click(screen.getByRole("button", { name: "Speichern" }));
|
|
await waitFor(() => expect(onSave).toHaveBeenCalledWith({ f1: "99" }));
|
|
});
|
|
|
|
// Pflichtpruefung 1: ungespeicherte Aenderungen loesen eine Warnung aus.
|
|
it("zeigt eine Bestaetigung, bevor ungespeicherte Aenderungen verworfen werden", () => {
|
|
render(<MetadataForm fields={fields} initialValues={{ f1: "10" }} onSave={vi.fn()} />);
|
|
const betrag = screen.getByLabelText("Betrag *");
|
|
fireEvent.change(betrag, { target: { value: "20" } });
|
|
|
|
fireEvent.click(screen.getByRole("button", { name: "Verwerfen" }));
|
|
expect(screen.getByRole("alertdialog")).toBeTruthy();
|
|
expect((betrag as HTMLInputElement).value).toBe("20"); // noch nicht verworfen
|
|
|
|
fireEvent.click(screen.getByRole("button", { name: "Ja, verwerfen" }));
|
|
expect((betrag as HTMLInputElement).value).toBe("10");
|
|
expect(screen.queryByRole("alertdialog")).toBeNull();
|
|
});
|
|
|
|
it("Verwerfen-Button ist deaktiviert, solange nichts geaendert wurde", () => {
|
|
render(<MetadataForm fields={fields} initialValues={{ f1: "10" }} onSave={vi.fn()} />);
|
|
const discardButton = screen.getByRole("button", { name: "Verwerfen" }) as HTMLButtonElement;
|
|
expect(discardButton.disabled).toBe(true);
|
|
});
|