A focused, signal-driven test suite for validating dotfiles functionality.
# Run all tests
./test/runner.zsh
# Run with debug output
./test/runner.zsh --debug
# Run in CI mode
CI=1 ./test/runner.zsh
# Run quick tests only
./test/runner.zsh --quick
This test suite focuses on meaningful signal rather than exhaustive coverage. Each test should answer a specific question about the health of the dotfiles setup:
Test results are logged to standard output with color-coded status:
test/
├── runner.zsh # Main test runner (Zsh)
├── security_test.zsh # Security vulnerability scanning
├── e2e/ # Docker-based end-to-end tests
├── examples/ # Reference/example tests
├── functional/ # Functional tests (< 30s)
├── integration/ # Integration tests (< 60s)
├── lib/ # Test framework and helpers
├── performance/ # Performance regression tests
├── smoke/ # Quick validation tests (smoke + regression)
├── stress/ # Edge case and extreme condition tests
├── unit/ # Unit tests (< 5s)
│ ├── config/ # App configuration tests (kitty, wezterm, tmux, etc.)
│ ├── lib/ # Library function tests
│ ├── nvim/ # Neovim configuration tests
│ ├── scripts/ # Script tests (including git)
│ └── setup/ # Setup script tests
└── README.md # This file
0 - All tests passed1 - One or more tests failedFailure propagation: the runner executes each test file through a wrapper
that installs an EXIT trap escalating to exit 1 whenever $FAILED > 0. Test
files therefore do NOT need to manage their own exit codes (an unconditional
exit 0 at the end of a file no longer masks failed assertions). Inside
run_test_functions, a test_* function returning non-zero is counted as a
failure even if it never calls fail().
Gotcha: assert_x || assert_y chains count a failure for every missed
alternative (each assert calls fail() internally before || moves on).
Put the alternative that actually matches first, or use a plain if grep
with an explicit pass/fail/skip.
Safety: test files that execute install.sh, symlinks.sh, uninstall.sh,
or switch-theme.sh MUST sandbox HOME (and XDG_CONFIG_HOME where read)
into $TEST_TMP_DIR first - never point them at the real home directory.
symlinks.sh deletes and recreates ~/.config/nvim on real runs.
Create a new test file in the appropriate category:
#!/usr/bin/env zsh
set -euo pipefail
# Source test framework
source "$TEST_DIR/lib/test_helpers.zsh"
describe "My Feature"
test_case "Feature should work"
if [[ condition ]]; then
pass
else
fail "Expected X but got Y"
fi
Make it executable and run via runner.zsh.
The suite includes: