Files
nextcraft/apps/cli/tests/helpers.ts
T
CIAgent 1a88ab3199
Release / release (push) Successful in 3m45s
CI / python (push) Successful in 1m52s
CI / node (push) Successful in 1m0s
merge: milestone/v0.8-ship-anywhere -> main (v0.8 complete — Ship Anywhere)
The v0.8 milestone: installable on any Debian-based server via docker
(Gitea registry image, honest sandbox degrade), deb (amd64+arm64,
advisory postinst), and arch-aware binary — with release consistency
enforced by pre-commit hooks + Gitea Actions (3-runner fleet on CT 113,
machine-made releases with the full 8-asset matrix + registry image), the
CLI carrying the full suite (guide, channel-aware doctor), and the admin
runbook (deploy/README.md, evidence-backed recipes).

---ci---
phase: 6
milestone: v0.8
status: complete
requirements:
  covered: [REQ-8-001, REQ-8-002, REQ-8-003, REQ-8-004, REQ-8-005]
  partial: []
---/ci---
2026-09-29 16:04:40 +00:00

54 lines
1.9 KiB
TypeScript

import type { Ctx } from "../src/ctx.ts";
import { readFileSync, existsSync, writeFileSync } from "node:fs";
import net from "node:net";
import { run as spawnRun } from "../src/lib/spawn.ts";
import type { SpawnResult } from "../src/lib/spawn.ts";
export interface TestCtx extends Ctx {
out(): string;
err(): string;
writes: Record<string, string>;
}
export function testCtx(overrides: Partial<Ctx> = {}): TestCtx {
const out: string[] = [];
const err: string[] = [];
const writes: Record<string, string> = {};
const base = {
cwd: process.cwd(),
env: { ...process.env } as Record<string, string | undefined>,
stdout: { write: (s: string) => void out.push(s) },
stderr: { write: (s: string) => void err.push(s) },
spawn: async (cmd: string, args: string[], opts: Parameters<Ctx["spawn"]>[2]) =>
spawnRun(cmd, args, opts),
exists: (p: string) => existsSync(p),
readFile: (p: string) => (existsSync(p) ? readFileSync(p, "utf8") : undefined),
writeFile: (p: string, c: string) => {
writes[p] = c;
writeFileSync(p, c);
},
portFree: async (port: number, host: string) =>
new Promise<boolean>((resolve) => {
const srv = net.createServer();
srv.once("error", () => resolve(false));
srv.once("listening", () => srv.close(() => resolve(true)));
srv.listen(port, host);
}),
out: () => out.join(""),
err: () => err.join(""),
};
const ctx = { ...base, ...overrides } as unknown as TestCtx;
(ctx as unknown as { writes: Record<string, string> }).writes = writes;
return ctx;
}
export function fakeSpawn(
sequence: Array<{ match: (cmd: string, args: string[]) => boolean; result: SpawnResult }>,
): Ctx["spawn"] {
return async (cmd, args) => {
const hit = sequence.find((s) => s.match(cmd, args));
if (!hit) throw new Error(`unexpected spawn: ${cmd} ${args.join(" ")}`);
return hit.result;
};
}