/** * @file Administration.test.tsx * @description The Administration page (`/admin`): local mode and a developer * are sent home; staff land on the Users tab; the Server tab shows the * machine's hardware, every disk, and each user's CPU/memory/home share from * `GET /api/host`, with a user's busiest processes on click. * @author Nguyễn Ngọc Trí Vĩ */ import { beforeEach, describe, expect, it, vi } from "vitest"; import { fireEvent, render, screen, within } from "@testing-library/react"; import { MemoryRouter, Route, Routes } from "react-router-dom"; import type { AuthState, HostStats } from "../../lib/api"; let authState: AuthState = { mode: "local" }; vi.mock("../../components/AuthGate", () => ({ useAuth: () => ({ state: authState, logout: async () => {} }), })); const GB = 1024 ** 3; const stats: HostStats = { at: "2026-10-15T00:00:00Z", hostname: "box", os: { platform: "linux", release: "7.0.0", distro: "Ubuntu 26.04", arch: "x64" }, uptime: 90000, cpu: { model: "i5-7500", cores: 4, load: [1, 0.5, 0.25] }, memory: { total: 16 * GB, available: 8 * GB, used: 8 * GB, swapTotal: 4 * GB, swapUsed: 0 }, disks: [ { device: "/dev/sdb2", mount: "/", type: "ext4", kind: "SSD", total: 200 * GB, used: 50 * GB, free: 150 * GB, }, { device: "/dev/sda1", mount: "/data", type: "ext4", kind: "HDD", total: 500 * GB, used: 0, free: 500 * GB, }, ], homesMount: "/", gpus: [], usage: { cpu: 40, sampleMs: 1000, groups: [ { key: "user:2", kind: "user", userId: 2, username: "mia", cpu: 25, memory: 2 * GB, memoryPercent: 12.5, processes: 3, top: [{ pid: 77, name: "claude", cpu: 20, memory: GB }], }, { key: "host", kind: "host", cpu: 5, memory: GB, memoryPercent: 6.3, processes: 90, top: [] }, ], }, }; const api = vi.hoisted(() => ({ host: { stats: vi.fn() }, users: { list: vi.fn(), audit: vi.fn(), storage: vi.fn(), tmux: vi.fn(async () => ({ available: false, users: [] })), avatarUrl: () => null, }, })); vi.mock("../../lib/api", async (importOriginal) => { const actual = await importOriginal>(); return { ...actual, api: { ...api, lanes: { list: vi.fn(async () => ({ lanes: [], counts: {} })) }, accountPool: { list: vi.fn(async () => ({ accounts: [], codex: [], blockPercent: 90 })) }, }, }; }); import { Administration } from "../Administration"; const renderAt = (url: string) => render( } /> } /> ); beforeEach(() => { api.host.stats.mockResolvedValue(stats); api.users.list.mockResolvedValue({ users: [ { id: 1, username: "boss", role: "admin", disabled: false, workspaces: 0, sessions: 0, last7d: { cost: 0, tokens: 0 }, last30d: { cost: 0, tokens: 0 }, }, { id: 2, username: "mia", role: "developer", displayName: "Mia", disabled: false, workspaces: 1, sessions: 2, last7d: { cost: 0, tokens: 0 }, last30d: { cost: 0, tokens: 0 }, }, ], }); api.users.audit.mockResolvedValue({ entries: [] }); api.users.storage.mockResolvedValue({ storage: { 2: { bytes: 20 * GB, files: 10, partial: false, measuredAt: "x" } }, measuring: false, }); }); describe("Administration", () => { it("sends local mode and a developer home", async () => { authState = { mode: "local" }; renderAt("/admin"); expect(await screen.findByTestId("home")).toBeTruthy(); authState = { mode: "server", user: { id: 2, username: "mia", role: "developer" } }; renderAt("/admin"); expect((await screen.findAllByTestId("home")).length).toBeGreaterThan(0); }); it("opens on the Users tab", async () => { authState = { mode: "server", user: { id: 1, username: "boss", role: "admin" } }; renderAt("/admin"); expect(await screen.findByTestId("users-table")).toBeTruthy(); expect(screen.getByRole("tab", { name: /users/i }).getAttribute("aria-selected")).toBe("true"); }); it("shows hardware and each user's share on the Server tab", async () => { authState = { mode: "server", user: { id: 1, username: "boss", role: "admin" } }; renderAt("/admin?tab=server"); const table = await screen.findByTestId("server-usage-table"); expect(await screen.findByText("box")).toBeTruthy(); expect(screen.getByTestId("server-disks-table").textContent).toContain("HDD"); const mia = await within(table).findByText("Mia"); const row = mia.closest("tr")!; expect(row.textContent).toContain("25%"); expect(row.textContent).toContain("(13%)"); // 20 GB home on the 200 GB homes disk. expect(row.textContent).toContain("10%"); expect(within(table).queryByText("claude")).toBeNull(); fireEvent.click(mia.closest("button")!); expect(within(table).getByText("claude")).toBeTruthy(); }); });