shout/CLAUDE.md
Chris Wanstrath ce1503a9d4 Add @def directive for command macro substitution
Macros let setup files define reusable command shorthands that
test files can invoke by name or override with their own definition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 11:28:59 -07:00

4.1 KiB

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 test [files...] — run shout CLI
    • -u, --update — rewrite .shout files with actual output
    • -k, --keep — keep temp directories after run
    • --clean-env — start with empty environment
    • --path <path> — prepend to $PATH (repeatable)
    • --timeout <dur> — per-command timeout (default 10s)
    • -t, --filter <pattern> — only run files whose path contains <pattern>
    • -v, --verbose — print each command as it runs
    • --port-from <n> — auto-assign $PORT starting from n (default 5400)
    • --parallel — run files in parallel

Architecture

  • src/parse.ts — parses .shout files into ShoutFile (list of Command)
  • src/run.ts — executes commands via Bun.spawn(["/bin/sh"], { detached: true }), 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/utils.ts — shared utilities (trimTrailingEmpty, escapeRegex)
  • src/duration.ts — parses duration strings (10s, 500ms, 1m)
  • src/cli/index.ts — CLI entry point via commander
  • src/index.ts — barrel exports
  • web/index.html — web documentation page

.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
  • $# comment line = not executed, no output expected (e.g. $# start the server)
  • # after a command = comment (stripped); # in expected output is literal
  • @env KEY=VALUE before first command = set environment variable
  • @teardown <command> before first command = run command after all test commands
    • Runs regardless of pass/fail
    • Teardown failures produce warnings but don't affect test results
    • Can appear in both .shout files and setup files
  • @setup path.shout before first command = prepend commands (and @env) from another file
    • Setup files use a plain format: each line is a command (no $ prefix), # lines are comments, blank lines ignored
    • Setup files can contain @env and @teardown directives but not @setup (no nesting)
    • User file @env overrides setup file @env
    • Setup command failures abort the test with an error
  • @def name body before first command = define a macro
    • If a command matches name exactly, body is substituted before execution
    • Backslash \ at end of line continues the body onto the next line
    • Allowed in both .shout files and setup files
    • User file @def overrides setup file @def with the same name
  • Each file runs in a fresh temp dir with a single /bin/sh session
  • $HOME and $SHOUT_DIR are set to the temp dir automatically
  • $SHOUT_SOURCE_DIR is set to the directory containing the .shout file
  • $SHOUT_PROJECT_DIR is set to cwd where shout was invoked
  • stdout and stderr are merged (exec 2>&1)

New feature checklist

  1. src/parse.ts — update types (Directive, ShoutFile, Command) and both parsers (parse + parseSetup)
  2. src/parse.test.ts — unit tests for parsing the new syntax in both .shout and setup file contexts
  3. src/cli/index.ts — wire up the parsed result in runOne (directive resolution, command merging, result handling)
  4. test/*.shout — integration test file exercising the feature end-to-end
  5. CLAUDE.md — update .shout file format section
  6. README.md — update Directives section
  7. web/index.html — add or update a section on the website
  8. Run bun test and bun run src/cli/index.ts test test/ to verify

Style

  • Strict TypeScript, Bun runtime
  • No classes — plain functions and types
  • Tests in src/*.test.ts, example .shout files in test/