--tunnel-client <id> (a tunnel started separately with testsprite tunnel start), the run behaves like an ordinary one. If that process stops or its credential is revoked while the original test run waits, the run is cancelled by default and the command exits 10; --no-cancel-on-interrupt skips the cancellation. A resumed test wait does not monitor the borrowed tunnel and has no such flag.
Ctrl-C detaches
Ctrl-C duringtest run --wait, test wait, test rerun --wait, or test flaky stops the watching, not the run. For an ordinary run the CLI says so:
--timeout expiry, it prints a partial { "runId": "...", "status": "running" } to stdout so scripts keep the runId (a fallback, not a fresh server observation). The exit code is 130 for SIGINT, 143 for SIGTERM, 129 for SIGHUP. A second Ctrl-C exits immediately without cleanup.
With --output json, stderr carries an envelope instead (error.code INTERRUPTED, with nextAction and details.signal).
Interrupting a batch (test run --all --wait, multi-id test wait / test rerun) prints a partial listing of dispatched runs. A local batch also lists not-run tests that never started, and Ctrl-C cancels unfinished runs on its own tunnel by default.
A self-minted --local run cancels by default
cancelled, with no test wait hint, since re-attaching cannot revive the closed tunnel. If cancellation failed or was skipped, use testsprite test cancel <run-id>; if the run already finished, its verdict stands. Start a new run with testsprite test run <test-id> --local <port>. Automatic cancellation uses the same endpoint and refund rules as test cancel.
--no-cancel-on-interrupt
No cancel is sent and the partial status is running. Check the verdict with testsprite test result <test-id> or testsprite test wait <run-id> (waiting does not reopen the tunnel), or stop it with testsprite test cancel <run-id>.
Stopping a run
- The test is immediately re-runnable, with no “run already in flight” conflict.
- The last verdict is untouched. A test that was passed stays passed.
- Refunds (frontend). If cancellation wins before any terminal verdict, the backend attempts to refund the recorded charge. The response’s
refund.statusisrefunded,not_charged, orfailed(the refund failed, cancellation still succeeded). Check it; cancellation success alone does not confirm a refund. A run whose verdict already landed is never refunded (exit6). Backend tests keep their no-refund behavior. - Background work is discarded. The engine may finish, but its result never overwrites cancelled.
Idempotent by design
Cancelling the same run twice exits0 with [advisory] run run_5c1d9a2b was already cancelled, so it is safe in retries and cleanup traps. Business refusals:
Cancelling several runs
test cancel accepts several IDs and prints a summary:
notFound gives 4, else any transport/auth errors gives 1, else any conflicts gives 6, else 0.
CI cleanup pattern
Where to Go Next
Running Tests
Triggering runs, waiting for verdicts, and resuming
Exit Codes
The full exit-code and signal contract
Reading Results
Run history, steps, and failure bundles
CI/CD Integration
Wire the CLI into GitHub Actions or any pipeline