Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit 82258a0

Browse files
committed
Implement —rerun-failures CLI flag.
1 parent f7770d2 commit 82258a0

File tree

8 files changed

+110
-2
lines changed

8 files changed

+110
-2
lines changed

lib/rspec/core/configuration.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ def exclude_pattern=(value)
224224
# (default: `false`).
225225
add_setting :run_all_when_everything_filtered
226226

227+
# @macro add_setting
228+
# Run only the examples that failed on the last run.
229+
# (default: `false`).
230+
add_setting :rerun_failures
231+
227232
# @macro add_setting
228233
# Color to use to indicate success.
229234
# @param color [Symbol] defaults to `:green` but can be set to one of the
@@ -800,7 +805,14 @@ def files_or_directories_to_run=(*files)
800805
# The spec files RSpec will run.
801806
# @return [Array] specified files about to run
802807
def files_to_run
803-
@files_to_run ||= get_files_to_run(@files_or_directories_to_run)
808+
@files_to_run ||= begin
809+
if rerun_failures?
810+
failures = LastRunPersister.for_current_project.failures_from_last_run
811+
self.files_or_directories_to_run = failures
812+
end
813+
814+
get_files_to_run(@files_or_directories_to_run)
815+
end
804816
end
805817

806818
# Creates a method that delegates to `example` including the submitted

lib/rspec/core/configuration_options.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def order(keys)
8686
# These must be set before `requires` to support checking
8787
# `config.files_to_run` from within `spec_helper.rb` when a
8888
# `-rspec_helper` option is used.
89-
:files_or_directories_to_run, :pattern, :exclude_pattern,
89+
:files_or_directories_to_run, :pattern, :exclude_pattern, :rerun_failures,
9090

9191
# Necessary so that the `--seed` option is applied before requires,
9292
# in case required files do something with the provided seed.

lib/rspec/core/option_parser.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ def parser(options)
156156
157157
FILTERING
158158

159+
parser.on('--rerun-failures', "Run just the examples that failed on the last run.") do
160+
options[:rerun_failures] = true
161+
end
162+
159163
parser.on('-P', '--pattern PATTERN', 'Load files matching pattern (default: "spec/**/*_spec.rb").') do |o|
160164
options[:pattern] = o
161165
end

lib/rspec/core/reporter.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ def finish
161161
def stop
162162
@duration = (RSpec::Core::Time.now - @start).to_f if @start
163163
notify :stop, Notifications::ExamplesNotification.new(self)
164+
record_failures
164165
end
165166

166167
# @private
@@ -181,6 +182,11 @@ def mute_profile_output?
181182
def seed_used?
182183
@configuration.seed && @configuration.seed_used?
183184
end
185+
186+
def record_failures
187+
ids = @failed_examples.map(&:id)
188+
LastRunPersister.for_current_project.persist_failures(ids)
189+
end
184190
end
185191

186192
# @private

spec/integration/filtering_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,33 @@ def run_rerun_command_for_failing_spec
6565
end
6666
end
6767

68+
context "using --rerun-failures" do
69+
it 'reruns the examples that failed on the last run' do
70+
write_file_formatted 'spec/string_spec.rb', """
71+
RSpec.describe 'Strings' do
72+
specify { expect('a').to eq('a') }
73+
specify { expect('a').to eq('b') } # failure
74+
specify { expect('c').to eq('c') }
75+
specify { expect('c').to eq('b') } # failure
76+
end
77+
"""
78+
79+
write_file_formatted 'spec/array_spec.rb', """
80+
RSpec.describe 'Arrays' do
81+
specify { expect([1, 2]).to include(1) }
82+
specify { expect([1, 2]).to include(3) } # failure
83+
specify { expect([1, 2]).to include(2) }
84+
end
85+
"""
86+
87+
run_command ""
88+
expect(last_cmd_stdout).to match(/7 examples, 3 failures/)
89+
90+
run_command "--rerun-failures"
91+
expect(last_cmd_stdout).to match(/3 examples, 3 failures/)
92+
end
93+
end
94+
6895
context "passing a line-number filter" do
6996
it "trumps exclusions, except for :if/:unless (which are absolute exclusions)" do
7097
write_file_formatted 'spec/a_spec.rb', """

spec/rspec/core/configuration_options_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@
9090
opts.configure(config)
9191
end
9292

93+
it "sets `rerun_failures` before `requires` so users can check `files_to_run` in a spec_helper loaded by `--require`" do
94+
opts = config_options_object(*%w[--require spec_helper --rerun-failures])
95+
expect(config).to receive(:force).with(:rerun_failures => true).ordered
96+
expect(config).to receive(:requires=).ordered
97+
opts.configure(config)
98+
end
99+
93100
it "sets default_path before `files_or_directories_to_run` since it relies on it" do
94101
opts = config_options_object(*%w[--default-path spec])
95102
expect(config).to receive(:force).with(:default_path => 'spec').ordered

spec/rspec/core/configuration_spec.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,40 @@ module RSpec::Core
8787
end
8888
end
8989

90+
describe "#rerun_failures=" do
91+
context "when set to true" do
92+
it 'assigns what to run from the previously persisted failures' do
93+
failures = %w[ ./spec_1.rb[1:1] ]
94+
persister = instance_double(LastRunPersister, :failures_from_last_run => failures)
95+
allow(LastRunPersister).to receive(:for_current_project) { persister }
96+
97+
config.rerun_failures = true
98+
99+
expect(config.files_to_run).to contain_exactly("./spec_1.rb")
100+
expect(inclusion_filter).to eq(:ids => { "./spec_1.rb" => ["1:1"] })
101+
end
102+
103+
it 'indicates it has been set' do
104+
expect {
105+
config.rerun_failures = true
106+
}.to change { config.rerun_failures? }.from(a_falsey_value).to(true)
107+
end
108+
end
109+
110+
context "when set to false" do
111+
it 'does nothing' do
112+
expect {
113+
config.rerun_failures = false
114+
}.not_to change { config.files_to_run }
115+
end
116+
117+
it 'indicates it has been set to false' do
118+
config.rerun_failures = false
119+
expect(config.rerun_failures?).to be false
120+
end
121+
end
122+
end
123+
90124
describe "#requires=" do
91125
def absolute_path_to(dir)
92126
File.expand_path("../../../../#{dir}", __FILE__)

spec/rspec/core/reporter_spec.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,24 @@ module RSpec::Core
3333

3434
reporter.finish
3535
end
36+
37+
def example_with_id(id)
38+
new_example.tap do |ex|
39+
allow(ex).to receive_messages(:id => id)
40+
end
41+
end
42+
43+
it 'records the failed examples in order to support the `--rerun-failures` flag' do
44+
persister = instance_spy(LastRunPersister)
45+
allow(LastRunPersister).to receive(:for_current_project) { persister }
46+
47+
reporter.example_failed(example_with_id("id_1"))
48+
reporter.example_failed(example_with_id("id_2"))
49+
50+
reporter.finish
51+
52+
expect(persister).to have_received(:persist_failures).with(%w[ id_1 id_2 ])
53+
end
3654
end
3755

3856
describe 'start' do

0 commit comments

Comments
 (0)