Files
nextcraft/apps/cli/tests/fresh-clone-e2e.test.ts
T
CIAgent 2c68b44c1a merge: milestone/v0.4-distribution → main (v0.4 Distribution & Bootstrap CLI complete)
The nextcraft bootstrap CLI ships: doctor/bootstrap/verify/dev commands, a
one-liner install script with checksum + version integrity gates, and linux
x64 SEA binaries published on every release going forward (v0.3.2 onward).
Fresh-clone E2E proven; 34 CLI tests + full monorepo gates green.

Escalation note: merge_to_main hook — proceeding per full autonomy + founder
directive D-016 (streamlined install + bootstrap CLI + ongoing binaries,
recorded at P0 SPECIFY).

---ci---
phase: 4
milestone: v0.4
status: complete
requirements:
  covered: [REQ-4-001, REQ-4-002, REQ-4-003, REQ-4-004, REQ-4-005]
  partial: []
---/ci---
2026-09-12 23:17:43 +00:00

72 lines
2.9 KiB
TypeScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { mkdtempSync, existsSync, readFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
const cliDir = join(dirname(fileURLToPath(import.meta.url)), "..");
const repoRoot = join(cliDir, "..", "..");
test("fresh-clone E2E: clone -> doctor -> bootstrap -> verify (happy path, transcript)", async () => {
const work = mkdtempSync(join(tmpdir(), "nc-e2e-"));
const cloneDir = join(work, "nextcraft");
const clone = spawnSync(
"git",
["clone", "--quiet", "--no-hardlinks", repoRoot, cloneDir],
{ encoding: "utf8", timeout: 120000 },
);
assert.equal(clone.status, 0, `clone failed: ${clone.stderr}`);
const binary = join(repoRoot, "apps", "cli", "dist", "nextcraft-linux-x64");
const cli = existsSync(binary)
? binary
: join(cliDir, "node_modules", ".bin", "tsx");
const transcript: string[] = [];
const step = (name: string, args: string[], expect: number, timeoutMs: number) => {
const { NODE_TEST_CONTEXT, ...restEnv } = process.env as Record<string, string | undefined>;
const env = {
...restEnv,
PATH: [join(process.env.HOME ?? "/home", ".local/bin"), process.env.PATH].filter(Boolean).join(":"),
NEXTCRAFT_VERSION: "v-e2e",
} as Record<string, string | undefined>;
const run = spawnSync(cli, existsSync(binary) ? args : [join(cliDir, "src", "index.ts"), ...args], {
cwd: cloneDir,
encoding: "utf8",
timeout: timeoutMs,
env,
});
transcript.push(`$ nextcraft ${args.join(" ")} -> exit ${run.status}`);
if (run.status !== expect) {
transcript.push(run.stdout, run.stderr);
assert.fail(
`${name} exited ${run.status} (expected ${expect})\nTRANSCRIPT:\n${transcript.join("\n")}\nstderr: ${run.stderr}`,
);
}
return run.stdout + run.stderr;
};
const doctorOut = step("doctor", ["doctor"], 0, 60000);
assert.ok(doctorOut.includes("node"), "doctor mentions node");
assert.ok(doctorOut.includes("pnpm"), "doctor mentions pnpm");
step("bootstrap", ["bootstrap"], 0, 600000);
const verifyOut = step("verify", ["verify"], 0, 120000);
assert.ok(verifyOut.includes("venv"), "verify covers venv");
assert.ok(existsSync(join(cloneDir, "apps", "ai-service", ".env")), ".env created in clone");
assert.ok(existsSync(join(cloneDir, "apps", "ai-service", ".venv")), "venv created in clone");
assert.ok(
existsSync(join(cloneDir, "node_modules", ".pnpm")),
"workspace node_modules present",
);
const envExample = readFileSync(join(repoRoot, "apps", "ai-service", ".env.example"), "utf8");
const envClone = readFileSync(join(cloneDir, "apps", "ai-service", ".env"), "utf8");
assert.equal(envClone, envExample, ".env content matches template");
console.log("E2E TRANSCRIPT:\n" + transcript.join("\n"));
});