This repository has been archived on 2026-06-01. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
nerve/packages/cli/src/__tests__/workflow-cli-e2e.test.ts
T

89 lines
2.9 KiB
TypeScript

/**
* Smoke / integration tests for `nerve workflow` and `nerve thread` citty handlers with a real HOME
* layout and logs.db. `loadDaemonModule` is mocked so tests use workspace
* `@uncaged/nerve-store` directly (no ~/.uncaged-nerve daemon install required).
*/
import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { runCommand } from "citty";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("../workspace-daemon.js", async () => {
const { createLogStore } = await import("@uncaged/nerve-store");
return {
loadDaemonModule: vi.fn(async () => ({ createLogStore })),
};
});
import { createLogStore } from "@uncaged/nerve-store";
import { threadCommand } from "../commands/thread.js";
describe("nerve thread CLI (runCommand + temp HOME)", () => {
let prevHome: string | undefined;
let fakeHome: string;
let stdoutSpy: ReturnType<typeof vi.spyOn> | null;
beforeEach(() => {
stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
prevHome = process.env.HOME;
fakeHome = mkdtempSync(join(tmpdir(), "nerve-wf-cli-e2e-"));
process.env.HOME = fakeHome;
const nerveRoot = join(fakeHome, ".uncaged-nerve");
mkdirSync(join(nerveRoot, "data"), { recursive: true });
const dbPath = join(nerveRoot, "data", "logs.db");
const store = createLogStore(dbPath);
store.upsertWorkflowRun(
{ source: "workflow", type: "started", refId: "e2e-run", payload: "{}", timestamp: 5000 },
{ runId: "e2e-run", workflow: "demo", status: "completed", timestamp: 5000, exitCode: 0 },
);
store.append({
source: "workflow",
type: "completed",
refId: "e2e-run",
payload: null,
timestamp: 5001,
});
store.append({
source: "workflow",
type: "thread_command_event",
refId: "e2e-run",
payload: JSON.stringify({ type: "step", role: "bot", content: "hello" }),
timestamp: 5100,
});
store.close();
});
afterEach(() => {
stdoutSpy?.mockRestore();
stdoutSpy = null;
if (prevHome === undefined) {
process.env.HOME = undefined;
} else {
process.env.HOME = prevHome;
}
rmSync(fakeHome, { recursive: true, force: true });
});
it("thread list --all completes without throwing", async () => {
await expect(runCommand(threadCommand, { rawArgs: ["list", "--all"] })).resolves.toBeDefined();
});
it("thread inspect <runId> completes without throwing", async () => {
await expect(
runCommand(threadCommand, { rawArgs: ["inspect", "e2e-run", "--limit", "10"] }),
).resolves.toBeDefined();
});
it("thread show <runId> completes without throwing (role rounds path)", async () => {
await expect(
runCommand(threadCommand, { rawArgs: ["show", "e2e-run", "--budget", "50000"] }),
).resolves.toBeDefined();
});
});