62 lines
2.8 KiB
TypeScript
62 lines
2.8 KiB
TypeScript
import { fireEvent, screen, waitFor, within } from "@testing-library/react";
|
|||
|
|
import { describe, expect, it } from "vitest";
|
||
|
|
import { DEPARTMENTS, makeMe, renderApp } from "../../test/auth";
|
||
|
|
import { callsTo, mockFetch } from "../../test/fetchMock";
|
||
|
|
|
||
|
|
const ADMIN = makeMe({
|
||
|
|
user: { display_name: "Ann Admin", sam_account: "admin.ann" },
|
||
|
|
roles: ["admin"],
|
||
|
|
screens: ["clerical", "warehouse", "supervisor", "stall", "qc", "pm", "admin"],
|
||
|
|
});
|
||
|
|
|
||
|
|
const GB = 1024 ** 3;
|
||
|
|
const ALERT = {
|
||
|
|
id: 3,
|
||
|
|
kind: "assets_quota",
|
||
|
|
severity: "warning",
|
||
|
|
subject: "assets",
|
||
|
|
detail: { total: 100 * GB, used: 90 * GB, free: 10 * GB, pct: 90, warn: true },
|
||
|
|
created_at: "2026-10-16T07:00:00Z",
|
||
|
|
resolved_at: null,
|
||
|
|
acknowledged_at: null,
|
||
|
|
acknowledged_by: null,
|
||
|
|
};
|
||
|
|
|
||
|
|
function base(clamav: { configured: boolean; host: string | null; reachable: boolean | null }) {
|
||
|
|
return {
|
||
|
|
"/api/auth/me": { body: ADMIN },
|
||
|
|
"/api/departments": { body: DEPARTMENTS },
|
||
|
|
"/api/admin/users": { body: [] },
|
||
|
|
"/api/admin/storage": {
|
||
|
|
body: { usage: { total: 100 * GB, used: 90 * GB, free: 10 * GB, pct: 90, warn: true }, quota_warn_pct: 85, alert: ALERT, clamav },
|
||
|
|
},
|
||
|
|
"/api/admin/alerts": { body: { alerts: [ALERT] } },
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
describe("Admin Storage tab", () => {
|
||
|
|
it("shows the usage, the warning threshold, the scanner and the open alert, and acknowledges it", async () => {
|
||
|
|
const fetch = mockFetch({ ...base({ configured: true, host: "clamav", reachable: true }), "POST /api/admin/alerts/3/ack": { body: { ...ALERT, acknowledged_at: "2026-10-16T08:00:00Z" } } });
|
||
|
|
renderApp("/admin");
|
||
|
|
fireEvent.click(await screen.findByRole("tab", { name: "Storage" }));
|
||
|
|
expect(await screen.findByText(/^Used/)).toHaveTextContent("Used 90 GB of 100 GB (90%).");
|
||
|
|
expect(screen.getByRole("meter", { name: "Assets volume used" })).toHaveAttribute("aria-valuenow", "90");
|
||
|
|
expect(screen.getByText("Warning at 85%.")).toBeInTheDocument();
|
||
|
|
expect(screen.getByText("clamav: reachable")).toBeInTheDocument();
|
||
|
|
const status = screen.getByRole("status");
|
||
|
|
expect(status).toHaveTextContent("The assets volume is 90% full.");
|
||
|
|
const table = await screen.findByRole("table", { name: "Open alerts" });
|
||
|
|
expect(within(table).getByText("warning")).toBeInTheDocument();
|
||
|
|
fireEvent.click(within(status).getByRole("button", { name: "Acknowledge" }));
|
||
|
|
await waitFor(() => expect(callsTo(fetch, "POST", "/api/admin/alerts/3/ack")).toEqual([{}]));
|
||
|
|
expect(await screen.findByText("Alert acknowledged.")).toBeInTheDocument();
|
||
|
|
});
|
||
|
|
|
||
|
|
it("says Not configured when no scanner is set", async () => {
|
||
|
|
mockFetch(base({ configured: false, host: null, reachable: null }));
|
||
|
|
renderApp("/admin");
|
||
|
|
fireEvent.click(await screen.findByRole("tab", { name: "Storage" }));
|
||
|
|
expect(await screen.findByText("Not configured")).toBeInTheDocument();
|
||
|
|
});
|
||
|
|
});
|