Skip to content
Draft
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
39 changes: 0 additions & 39 deletions packages/devtools/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

193 changes: 193 additions & 0 deletions packages/devtools/test/args.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import { describe, expect, it } from "vitest";
import { HELP, parseArgs } from "../src/args.js";
import type { Flags } from "../src/types.js";

const allFalse: Flags = {
dryRun: false,
volumes: false,
stopDb: false,
yes: false,
};

describe("parseArgs — command positional", () => {
it("captures the first positional as command", () => {
expect(parseArgs(["up"]).command).toBe("up");
});

it("returns undefined command for an empty argv", () => {
expect(parseArgs([]).command).toBeUndefined();
});

it("captures only the first positional; extras go to unknown", () => {
const r = parseArgs(["up", "extra"]);
expect(r.command).toBe("up");
expect(r.unknown).toEqual(["extra"]);
});

it("treats a dash-prefixed token as a flag even when it appears first", () => {
const r = parseArgs(["--dry-run", "up"]);
expect(r.command).toBe("up");
expect(r.flags.dryRun).toBe(true);
});

it("does not treat a command-like token after a flag as unknown", () => {
const r = parseArgs(["-y", "down"]);
expect(r.command).toBe("down");
expect(r.unknown).toEqual([]);
});
});

describe("parseArgs — boolean flags default false", () => {
it("all flags start false for an empty argv", () => {
expect(parseArgs([]).flags).toEqual(allFalse);
});
});

describe("parseArgs — long flags", () => {
it.each([
["--dry-run", "dryRun"],
["--volumes", "volumes"],
["--stop-db", "stopDb"],
["--yes", "yes"],
] as const)("sets %s → flags.%s", (flag, key) => {
expect(parseArgs([flag]).flags[key]).toBe(true);
});

it("only the named long flag is set", () => {
expect(parseArgs(["--volumes"]).flags).toEqual({ ...allFalse, volumes: true });
});
});

describe("parseArgs — short aliases", () => {
it("-n aliases --dry-run", () => {
expect(parseArgs(["-n"]).flags.dryRun).toBe(true);
});

it("-y aliases --yes", () => {
expect(parseArgs(["-y"]).flags.yes).toBe(true);
});

it("short aliases set no other flag", () => {
expect(parseArgs(["-n"]).flags).toEqual({ ...allFalse, dryRun: true });
});
});

describe("parseArgs — help", () => {
it("recognises --help", () => {
expect(parseArgs(["--help"]).help).toBe(true);
});

it("recognises -h", () => {
expect(parseArgs(["-h"]).help).toBe(true);
});

it("help defaults to false", () => {
expect(parseArgs([]).help).toBe(false);
});

it("help does not set any boolean flag", () => {
expect(parseArgs(["--help"]).flags).toEqual(allFalse);
});

it("help can combine with a command", () => {
const r = parseArgs(["up", "-h"]);
expect(r.help).toBe(true);
expect(r.command).toBe("up");
});

it("help takes precedence visually but leaves command intact when --help comes first", () => {
const r = parseArgs(["-h", "up"]);
expect(r.help).toBe(true);
expect(r.command).toBe("up");
});
});

describe("parseArgs — unknown handling", () => {
it("collects unknown long flags", () => {
expect(parseArgs(["--bogus"]).unknown).toEqual(["--bogus"]);
});

it("collects surplus positionals as unknown", () => {
expect(parseArgs(["up", "extra1", "extra2"]).unknown).toEqual([
"extra1",
"extra2",
]);
});

it("preserves order of unknown tokens across flags and positionals", () => {
const r = parseArgs(["--bogus", "up", "extra", "--wat"]);
expect(r.unknown).toEqual(["--bogus", "extra", "--wat"]);
});

it("does not mutate flags for an unknown flag", () => {
expect(parseArgs(["--nope"]).flags).toEqual(allFalse);
});

it("a bare dash is treated as an unknown flag", () => {
const r = parseArgs(["-"]);
expect(r.unknown).toEqual(["-"]);
expect(r.command).toBeUndefined();
});
});

describe("parseArgs — combinations", () => {
it("parses a realistic up invocation", () => {
const r = parseArgs(["up", "--dry-run", "-y"]);
expect(r).toEqual({
command: "up",
flags: { ...allFalse, dryRun: true, yes: true },
help: false,
unknown: [],
});
});

it("parses down --volumes --stop-db", () => {
const r = parseArgs(["down", "--volumes", "--stop-db"]);
expect(r.command).toBe("down");
expect(r.flags.volumes).toBe(true);
expect(r.flags.stopDb).toBe(true);
expect(r.flags.dryRun).toBe(false);
expect(r.flags.yes).toBe(false);
});

it("flags can appear before the command", () => {
const r = parseArgs(["-n", "verify"]);
expect(r.command).toBe("verify");
expect(r.flags.dryRun).toBe(true);
});

it("flags interleave freely with the command", () => {
const r = parseArgs(["--yes", "down", "--stop-db", "--volumes"]);
expect(r).toEqual({
command: "down",
flags: { ...allFalse, yes: true, stopDb: true, volumes: true },
help: false,
unknown: [],
});
});
});

describe("HELP text", () => {
it("is a non-empty string", () => {
expect(typeof HELP).toBe("string");
expect(HELP.length).toBeGreaterThan(0);
});

it("documents every command", () => {
for (const cmd of ["up", "down", "verify", "provision-prod"]) {
expect(HELP).toContain(cmd);
}
});

it("documents the help flags", () => {
expect(HELP).toContain("--help");
expect(HELP).toContain("-h");
});

it("documents every boolean flag", () => {
expect(HELP).toContain("--dry-run");
expect(HELP).toContain("--volumes");
expect(HELP).toContain("--stop-db");
expect(HELP).toContain("--yes");
});
});
Loading