$shout

shell output tester

$ curl -fsSL https://because.sh/shout | sh

✓ Write a test

Each .shout file is a session.

Commands start with $.

Everything else is expected output.

... matches anything — inline or across lines.

[1] asserts the exit code. Default expects 0.

Lines starting with # are comments.

(\# matches output starting with #.)

$ echo hello
hello

$ ls missing
ls: missing: No such file or directory
[1]

$ brew --version
Homebrew 5...

# start the server
$ my-server &
$ curl localhost:8080
OK

✓ Setup & teardown

Use @setup to share commands across test files.

Use @teardown to clean up after tests — it runs regardless of pass/fail.

@teardown can appear in both .shout files and setup files. Teardown failures produce warnings but don't affect test results.

# setup.shout
export DB_URL=sqlite:data/test.db
@teardown rm -f "$SHOUT_PROJECT_DIR/data/test.db"
@setup setup.shout
@teardown rm -f /tmp/extra-cleanup

$ create-db && run-tests
...

✓ Macros

Use @def to define reusable command macros.

If a command matches a macro name exactly, the body is substituted. Use \ for multi-line bodies. Macros from setup files are inherited; user-file macros override them.

@def greet echo "hello world"

$ greet
hello world

✓ Run it

Each file gets a fresh temp directory and its own /bin/sh session. State carries between commands within a file.

$ shout test
...............
15 passed in 23ms

✓ Update expectations

Rewrites your .shout files with the actual output. No more copy-pasting from the terminal.

$ shout test --update

Usage

$ shout test --help
Usage: shout test [options] [files...]

Run .shout test files

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
  --path <path>    Prepend <path> to PATH (repeatable)
  --timeout <dur>  Per-command timeout (default: "10s")
  -t, --filter     Only run files matching <pattern> (substring match)
  -v, --verbose    Print each command as it runs
  --port-from <n>  Auto-assign $PORT starting from n (default: "5400")
  --parallel       Run files in parallel
  -h, --help       display help for command

Environment

Shout sets these variables before running your commands:

HOME               temp directory for this test file
SHOUT_DIR          same temp directory
SHOUT_SOURCE_DIR   directory containing the .shout file
SHOUT_PROJECT_DIR  directory where shout was invoked
PORT               auto-assigned from 5400 (or --port-from), increments per file
PATH               prepended with --path dirs, if any

Each file runs in its own temp directory. --clean-env starts with an empty environment instead of inheriting yours.