144 lines
4.2 KiB
TypeScript
144 lines
4.2 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { existsSync, readFileSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
import { runCli } from "../src/cli";
|
|
|
|
const repoRoot = resolve(import.meta.dir, "..");
|
|
const packageJson = JSON.parse(
|
|
readFileSync(resolve(repoRoot, "package.json"), "utf8"),
|
|
) as {
|
|
bin?: Record<string, string>;
|
|
version?: string;
|
|
};
|
|
|
|
function normalizeBinTarget(target: string | undefined) {
|
|
return target?.replace(/^[.][/\\]/, "");
|
|
}
|
|
|
|
test("declares a working skvlt bin target", async () => {
|
|
expect(normalizeBinTarget(packageJson.bin?.skvlt)).toBe("src/cli.ts");
|
|
|
|
const targetPath = resolve(repoRoot, packageJson.bin!.skvlt);
|
|
expect(existsSync(targetPath)).toBe(true);
|
|
|
|
const result = Bun.spawnSync(
|
|
[process.execPath, targetPath, "backup", "--help"],
|
|
{
|
|
cwd: repoRoot,
|
|
},
|
|
);
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
});
|
|
|
|
test("dispatches the restore command", async () => {
|
|
const result = await runCli(["restore", "--help"]);
|
|
expect(result.exitCode).toBe(0);
|
|
});
|
|
|
|
test("dispatches the backup command", async () => {
|
|
const result = await runCli(["backup", "--help"]);
|
|
expect(result.exitCode).toBe(0);
|
|
});
|
|
|
|
test("dispatches the doctor command", async () => {
|
|
const result = await runCli(["doctor", "--help"]);
|
|
expect(result.exitCode).toBe(0);
|
|
});
|
|
|
|
test("dispatches the completion command", async () => {
|
|
const result = await runCli(["completion", "--help"]);
|
|
expect(result.exitCode).toBe(0);
|
|
});
|
|
|
|
test("prints top-level help", async () => {
|
|
const result = await runCli(["--help"]);
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
expect(result.stdout).toContain("Skills Vault CLI");
|
|
expect(result.stdout).toContain("Usage:");
|
|
expect(result.stdout).toContain("skvlt <command> [options]");
|
|
expect(result.stdout).toContain("backup");
|
|
expect(result.stdout).toContain("completion");
|
|
expect(result.stdout).toContain("doctor");
|
|
expect(result.stdout).toContain("restore");
|
|
expect(result.stderr).toBe("");
|
|
});
|
|
|
|
test("prints the package version", async () => {
|
|
const result = await runCli(["--version"]);
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
expect(result.stdout.trim()).toBe(packageJson.version);
|
|
expect(result.stderr).toBe("");
|
|
});
|
|
|
|
test("prints the package version as JSON", async () => {
|
|
const result = await runCli(["--json", "--version"]);
|
|
const payload = JSON.parse(result.stdout) as {
|
|
ok: boolean;
|
|
command: string;
|
|
data: { version: string };
|
|
};
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
expect(result.stderr).toBe("");
|
|
expect(payload).toEqual({
|
|
ok: true,
|
|
command: "version",
|
|
data: { version: packageJson.version! },
|
|
});
|
|
});
|
|
|
|
test("rejects unknown commands with guidance", async () => {
|
|
const result = await runCli(["sync"]);
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
expect(result.stdout).toBe("");
|
|
expect(result.stderr).toContain("Unknown command: sync");
|
|
expect(result.stderr).toContain("Run 'skvlt --help'");
|
|
});
|
|
|
|
test("returns JSON errors for unknown commands", async () => {
|
|
const result = await runCli(["sync", "--json"]);
|
|
const payload = JSON.parse(result.stdout) as {
|
|
ok: boolean;
|
|
command: string;
|
|
error: { code: string; message: string };
|
|
};
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
expect(result.stderr).toBe("");
|
|
expect(payload.ok).toBe(false);
|
|
expect(payload.command).toBe("sync");
|
|
expect(payload.error.code).toBe("UNKNOWN_COMMAND");
|
|
expect(payload.error.message).toContain("Unknown command: sync");
|
|
});
|
|
|
|
test("uses process argv when invoked like the CLI", async () => {
|
|
const { main } = await import("../src/cli");
|
|
const processRef = process as unknown as { argv: string[] };
|
|
const consoleRef = console as unknown as {
|
|
error: (...args: unknown[]) => void;
|
|
};
|
|
const originalArgv = processRef.argv;
|
|
const originalError = consoleRef.error;
|
|
let usageText = "";
|
|
|
|
try {
|
|
processRef.argv = ["bun", "/tmp/skvlt/src/cli.ts"];
|
|
consoleRef.error = (...args: unknown[]) => {
|
|
usageText = args.join(" ");
|
|
};
|
|
|
|
const exitCode = await main();
|
|
|
|
expect(exitCode).toBe(1);
|
|
expect(usageText).toContain("Usage:");
|
|
expect(usageText).toContain("skvlt <command> [options]");
|
|
} finally {
|
|
processRef.argv = originalArgv;
|
|
consoleRef.error = originalError;
|
|
}
|
|
});
|