diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..9bf54dc --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,37 @@ +# shout + +Transcript-based shell integration test runner. Bun + TypeScript. + +## Commands + +- `bun test` — run unit tests +- `bunx tsc --noEmit` — type check +- `bun run src/cli/index.ts [files...]` — run shout CLI + +## Architecture + +- `src/parse.ts` — parses `.shout` files into `ShoutFile` (list of `Command`) +- `src/run.ts` — executes commands via `Bun.spawn(["/bin/sh"])`, captures output with sentinels +- `src/match.ts` — wildcard-aware output matching and diff generation +- `src/format.ts` — evaluates pass/fail, formats failures and summary +- `src/update.ts` — rewrites `.shout` files with actual output (`--update` mode) +- `src/duration.ts` — parses duration strings (`10s`, `500ms`, `1m`) +- `src/cli/index.ts` — CLI entry point via `commander` +- `src/index.ts` — barrel exports + +## .shout file format + +- `$ ` prefix = command to execute +- Lines between commands = expected output (stdout+stderr merged) +- `...` on its own line = multi-line wildcard (matches zero or more lines) +- `...` inline = matches any characters on that line +- `[N]` on last line of expected output = assert exit code N +- `[*]` = assert any non-zero exit code; default expects 0 +- `#` after a command = comment (stripped); `#` in expected output is literal +- Each file runs in a fresh temp dir with a single `/bin/sh` session + +## Style + +- Strict TypeScript, Bun runtime +- No classes — plain functions and types +- Tests in `src/*.test.ts`, example `.shout` files in `test/` diff --git a/README.md b/README.md index 1a21116..b9ad583 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,59 @@ # shout -To install dependencies: +`shout` is kinda like really basic integration testing for your cli. -```bash -bun install +Write `.shout` files that look like shell sessions and run `shout` to test 'em. + +## Install + +``` +bun install -g @because/shout ``` -To run: +## Features -```bash -bun run index.ts +Here are all the features you could ever ask for: + +``` +$ echo hello +hello + +$ brew --version +Homebrew 5... + +$ ls missing +ls: missing: No such file or directory +[1] ``` -This project was created using `bun init` in bun v1.3.10. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime. +`...` matches anything — a whole line inline, or any number of lines on its own. + +`[1]` after the expected output matches the exit code. + +## Usage + +`shout` runs code in a temp directory. `-k`/`--keep` keeps it around. + +`--update` will modify `.shout` files to match reality, without running any tests. + +Each line in a `.shout` file is run sequentially, unless `--parallel` is passed. + +``` +Usage: shout [options] [files...] + +shell output tester. + +Arguments: + files Files or directories to test + +Options: + -u, --update Rewrite expected output in-place with actual output + -k, --keep Keep temp directories after run + --clean-env Start with empty environment + --bin Prepend to PATH + --timeout Per-command timeout (default: "10s") + -v, --verbose Print each command as it runs + --parallel Run files in parallel + -h, --help display help for command + +``` diff --git a/src/cli/index.ts b/src/cli/index.ts index 6cfc7a7..0f207c5 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -45,7 +45,7 @@ async function findShoutFiles(paths: string[]): Promise { program .name("shout") - .description("Transcript-based shell integration test runner") + .description("$ shell output tester") .argument("[files...]", "Files or directories to test") .option("-u, --update", "Rewrite expected output in-place with actual output") .option("-k, --keep", "Keep temp directories after run")