Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ coverage/
.dolt/
*.db
.beads-credential-key
AGY.md
32 changes: 0 additions & 32 deletions plan.md

This file was deleted.

56 changes: 56 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
function printHelp() {
console.log("Usage: fleet-e2e-toy [command] [options]\n");
console.log("Commands:");
console.log(" add <title> Add a new note");
console.log(" serve Start the API server");
console.log(" help Show this help message\n");
console.log("Options:");
console.log(" --version, -v Show version information");
console.log(" --help, -h Show this help message");
}

async function main() {
const args = process.argv.slice(2);

if (args.includes('--version') || args.includes('-v')) {
console.log('fleet-e2e-toy v1.0.0');
process.exit(0);
}

if (args.length === 0) {
printHelp();
process.exit(0);
}

const firstArg = args[0];

if (firstArg.trim() === '') {
console.error('Error: Argument cannot be empty or whitespace-only.');
process.exit(1);
}

if (firstArg === 'help' || firstArg === '--help' || firstArg === '-h') {
printHelp();
process.exit(0);
}

if (firstArg === 'add') {
const titleVal = args[1];
if (titleVal === undefined || titleVal.trim() === '') {
console.error('Error: Note title cannot be empty or whitespace-only.');
process.exit(1);
}
console.log(`Note added: ${titleVal}`);
process.exit(0);
}

if (firstArg === 'serve') {
console.log('Starting server...');
process.exit(0);
}
}

main().catch((err) => {
console.error(err);
process.exit(1);
});
138 changes: 138 additions & 0 deletions tests/cli.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { exec } from "child_process";
import * as path from "path";

jest.setTimeout(20000);

const cliScript = path.resolve(__dirname, "../src/cli.ts");

function runCli(args: string[]): Promise<{ code: number; stdout: string; stderr: string }> {
return new Promise((resolve) => {
// For executing in terminal, quote each argument.
// Replace double quotes inside the arg with escaped double quotes.
const escapedArgs = args.map(arg => {
const escaped = arg.replace(/"/g, '\\"');
return `"${escaped}"`;
}).join(" ");

const cmd = `npx ts-node "${cliScript}" ${escapedArgs}`;

exec(cmd, (error, stdout, stderr) => {
resolve({
code: error ? (error.code ?? 1) : 0,
stdout: stdout.trim(),
stderr: stderr.trim(),
});
});
});
}

describe("CLI Tool", () => {
describe("Version Flags", () => {
it("should print version and exit 0 for --version", async () => {
const result = await runCli(["--version"]);
expect(result.code).toBe(0);
expect(result.stdout).toBe("fleet-e2e-toy v1.0.0");
expect(result.stderr).toBe("");
});

it("should print version and exit 0 for -v", async () => {
const result = await runCli(["-v"]);
expect(result.code).toBe(0);
expect(result.stdout).toBe("fleet-e2e-toy v1.0.0");
expect(result.stderr).toBe("");
});
});

describe("Help Commands", () => {
const expectedHelpText =
"Usage: fleet-e2e-toy [command] [options]\n\n" +
"Commands:\n" +
" add <title> Add a new note\n" +
" serve Start the API server\n" +
" help Show this help message\n\n" +
"Options:\n" +
" --version, -v Show version information\n" +
" --help, -h Show this help message";

it("should print help and exit 0 for help command", async () => {
const result = await runCli(["help"]);
expect(result.code).toBe(0);
expect(result.stdout).toBe(expectedHelpText);
expect(result.stderr).toBe("");
});

it("should print help and exit 0 for --help flag", async () => {
const result = await runCli(["--help"]);
expect(result.code).toBe(0);
expect(result.stdout).toBe(expectedHelpText);
expect(result.stderr).toBe("");
});

it("should print help and exit 0 for -h flag", async () => {
const result = await runCli(["-h"]);
expect(result.code).toBe(0);
expect(result.stdout).toBe(expectedHelpText);
expect(result.stderr).toBe("");
});
});

describe("Input Validation", () => {
it("should fail and exit 1 for empty string argument", async () => {
const result = await runCli([""]);
expect(result.code).toBe(1);
expect(result.stderr).toContain("Error: Argument cannot be empty or whitespace-only.");
expect(result.stdout).toBe("");
});

it("should fail and exit 1 for whitespace-only argument", async () => {
const result = await runCli([" "]);
expect(result.code).toBe(1);
expect(result.stderr).toContain("Error: Argument cannot be empty or whitespace-only.");
expect(result.stdout).toBe("");
});

it("should succeed and exit 0 for valid arguments", async () => {
const result = await runCli(["valid-arg"]);
expect(result.code).toBe(0);
expect(result.stdout).toBe("");
expect(result.stderr).toBe("");
});
});

describe("Subcommands (add/serve)", () => {
it("should log Starting server... and exit 0 for serve command", async () => {
const result = await runCli(["serve"]);
expect(result.code).toBe(0);
expect(result.stdout).toBe("Starting server...");
expect(result.stderr).toBe("");
});

it("should log Note added: <title> and exit 0 for add command with valid title", async () => {
const result = await runCli(["add", "my new note"]);
expect(result.code).toBe(0);
expect(result.stdout).toBe("Note added: my new note");
expect(result.stderr).toBe("");
});

it("should fail and exit 1 for add command with missing title", async () => {
const result = await runCli(["add"]);
expect(result.code).toBe(1);
expect(result.stderr).toContain("Error: Note title cannot be empty or whitespace-only.");
expect(result.stdout).toBe("");
});

it("should fail and exit 1 for add command with empty string title", async () => {
const result = await runCli(["add", ""]);
expect(result.code).toBe(1);
expect(result.stderr).toContain("Error: Note title cannot be empty or whitespace-only.");
expect(result.stdout).toBe("");
});

it("should fail and exit 1 for add command with whitespace-only title", async () => {
const result = await runCli(["add", " "]);
expect(result.code).toBe(1);
expect(result.stderr).toContain("Error: Note title cannot be empty or whitespace-only.");
expect(result.stdout).toBe("");
});
});
});
3 changes: 3 additions & 0 deletions tool
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
npx ts-node src/cli.ts "$@"
exit $?
2 changes: 2 additions & 0 deletions tool.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules\.bin\ts-node.cmd src/cli.ts $args
exit $LASTEXITCODE
Loading