Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,17 @@ The async, snapshot, progress, and timeout examples are compile-checked rather
than executed by this step because they intentionally demonstrate delays,
generated files, interactive output, or failure handling.

## Watch Mode

```bash
zig-test --test-dir tests --watch
```

After the initial full run, watch mode reruns changed tests or tests affected by
relative Zig imports. It falls back to the full suite when dependency data is
incomplete. Type `r` and press Enter to force a full rerun. See
[docs/watch-mode.md](docs/watch-mode.md) for selection and debounce behavior.

## Requirements

- The exact Zig development build recorded in [`.zig-version`](.zig-version)
Expand All @@ -905,6 +916,7 @@ Comprehensive guides and API documentation:
- **[Mocking & Spying](docs/mocks.md)** - Complete Jest-compatible mocking API with 20+ methods
- **[Snapshot Testing](docs/snapshots.md)** - Multiple formats, named snapshots, and diff visualization
- **[Date & Time Mocking](docs/dates-and-times.md)** - Control time with `setSystemTime()` and Jest-compatible APIs
- **[Watch Mode](docs/watch-mode.md)** - Affected-test selection, safe fallbacks, and full reruns

### Additional Resources

Expand Down
45 changes: 45 additions & 0 deletions docs/watch-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Watch mode

Watch mode runs the full discovered suite once, then polls Zig source and test
files after the configured debounce interval. Start it with a test directory:

```bash
zig-test --test-dir tests --watch
```

Type `r` and press Enter at any time to request an explicit full-suite rerun.
Ctrl-C stops the watcher and any UI server cleanly.

## Affected-test selection

Each rerun prints both the selected test and the reason it was selected:

```text
Watch selection:
- math.test.zig (imports changed source: src/math.zig)
```

The selection rules are conservative:

- A modified or newly added test file runs by itself. Multiple changed tests
are batched by the debounce interval and run together.
- For a source change, the watcher follows relative `.zig` imports from every
discovered test, including transitive imports, and runs tests whose import
graph contains the changed file.
- Named module imports such as `@import("my_app")` cannot be resolved from
source text alone. If any test has unresolved imports, or a changed source
file maps to no test, the watcher safely runs the full suite.
- Deleting a test, or renaming one (observed as a delete plus an add), runs the
full suite so reporters and the live UI receive the new test topology.
- Deleting or renaming an imported source file also falls back to the full
suite when its dependency graph can no longer be resolved.

The watcher scans the project root for `.zig` changes while using `--test-dir`,
`--pattern`, and recursive-discovery settings to decide which files are tests.
It excludes Git metadata, Zig caches/output, `node_modules`, and `.codex`.

## Debouncing

`--watch-debounce <ms>` controls the polling and batching interval. The default
is 300 milliseconds. A test run is never interrupted: edits made while tests
are running are detected on the next poll and cause another affected run.
1 change: 1 addition & 0 deletions src/cli.zig
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ pub const CLI = struct {
\\WATCH MODE:
\\ -w, --watch Watch files and re-run tests on changes
\\ --watch-debounce <ms> Debounce delay in milliseconds (default: 300)
\\ Type r + Enter to force a full rerun
\\
\\MEMORY PROFILING:
\\ --profile-memory Enable memory profiling for tests
Expand Down
2 changes: 2 additions & 0 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,13 @@ pub fn main(init: std.process.Init.Minimal) !void {

const watch_options = lib.WatchOptions{
.watch_dir = test_dir,
.project_root = ".",
.pattern = cli_parser.options.pattern,
.recursive = !cli_parser.options.no_recursive,
.debounce_ms = cli_parser.options.watch_debounce,
.clear_screen = true,
.verbose = cli_parser.options.verbose,
.interactive_commands = true,
};

var watcher = lib.TestWatcher.init(allocator, watch_options, &keep_running);
Expand Down
Loading
Loading