Rollen Chunk 7: Benutzerverwaltung und Sicherung strikt Admin-only
Docker Image / test (push) Canceled after 0s
Docker Image / image (push) Canceled after 0s

This commit is contained in:
loki committed 2026-10-11 20:35:55 +02:00
1 parent b523982cd0
commit 03dbf30acf
1 file changed
+81
+81
View File
@@ -0,0 +1,81 @@
import { fireEvent, render, screen, within } from "@testing-library/react";
import { describe, expect, test, vi } from "vitest";
import { createUser, deleteUser, listUsers, setUserRole } from "@/lib/api-client";
import { UsersTab } from "./UsersTab";
vi.mock("@/lib/api-client", async (importOriginal) => ({
...(await importOriginal<typeof import("@/lib/api-client")>()),
listUsers: vi.fn(),
createUser: vi.fn(),
setUserRole: vi.fn(),
deleteUser: vi.fn(),
}));
const users = [
{ id: "u-1", name: "Admina", email: "admina@example.org", role: "admin" as const },
{ id: "u-2", name: "Ben", email: "ben@example.org", role: "benutzer" as const },
];
function open(selfId = "u-1") {
vi.mocked(listUsers).mockResolvedValue({ users });
return render(<UsersTab selfId={selfId} />);
}
describe("UsersTab", () => {
test("listet Benutzer mit Rollen", async () => {
open();
expect(await screen.findByRole("heading", { name: "Benutzer" })).toBeInTheDocument();
const row = screen.getByRole("row", { name: /Ben/ });
expect(within(row).getByText("ben@example.org")).toBeInTheDocument();
expect(within(row).getByDisplayValue("benutzer")).toBeInTheDocument();
});
test("legt Benutzer mit deutschem Fehler bei belegter Mail an", async () => {
const { ApiError } = await import("@/lib/api-client");
vi.mocked(createUser).mockRejectedValue(
new ApiError("Diese E-Mail ist bereits vergeben.", "emailTaken", 409),
);
open();
await screen.findByRole("heading", { name: "Benutzer" });
fireEvent.change(screen.getByLabelText(/Name/), {
target: { value: "Neu" },
});
fireEvent.change(screen.getByLabelText(/E-Mail/), {
target: { value: "ben@example.org" },
});
fireEvent.change(screen.getByLabelText(/Passwort/), {
target: { value: "geheim-geheim!" },
});
fireEvent.click(screen.getByRole("button", { name: "Benutzer anlegen" }));
await vi.waitFor(() => expect(createUser).toHaveBeenCalled());
expect(await screen.findByRole("alert")).toHaveTextContent(
"Diese E-Mail ist bereits vergeben.",
);
});
test("löscht nach zweistufiger Bestätigung", async () => {
vi.mocked(deleteUser).mockResolvedValue({ deleted: true });
open();
await screen.findByRole("heading", { name: "Benutzer" });
const row = screen.getByRole("row", { name: /Ben/ });
fireEvent.click(within(row).getByRole("button", { name: "Ben löschen" }));
fireEvent.click(screen.getByRole("button", { name: "Ja, löschen" }));
await vi.waitFor(() => expect(deleteUser).toHaveBeenCalledWith("u-2"));
});
test("eigene Zeile ohne Löschen, Rollenwechsel ruft API", async () => {
vi.mocked(setUserRole).mockResolvedValue({ user: { id: "u-2", role: "teamleiter" } });
open();
await screen.findByRole("heading", { name: "Benutzer" });
expect(
within(screen.getByRole("row", { name: /Admina/ })).queryByRole("button", {
name: /löschen/,
}),
).toBeNull();
const row = screen.getByRole("row", { name: /Ben/ });
fireEvent.change(within(row).getByLabelText("Rolle"), {
target: { value: "teamleiter" },
});
await vi.waitFor(() => expect(setUserRole).toHaveBeenCalledWith("u-2", "teamleiter"));
});
});