import { describe, it, expect, vi } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { NodeCard } from "../NodeCard";
import type { NodeInfo, ProjectInfo } from "../../api";
vi.mock("lucide-react", () => ({
Activity: () => activity,
Server: () => server,
Settings: () => settings,
Trash2: () => trash,
}));
function makeNode(overrides: Partial = {}): NodeInfo {
return {
id: "node-1",
name: "Primary Node",
type: "local",
status: "online",
maxConcurrent: 3,
createdAt: "2026-01-01T00:00:00.000Z",
updatedAt: "2026-01-01T00:00:00.000Z",
...overrides,
};
}
function makeProject(overrides: Partial = {}): ProjectInfo {
return {
id: "proj-1",
name: "Project One",
path: "/workspace/project-one",
status: "active",
isolationMode: "in-process",
createdAt: "2026-01-01T00:00:00.000Z",
updatedAt: "2026-01-01T00:00:00.000Z",
...overrides,
};
}
describe("NodeCard", () => {
it("renders node name, type, status, project count, and concurrency", () => {
const node = makeNode({ id: "node-abc", name: "Build Worker", type: "remote", status: "connecting", url: "https://remote.example.com" });
const projects = [
makeProject({ id: "proj-a", nodeId: "node-abc" }),
makeProject({ id: "proj-b", nodeId: "node-abc" }),
makeProject({ id: "proj-c", nodeId: "other-node" }),
];
render(
);
expect(screen.getByText("Build Worker")).toBeDefined();
expect(screen.getByText("Remote")).toBeDefined();
expect(screen.getByText("Connecting")).toBeDefined();
expect(screen.getByText("2")).toBeDefined();
expect(screen.getByText("3")).toBeDefined();
expect(screen.getByText("https://remote.example.com")).toBeDefined();
});
it("maps status classes correctly", () => {
const { rerender } = render(
);
expect(screen.getByText("Online").className).toContain("node-card__status--online");
rerender(
);
expect(screen.getByText("Offline").className).toContain("node-card__status--offline");
rerender(
);
expect(screen.getByText("Error").className).toContain("node-card__status--error");
});
it("fires health check and edit callbacks", () => {
const node = makeNode();
const onHealthCheck = vi.fn();
const onEdit = vi.fn();
render(
);
fireEvent.click(screen.getByLabelText("Run node health check"));
expect(onHealthCheck).toHaveBeenCalledWith(node.id);
fireEvent.click(screen.getByLabelText("Edit node"));
expect(onEdit).toHaveBeenCalledWith(node);
});
it("requires a second click to confirm remove", () => {
const onRemove = vi.fn();
const node = makeNode();
render(
);
const removeButton = screen.getByLabelText("Remove node");
fireEvent.click(removeButton);
expect(onRemove).not.toHaveBeenCalled();
expect(screen.getByText("Confirm")).toBeDefined();
fireEvent.click(screen.getByLabelText("Confirm remove node"));
expect(onRemove).toHaveBeenCalledWith(node.id);
});
});