watch

Watch mode

Watch mode keeps behave running between runs. When a file under lib/ or specs/ changes, Behave figures out which spec files are affected and re-runs only those. The rest of the time you read pass/fail output, type a single-letter command, and keep editing.

Usage

$ behave --watch

The default watched roots are ./lib and ./specs when each one exists. To watch additional directories or a custom layout, pass --watch-path PATH (repeatable):

$ behave --watch --watch-path app/ --watch-path test/

When --watch-path is given at least once, the default lib//specs/ roots are replaced by your list. Pass them explicitly if you still want them.

--watch is mutually exclusive with --bisect, --bisect-data, --coverage, --doc, and --parallel. Combining any of these exits with status 2.

Initial run

When you start --watch, Behave does a baseline run of every spec file it can see. The exit code of that run does not terminate watch mode: failures are reported and the loop continues. After the initial run, the watch prompt appears:

[behave watch] press r rerun selection, a rerun all, f failed only, q quit

Smart test selection

When a file changes, Behave decides which specs to re-run:

Change kindWhat runs
specs/foo-spec.raku (matches *-spec.raku)That spec file only.
lib/Foo.rakumod or lib/A/B.rakumodEvery spec whose source contains the module's basename (Foo) or its joined module path (A::B).
A lib/ change that no spec referencesFalls back to every spec file (so you never miss a real failure).
A removed fileIgnored.
Multiple files in one tickUnion of all of the above, deduplicated.

The mapping is intentionally a substring search rather than a parse. It is fast, has no false negatives in the common case, and makes the fallback explicit: if nothing matches, everything runs.

Interactive commands

While the loop is running, type one of the following on its own line and press Enter:

CommandEffect
rRe-run the last selection (the most recent set of specs, whether triggered by a change or by a).
aRe-run every spec.
fRe-run only previously-failed examples (uses .behave-failures, see Retry and Only-Failures).
h / ?Re-print the prompt.
qExit watch mode. The Behave process exits with status 0.
(Enter)Equivalent to r.

Unknown input prints a warning and re-prints the prompt.

Forwarding other flags

--watch forwards a subset of CLI flags to each spawned subprocess so your filters and formatters stay in effect across re-runs:

  • --format NAME (unless the default progress)

  • --order ORDER (unless random)

  • --seed N (when --order=random and a seed was set)

  • --show-seed (when set)

  • --verbose

  • --retry N (when N > 0)

  • --tag NAME (repeatable)

  • --exclude-tag NAME (repeatable)

  • --example PATTERN (repeatable)

Each subprocess inherits a BEHAVE_DISABLE_CONFIG=1 environment so it does not re-read ~/.behave or ./.behave and conflict with the parent's resolved configuration.

Implementation notes

  • File detection is mtime + size polling at 0.25s intervals. There is no inotify / kqueue / FSEvents dependency. For typical projects (hundreds to a few thousand files) the polling overhead is negligible.

  • Watched files are filtered by basename to .rakumod, .raku, .rakutest, and .pm6. Hidden directories (.git, .precomp) are skipped during the walk.

  • Each re-run is a subprocess (raku -Ilib bin/behave …) so user-level class / role / enum declarations from one run cannot collide with the next. This is the same isolation pattern used by --bisect, --coverage, and --parallel.

  • The watch loop itself is a single thread. The interactive reader is a start { } block that pushes lines into a Channel. The main loop drains it non-blocking with Channel.poll.

Limitations

  • New file detection requires a poll tick after the file lands on disk. Saving and immediately exiting before the next 250 ms tick may miss the event. In practice this is invisible.

  • File renames register as one removed plus one added. Smart selection treats only the added half.

  • Watch mode does not surface profile / memory / benchmark summaries across runs: each subprocess emits its own. Aggregation across runs is out of scope for v1.

  • --coverage is incompatible: each subprocess would need its own MoarVM coverage log path and merge step.

  • Smart selection is a substring search. If a spec references a module only by a name that does not appear in the file (e.g. only through dynamic dispatch), Behave will not pick it up. Use --watch-path and the a/r commands to cover that case.

BDD::Behave v0.9.4

Behavior driven development framework

Authors

  • Greg Donald

License

Artistic-2.0

Dependencies

Provides

  • BDD::Behave
  • BDD::Behave::Benchmark
  • BDD::Behave::Benchmark::Baseline
  • BDD::Behave::Benchmark::Format
  • BDD::Behave::Bisect
  • BDD::Behave::Colors
  • BDD::Behave::Configuration
  • BDD::Behave::Coverage
  • BDD::Behave::DSL
  • BDD::Behave::Diff
  • BDD::Behave::DocExtractor
  • BDD::Behave::DryRun
  • BDD::Behave::Expectation
  • BDD::Behave::Failure
  • BDD::Behave::FailureStore
  • BDD::Behave::Failures
  • BDD::Behave::Files
  • BDD::Behave::Formatter
  • BDD::Behave::Formatter::Documentation
  • BDD::Behave::Formatter::HTML
  • BDD::Behave::Formatter::JSON
  • BDD::Behave::Formatter::JUnit
  • BDD::Behave::Formatter::JsonEvents
  • BDD::Behave::Formatter::Progress
  • BDD::Behave::Formatter::Registry
  • BDD::Behave::Formatter::TAP
  • BDD::Behave::Formatter::Tree
  • BDD::Behave::LetRuntime
  • BDD::Behave::Matcher
  • BDD::Behave::Matcher::Async
  • BDD::Behave::Matcher::Boolean
  • BDD::Behave::Matcher::Change
  • BDD::Behave::Matcher::Collection
  • BDD::Behave::Matcher::Core
  • BDD::Behave::Matcher::Custom
  • BDD::Behave::Matcher::Exception
  • BDD::Behave::Matcher::Numeric
  • BDD::Behave::Matcher::String
  • BDD::Behave::Matcher::Type
  • BDD::Behave::Mock::Allow
  • BDD::Behave::Mock::ArgMatcher
  • BDD::Behave::Mock::Double
  • BDD::Behave::Mock::HaveReceived
  • BDD::Behave::Mock::Spy
  • BDD::Behave::Mock::Stub
  • BDD::Behave::Parallel
  • BDD::Behave::Parallel::Distribution
  • BDD::Behave::Parallel::EventStream
  • BDD::Behave::Parallel::Manifest
  • BDD::Behave::Parallel::Queue
  • BDD::Behave::Parallel::WorkerPool
  • BDD::Behave::Runner
  • BDD::Behave::SharedContexts
  • BDD::Behave::SharedExamples
  • BDD::Behave::Slang
  • BDD::Behave::SpecLoader
  • BDD::Behave::SpecRegistry
  • BDD::Behave::SpecTree
  • BDD::Behave::SpecTree::Core
  • BDD::Behave::SpecTree::Example
  • BDD::Behave::SpecTree::ExampleGroup
  • BDD::Behave::SpecTree::Suite
  • BDD::Behave::Time
  • BDD::Behave::TypeName
  • BDD::Behave::Version
  • BDD::Behave::Watch
  • BDD::Behave::Watch::Session
  • BDD::Behave::Watch::SmartSelector
  • BDD::Behave::Watch::UI
  • BDD::Behave::Watch::Watcher
  • BDD::Behave::Worker

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.