Print CLI errors as one line instead of a stack trace (closes #102)
check / check (push) Successful in 1m27s
check / check (push) Successful in 1m27s
An error a command throws now reaches the user as one `quak: MESSAGE` line on stderr, and the CLI exits 1 once output has drained. The wrapper moved from bin/quak.ts to src/cli-run.ts so it can be tested, and bin/quak.ts awaits program.parseAsync() so async actions are awaited. Model: opus-5-5
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Tests for `run` in `src/cli-run.ts`, which every CLI command goes through.
|
||||
*/
|
||||
|
||||
import { PassThrough } from "node:stream";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { run } from "../../src/cli-run.js";
|
||||
|
||||
// A stream whose written text is kept in `text`; writes finish at once, so
|
||||
// nothing is left waiting to drain.
|
||||
const collector = (): { stream: PassThrough; text: () => string } => {
|
||||
const stream = new PassThrough();
|
||||
const chunks: string[] = [];
|
||||
stream.on("data", (chunk: Buffer) => chunks.push(chunk.toString()));
|
||||
return { stream, text: () => chunks.join("") };
|
||||
};
|
||||
|
||||
const runToExit = async (
|
||||
command: Promise<number>,
|
||||
): Promise<{ code: number; stdout: string; stderr: string }> => {
|
||||
const stdout = collector();
|
||||
const stderr = collector();
|
||||
const code = await new Promise<number>((resolve) => {
|
||||
void run(command, stdout.stream, stderr.stream, resolve);
|
||||
});
|
||||
return { code, stdout: stdout.text(), stderr: stderr.text() };
|
||||
};
|
||||
|
||||
describe("run", () => {
|
||||
it("exits with the code the command returns", async () => {
|
||||
const result = await runToExit(Promise.resolve(3));
|
||||
expect(result).toEqual({ code: 3, stdout: "", stderr: "" });
|
||||
});
|
||||
|
||||
it("prints a thrown error as one line without a stack trace and exits 1", async () => {
|
||||
const failing = async (): Promise<number> => {
|
||||
throw new Error(
|
||||
"ENOTDIR: not a directory, mkdir '/dev/null/x/originals'",
|
||||
);
|
||||
};
|
||||
const result = await runToExit(failing());
|
||||
expect(result.code).toBe(1);
|
||||
expect(result.stdout).toBe("");
|
||||
expect(result.stderr).toBe(
|
||||
"quak: ENOTDIR: not a directory, mkdir '/dev/null/x/originals'\n",
|
||||
);
|
||||
});
|
||||
|
||||
it("prints a thrown value that is not an Error", async () => {
|
||||
const result = await runToExit(Promise.reject("offline"));
|
||||
expect(result).toEqual({
|
||||
code: 1,
|
||||
stdout: "",
|
||||
stderr: "quak: offline\n",
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user