# shout `shout` is kinda like really basic integration testing for your cli. Write `.shout` files that look like shell sessions and run `shout` to test 'em. ## Install ``` bun install -g @because/shout ``` ## Features Everything you could ever ask for: ``` $ echo hello hello $ brew --version Homebrew 5... $ ls missing ls: missing: No such file or directory [1] ``` `...` matches anything — a whole line inline, or any number of lines on its own. `[1]` after the expected output matches the exit code. `$#` is a comment line — not executed, no output expected: ``` $# start the server $ my-server & $# now test it $ curl localhost:8080 OK ``` ## Usage ``` $ shout test ............... 15 passed in 23ms ``` `shout test` 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. ## Directives Directives go at the top of a `.shout` file, before any commands. ### `@env` Set environment variables for the test: ``` @env GREETING=hello @env TARGET=world $ echo "$GREETING $TARGET" hello world ``` ### `@setup` Prepend commands (and `@env` directives) from another `.shout` file: ``` @setup setup-shared.shout ``` Setup commands run first and their failures abort the test. Setup files cannot themselves contain `@setup` — no nesting. If both the setup file and the user file define the same `@env`, the user file wins. ### `@teardown` Run a cleanup command after all test commands, regardless of pass/fail: ``` @teardown rm -f "$SHOUT_PROJECT_DIR/data/test.db" $ create-db && run-tests ... ``` Teardown failures produce warnings but don't affect test results. You can also put `@teardown` in setup files: ``` # setup.shout export DB_URL=sqlite:data/test.db @teardown rm -f "$SHOUT_PROJECT_DIR/data/test.db" ``` ``` 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 Prepend to PATH (repeatable) --timeout Per-command timeout (default: "10s") -v, --verbose Print each command as it runs --port-from Auto-assign $PORT starting from n (default: "5400") --parallel Run files in parallel -h, --help display help for command ``` ## Environment Variables ### Set automatically | Variable | Value | |---|---| | `HOME` | Path to the temp directory created for the test | | `SHOUT_DIR` | Same as `HOME` — the temp directory for the test | | `SHOUT_SOURCE_DIR` | Directory containing the `.shout` file being run | | `SHOUT_PROJECT_DIR` | The `cwd` where `shout` was invoked | | `PORT` | Auto-assigned starting from `5400` (or the value of `--port-from`), increments per file. Not set if `PORT` is already defined via `@env` or `@setup`. | ### Inherited By default, the test shell inherits all environment variables from the parent process. Use `--clean-env` to start with an empty environment instead. ### Modified `PATH` is prepended with any directories passed via `--path `. ### User-defined Use `@env KEY=VALUE` directives to set arbitrary variables. See [Directives](#directives). Print an example `.shout` file: ``` $ shout example ``` ## Editor Support ### Neovim The `vim/` directory contains a Neovim plugin with syntax highlighting and commands (`:ShoutRun`, `:ShoutUpdate`, `:ShoutRunAll`). #### lazy.nvim ```lua { dir = "~/path/to/shout/vim", ft = "shout", } ``` #### Manual ```sh mkdir -p ~/.local/share/nvim/site/pack/shout/start ln -s /path/to/shout/vim ~/.local/share/nvim/site/pack/shout/start/shout ```