/** * @file MemberTmuxCard.test.tsx * @description The Users page's members' tmux card: hidden without one Linux * user per account, lists each running member server with its version and a * badge when it is older than the installed tmux, warns until tmux-member is * installed, and an admin restarts one member — or every idle outdated one, * the working member left out — only with their own password typed; an * analyst sees no restart control. * @author Nguyễn Ngọc Trí Vĩ */ import { beforeEach, describe, expect, it, vi } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import type { MemberTmux } from "../../../lib/api"; const users = vi.hoisted(() => ({ tmux: vi.fn(), tmuxRestart: vi.fn(), tmuxRestartIdle: vi.fn(), })); vi.mock("../../../lib/api", async (importOriginal) => { const actual = await importOriginal>(); return { ...actual, api: { users } }; }); vi.mock("../../../lib/toast", () => ({ toast: { success: vi.fn(), error: vi.fn() } })); import { MemberTmuxCard } from "../MemberTmuxCard"; const DATA: MemberTmux = { available: true, installed: "3.8", matched: true, users: [ { id: 2, username: "mia", running: true, version: "3.6", sessions: 2, busy: 0, outdated: true }, { id: 3, username: "zed", running: true, version: "3.6", sessions: 1, busy: 1, outdated: true }, { id: 4, username: "ann", running: true, version: "3.8", sessions: 3, busy: 0, outdated: false, }, { id: 5, username: "bob", running: false, busy: 0, outdated: false }, ], }; beforeEach(() => { vi.clearAllMocks(); users.tmux.mockResolvedValue(DATA); }); describe("MemberTmuxCard", () => { it("renders nothing without one Linux user per account", async () => { users.tmux.mockResolvedValue({ available: false, users: [] }); const { container } = render(); await waitFor(() => expect(users.tmux).toHaveBeenCalled()); expect(container).toBeEmptyDOMElement(); }); it("lists running servers and marks the ones older than the installed tmux", async () => { render(); expect(await screen.findByText("mia")).toBeInTheDocument(); expect(screen.queryByText("bob")).toBeNull(); expect(screen.getAllByText("older than installed")).toHaveLength(2); expect(screen.getByText(/Installed: tmux 3\.8/)).toBeInTheDocument(); // An analyst reads only. expect(screen.queryByRole("button", { name: /Restart/ })).toBeNull(); }); it("warns until tmux-member is installed", async () => { users.tmux.mockResolvedValue({ ...DATA, matched: false }); render(); expect(await screen.findByText(/install-system/)).toBeInTheDocument(); }); it("restarts one member only with the admin's password", async () => { users.tmuxRestart.mockResolvedValue({}); render(); await userEvent.click(await screen.findByRole("button", { name: "Restart mia's tmux" })); expect(screen.getByText(/Every pane of mia closes \(2 sessions\)/)).toBeInTheDocument(); const go = screen.getByRole("button", { name: "Restart" }); expect(go).toBeDisabled(); await userEvent.type(screen.getByLabelText("Your password"), "pw"); await userEvent.click(go); await waitFor(() => expect(users.tmuxRestart).toHaveBeenCalledWith(2, "pw")); }); it("restarts every idle outdated member at once, the working one left out", async () => { users.tmuxRestartIdle.mockResolvedValue({ restarted: ["mia"], skipped: ["zed"], failed: [] }); render(); await userEvent.click(await screen.findByRole("button", { name: "Restart 1 idle member" })); expect(screen.getByText(/no agent working: mia\./)).toBeInTheDocument(); await userEvent.type(screen.getByLabelText("Your password"), "pw"); await userEvent.click(screen.getByRole("button", { name: "Restart" })); await waitFor(() => expect(users.tmuxRestartIdle).toHaveBeenCalledWith("pw")); }); });