Skip to content

Commit 9fd6566

Browse files
committed
Return error when rspec exits with non-zero but no failure
1 parent 51ba7fc commit 9fd6566

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

internal/runner/rspec.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,16 @@ func (r Rspec) Run(result *RunResult, testCases []plan.TestCase, retry bool) err
124124
result.error = fmt.Errorf("RSpec failed with errors outside of examples")
125125
}
126126

127+
if exitError := new(exec.ExitError); errors.As(err, &exitError) {
128+
if report.Summary.FailureCount == 0 && report.Summary.ErrorsOutsideOfExamplesCount == 0 {
129+
// If Rspec exits with a non-zero exit code, but the report is parsed successfully and contains no failures or errors,
130+
// it may mean that the process was terminated by an explicit call to `exit` in the code or specs.
131+
// Rspec does not report this as a test failure or error, but instead exits with the same exit code that terminated the process.
132+
// In this case, we should mark the result as an error.
133+
result.error = fmt.Errorf("RSpec exited with code %d, but no failed tests were reported. This may be caused by an explicit call to `exit` in the code or specs", exitError.ExitCode())
134+
}
135+
}
136+
127137
return nil
128138
}
129139

internal/runner/rspec_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,36 @@ func TestRspecRun_TestSkipped(t *testing.T) {
208208
}
209209
}
210210

211+
func TestRspecRun_TestExit(t *testing.T) {
212+
rspec := NewRspec(RunnerConfig{
213+
TestCommand: "rspec --format json --out {{resultPath}} --format progress",
214+
ResultPath: "tmp/rspec.json",
215+
})
216+
217+
t.Cleanup(func() {
218+
os.Remove(rspec.ResultPath)
219+
})
220+
221+
testCases := []plan.TestCase{
222+
{Path: "./testdata/rspec/spec/exit_spec.rb"},
223+
}
224+
result := NewRunResult([]plan.TestCase{})
225+
err := rspec.Run(result, testCases, false)
226+
227+
if err != nil {
228+
t.Errorf("Rspec.Run(%q) error = %v", testCases, err)
229+
}
230+
231+
if result.Status() != RunStatusError {
232+
t.Errorf("Rspec.Run(%q) RunResult.Status = %v, want %v", testCases, result.Status(), RunStatusError)
233+
}
234+
235+
wantError := "RSpec exited with code 7, but no failed tests were reported. This may be caused by an explicit call to `exit` in the code or specs."
236+
if diff := cmp.Diff(result.error.Error(), wantError); diff != "" {
237+
t.Errorf("Rspec.Run(%q) RunResult.error diff (-got +want):\n%s", testCases, diff)
238+
}
239+
}
240+
211241
func TestRspecRun_ErrorOutsideOfExamples(t *testing.T) {
212242
rspec := NewRspec(RunnerConfig{
213243
TestCommand: "rspec --format json --out {{resultPath}} --format documentation",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
RSpec.describe("Exit") do
2+
it("exits") do
3+
exit 7
4+
end
5+
end

0 commit comments

Comments
 (0)