fix(runner): fail the run when a test is aborted by a pipeline error#257
Conversation
1d5544c to
75cfc85
Compare
|
Thanks for spotting this and pushing a fix! I pushed a revised approach to this branch — sharing the reasoning here. We agree on the goal: an aborted test (a critical interceptor failure — unknown verdict) must fail the run and exit with code Why not add if ($result->status->isFailure()) { /* retry */ }An aborted test must not be retried — retrying won't fix a broken pipeline, and the verdict is unknown. Adding
What this branch does instead — escalate at the aggregation point, leaving // CaseRunner::run()
($result->status->isFailure() || $result->status === Status::Aborted)
and $status = Status::Failed;An aborted test now fails its case, which propagates case → suite → run → exit code through the existing chain. Retry/repeat semantics stay correct (an abort is still not retried). Extras included:
Verified: the new self-test (5/5) plus the retry, repeat and output suites (275/275) are green; retry is not broken. Note: the PR title/description still mention |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
An interceptor that throws (before or after $next) makes TestRunner mark the
test Status::Aborted. The terminal/JUnit/TeamCity reporters already render an
abort as a failure, yet the process exit code stayed 0: Aborted is not a
Status::isFailure(), so CaseRunner/SuiteRunner never escalated. CaseRunner now
treats an aborted test as a case failure, so the suite/run status and the exit
code agree with what the reporters print.
Kept out of Status::isFailure() on purpose — that predicate also drives retry
(RetryPolicyRunInterceptor), which must not retry an aborted test.
Also give Aborted its own red "A" glyph in the terminal (verbose + dots) so it
reads distinctly from a genuine Error ("E").
Adds a self-test (PipelineFailureStatusTest) plus a small stub apparatus: a
FailPipeline attribute that self-binds a throwing interceptor via
FallbackInterceptor (no plugin needed), covering test-level and case-level
throws before/after $next().
Assisted-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
75cfc85 to
9e84713
Compare
Enables the sandbox suite in testo.php (skipped under TESTO_CI) and adds a sandbox file exercising the FailPipeline attribute at every stage — test-level and case-level throws before/after $next() — for eyeballing the terminal report. Assisted-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem
When tests are
Aborted(an interceptor throws during the pipeline — e.g. a DI container cannot resolve a dependency), the terminal renderer correctly prints FAILED and counts aborted tests as failures in the summary. However, the process exits with code 0.Root cause:
Status::isFailure()did not includeStatus::Aborted, so the failure flag was never propagated up the aggregation chain:The renderer (
TerminalLogger) handles this correctly already — it explicitly includesAbortedwhen computing the failure count for the final banner. The exit code logic does not.Fix
Add
self::Abortedto theisFailure()match inStatus.php. This single change cascades through the entire aggregation chain and produces exit code 1 whenever any test is aborted.Behaviour after fix