--- name: testbox-runners description: "Use this skill when running TestBox tests: CommandBox CLI (testbox run), BoxLang CLI (./testbox/run), HTML web runner, programmatic TestBox instantiation (run/runRaw/runRemote), configuring test directories or bundles, using the streaming runner (--stream flag / StreamingRunner), watcher mode, all CLI flags (--show-failed-only, --dry-run, --slow-threshold-ms, --stacktrace, --max-failures), or setting up box.json testbox configuration." applyTo: "**/tests/**/*.{bx,bxm,cfc,cfm,cfml}" --- # TestBox Runners — Comprehensive Reference ## When to Use This Skill - Running tests from the command line (CommandBox or BoxLang CLI) - Configuring `testbox` in `box.json` - Starting a file-watcher to auto-run tests on change - Using `--stream` / `StreamingRunner` for SSE-based real-time output - Invoking TestBox programmatically from CFML/BoxLang code - Choosing the right runner for a use case (CLI, web, CI, programmatic) --- ## Runner Overview | Runner | Use Case | |---|---| | CommandBox CLI | Standard development workflow; wraps `testbox run` | | BoxLang CLI | BoxLang projects; binary at `./testbox/run` | | HTML Web Runner | Browser-based interactive test runner | | Programmatic API | Embedding tests in application code or custom scripts | | StreamingRunner | Real-time SSE-based output (TestBox 7+) | --- ## CommandBox CLI Runner ### Basic Usage ```bash # Run all tests configured in box.json testbox run # Override directory at runtime testbox run runner="http://localhost:8080/tests/runner.cfm" ``` ### `box.json` Configuration ```json { "testbox": { "runner": "http://localhost:8080/tests/runner.cfm", "verbose": false, "labels": "", "excludes": "", "reporter": "min", "recurse": true, "bundles": "", "directory": { "mapping": "tests.specs", "recurse": true, "filter": "" }, "options": {} } } ``` ### Key CLI Flags ```bash # Streaming real-time output (SSE) testbox run --streaming # Verbose output testbox run verbose=true # Specific reporter testbox run reporter=json # Run with labels testbox run labels=integration # Limit concurrent specs (parallel) testbox run options.maxParallel=4 ``` ### File Watcher Start a persistent process that re-runs tests on file changes: ```bash testbox watch # Watch specific directory testbox watch directory=models # With streaming output testbox watch --streaming ``` Watch is configured in `box.json`: ```json { "testbox": { "runner": "http://localhost:8080/tests/runner.cfm", "watchDelay": 500, "watchPaths": "**.cfc,templates/**" } } ``` --- ## BoxLang CLI Runner For BoxLang projects, TestBox ships a native binary runner at `./testbox/run`. ### Installation TestBox CLI runner is automatically installed when TestBox is a dependency: ```bash # Install testbox (adds ./testbox/run) install testbox ``` ### All Flags ```bash # Run all specs under tests/ ./testbox/run # Run specific directory ./testbox/run --directory=tests/unit # Run specific bundles (comma-separated) ./testbox/run --bundles=tests.specs.MySpec,tests.specs.OtherSpec # Streaming / real-time output ./testbox/run --stream # Dry run — discover specs without executing ./testbox/run --dry-run # Show only failed specs ./testbox/run --show-failed-only # Show passed specs explicitly ./testbox/run --show-passed # Show skipped specs explicitly ./testbox/run --show-skipped # Show full stack traces ./testbox/run --stacktrace # Set maximum failures before stopping ./testbox/run --max-failures=10 # Flag specs slower than N ms ./testbox/run --slow-threshold-ms=100 # Show top N slowest specs ./testbox/run --top-slowest=5 # Set reporter (min, json, junit, etc.) ./testbox/run --reporter=min # Combine options ./testbox/run --directory=tests/unit --show-failed-only --slow-threshold-ms=50 --top-slowest=5 ``` ### Exit Codes | Code | Meaning | |---|---| | `0` | All tests passed | | `1` | One or more failures or errors | Use exit codes in CI/CD pipelines to gate deployments. --- ## StreamingRunner (TestBox 7+) The StreamingRunner emits specs in real time using SSE (Server-Sent Events), allowing the terminal or browser to show results as they complete instead of waiting for the full suite. ### Via CommandBox ```bash testbox run --streaming ``` ### Via BoxLang CLI ```bash ./testbox/run --stream ``` ### Programmatic Setup ```boxlang var runner = new testbox.system.runners.StreamingRunner() runner.run( directory: { mapping: "tests.specs", recurse: true }, reporter: "min", labels: [] ) ``` ### Web Endpoint (SSE) The web-based streaming endpoint sends `text/event-stream`: ``` GET /testbox/runners/streamingrunner.bxm?reporter=min&directory=tests.specs ``` Browser-side: ```javascript const es = new EventSource( "/testbox/stream?reporter=min" ) es.onmessage = ( e ) => console.log( JSON.parse( e.data ) ) ``` --- ## HTML Web Runner The HTML runner is the classic browser-based test interface. ### Quick Setup ``` http://localhost:8080/tests/runner.cfm ``` Create `tests/runner.cfm` (or `tests/runner.cfm`): ```cfm // Defaults: directory = /tests/specs new testbox.system.TestBox( directory: { mapping: "tests.specs", recurse: true } ).run() ``` ### With Options ```cfm new testbox.system.TestBox( directory: { mapping: "tests.specs", recurse: true }, reporter: "simple", labels: url.keyExists( "labels" ) ? url.labels : [], excludes: [], options: {} ).run() ``` --- ## Programmatic Runner API ### TestBox Construction ```boxlang // By directory var tb = new testbox.system.TestBox( directory: { mapping: "tests.specs", // dot-notation mapping recurse: true, filter: "" // optional glob filter } ) // By specific bundles var tb = new testbox.system.TestBox( bundles: [ "tests.specs.unit.UserServiceSpec", "tests.specs.integration.APISpec" ] ) // With reporter and labels var tb = new testbox.system.TestBox( directory: { mapping: "tests.specs", recurse: true }, reporter: "json", labels: [ "unit", "fast" ], excludes: [ "slow" ] ) ``` ### Running ```boxlang // Run and render output (returns and writes results to browser/stdout) tb.run() // Run and return raw result struct var results = tb.runRaw() // results.totalDuration, results.totalSpecs, results.totalPass, // results.totalFail, results.totalError, results.totalSkipped // Run via HTTP and return result string (for cross-server testing) var output = tb.runRemote( testBundles: "tests.specs.MySpec", reporter: "json", options: {} ) writeOutput( output ) ``` ### Inspecting Raw Results ```boxlang var results = new testbox.system.TestBox( directory: { mapping: "tests.specs", recurse: true } ).runRaw() if ( results.totalFail > 0 || results.totalError > 0 ) { // CI: exit with failure systemOutput( "TESTS FAILED: #results.totalFail# failures, #results.totalError# errors" ) abort } ``` --- ## Auto-Load via `Application.bx` In BoxLang projects, wire TestBox into the app lifecycle so you can hit `/tests/` without a dedicated runner file: ```boxlang // Application.bx class { variables.this.name = "MyApp" variables.this.mappings[ "/testbox" ] = expandPath( "/testbox" ) variables.this.mappings[ "/tests" ] = expandPath( "/tests" ) } ``` --- ## Integration Testing with `bx-web-support` Install the `bx-web-support` BoxLang module to run web requests from the CLI runner: ```bash install bx-web-support ./testbox/run --directory=tests/integration ``` Integration tests can then make HTTP calls directly without a running web server. --- ## CI/CD Integration ```yaml # GitHub Actions example - name: Run TestBox Tests run: | ./testbox/run --directory=tests --reporter=junit --show-failed-only # Non-zero exit on failure automatically fails the step ``` ```bash # Jenkins / generic shell ./testbox/run --directory=tests --reporter=junit if [ $? -ne 0 ]; then echo "Tests failed" exit 1 fi ``` --- ## Quick Reference | Task | Command | |---|---| | Run all tests | `./testbox/run` or `testbox run` | | Stream output | `./testbox/run --stream` | | Only failures | `./testbox/run --show-failed-only` | | Dry run | `./testbox/run --dry-run` | | Stack traces | `./testbox/run --stacktrace` | | Slow spec report | `./testbox/run --slow-threshold-ms=200 --top-slowest=10` | | Max failures | `./testbox/run --max-failures=5` | | Specific directory | `./testbox/run --directory=tests/unit` | | Specific bundles | `./testbox/run --bundles=tests.specs.MySpec` | | JUnit for CI | `./testbox/run --reporter=junit` | | Watch mode | `testbox watch` |