shell output tester

This commit is contained in:
Chris Wanstrath 2026-03-09 21:45:07 -07:00
parent 17268b50f0
commit fbeba43120
3 changed files with 89 additions and 8 deletions

37
CLAUDE.md Normal file
View File

@ -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/`

View File

@ -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 <path> Prepend <path> to PATH
--timeout <dur> Per-command timeout (default: "10s")
-v, --verbose Print each command as it runs
--parallel Run files in parallel
-h, --help display help for command
```

View File

@ -45,7 +45,7 @@ async function findShoutFiles(paths: string[]): Promise<string[]> {
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")