Skip to content

Test the CLI entry point - #51

Merged
nrodd merged 1 commit into
tests/harness-and-cifrom
tests/cli-entry
Sep 28, 2026
Merged

nrodd merged 1 commit into
tests/harness-and-cifrom
tests/cli-entry

Conversation

@nrodd

@nrodd nrodd commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Chunk 9 of the test plan. src/cli.test.ts, 34 tests, plus the one file split the plan flagged.

Based on #42 (the harness). GitHub will retarget this to main when that merges. Independent of #43–#50.

The split

bin.ts called main() at import, so no test could load it without starting a wizard as a side effect. The body moves to src/cli.ts (exporting main and resolveCredential); bin.ts is now four lines.

The move is mechanical. main still calls process.exit itself on every path it did before, so there's no semantic change hiding in here — --help still returns without exiting (which keeps --help | head from truncating), everything else still exits explicitly. The only addition is an optional argv parameter that defaults to process.argv.slice(2) via parseArgs.

Rebuilt and re-smoke-tested: --version, --help, and an unknown flag still exit 0/0/2.

What's pinned

The credential ladder, because getting it wrong leaks or strands a credential: --api-key-oauth beats --api-key beats SUBTEXT_API_KEY_OAUTH beats SUBTEXT_API_KEY. Flags beat env deliberately, so a credential needn't appear in argv where it lands in shell history and the process list.

--mock ignores the environment but still honours an explicit flag. A SUBTEXT_API_KEY left in the shell would otherwise be validated — and could be rejected — or short-circuit the canned mock auth, in a mode whose entire point is making no network calls. That asymmetry is deliberate and was previously undefended.

Bad invocations exit non-zero, which matters more than the message: a typo must not fall through into an autonomous agent run. Unknown flag → 2, both credential flags → 2, positional args → 2, and runWizard never called in any of them.

The Node floor accepts 18.17.0 and rejects 18.16.0 and 17.9.1.

Plus option mapping (--dir resolved absolute, --integrations split/trimmed/de-blanked, region pinned to us), telemetry defaulting on and off via either the flag or DO_NOT_TRACK/DISABLE_TELEMETRY, and the wizard's resolved code becoming the exit code.

Two notes on the harness

Both came out of getting this wrong first:

  • process.exit throws only during main's synchronous phase. Throwing unconditionally is what stops main running on past a parse error — but a throw from inside main's own .then/.catch just becomes an unhandled rejection, and vitest flags those as a false-positive risk (15 of them, in my first pass). Async exits are recorded instead.
  • The suite stubs SUBTEXT_API_KEY* to empty in beforeEach. I have a real one exported in my shell, and without this the credential tests pass locally for the wrong reason and would behave differently in CI.

Verification

34 tests passing (87 on this branch), no unhandled errors, typecheck clean, and the rebuilt dist/bin.js verified by hand. Mutation-checked the --mock env guard and the Node minor-version check; both caught, then reverted.


Note

Low Risk
Mechanical entry-point split with no intended behavior change; new tests lock down credential resolution and failure paths on the CLI boundary.

Overview
Refactors the wizard CLI so it can be tested without side effects. Almost all logic moves from bin.ts into new src/cli.ts (main, resolveCredential, exported HELP); the binary entry is now a four-line shim that calls main(). main accepts an optional argv for tests; runtime behavior (exit codes, --help returning without exit, credential rules) is intended to stay the same.

Adds src/cli.test.ts (34 tests) with runWizard mocked. Coverage focuses on safety-sensitive behavior: credential precedence (flags over env, OAuth over plain key), --mock ignoring env credentials unless a flag is explicit, invalid invocations exiting 2 without starting the wizard, Node 18.17+ gate, option mapping (--dir, --integrations, telemetry opt-out), and wizard exit/error handling. The harness models sync process.exit as throws and clears credential env vars in beforeEach for stable CI.

Reviewed by Cursor Bugbot for commit 8ce07cb. Bugbot is set up for automated code reviews on this repo. Configure here.

Chunk 9. Adds src/cli.test.ts, 34 tests, and splits bin.ts.

bin.ts called main() at import, so nothing could load it without
starting a wizard. The body moves to src/cli.ts, which exports main and
resolveCredential; bin.ts is now the shebang and two lines. The move is
mechanical: main still exits the process itself on every path it did
before, so there is no semantic change to review.

The tests cover the credential ladder (flag beats env, -oauth beats
plain, and --mock ignores SUBTEXT_API_KEY* from the environment while
still honouring an explicit flag), the Node floor accepting 18.17.0 and
rejecting 18.16.0, and bad invocations exiting non-zero rather than
falling through into an autonomous agent run.

Two things about the harness worth knowing. process.exit is modelled as
a throw, but only while main runs synchronously — a throw from inside
main's own .then/.catch just becomes an unhandled rejection, and vitest
rightly flags those as a false-positive risk. And the suite stubs
SUBTEXT_API_KEY* to empty in beforeEach: a real key in the developer's
shell otherwise changes what these tests see.
@nrodd nrodd mentioned this pull request Sep 25, 2026
@nrodd
nrodd merged commit bb655e1 into tests/harness-and-ci Sep 28, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant