Skip to content

Commit ccd5bac

Browse files
committed
Merge pull request rspec#2105 from rspec/pr-2065-followups
Followups from rspec#2065.
2 parents 9aee075 + fe6e1bc commit ccd5bac

File tree

10 files changed

+64
-66
lines changed

10 files changed

+64
-66
lines changed

Changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Enhancements:
4949
(Yuji Nakayama, #2083)
5050
* Add `max_displayed_failure_line_count` configuration option
5151
(defaults to 10). (Yuji Nakayama, #2083)
52+
* Enhance `fail_fast` option so it can take a number (e.g. `--fail-fast=3`)
53+
to force the run to abort after the specified number of failures.
54+
(Jack Scotti, #2065)
5255

5356
Bug Fixes:
5457

features/configuration/fail_fast.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Feature: fail fast
22

3-
Use the `fail_fast` option to tell RSpec to abort the run on after N failures:
3+
Use the `fail_fast` option to tell RSpec to abort the run after N failures:
44

55
Scenario: `fail_fast` with no failures (runs all examples)
66
Given a file named "spec/spec_helper.rb" with:

lib/rspec/core/configuration.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def only_failures_but_not_configured?
187187

188188
# @macro add_setting
189189
# If specified, indicates the number of failures required before cleaning
190-
# up and exit (default: `false`).
190+
# up and exit (default: `nil`).
191191
add_setting :fail_fast
192192

193193
# @macro add_setting

lib/rspec/core/example_group.rb

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,8 @@ def self.run(reporter=RSpec::Core::NullReporter)
547547
for_filtered_examples(reporter) { |example| example.skip_with_exception(reporter, ex) }
548548
true
549549
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
550-
RSpec.world.wants_to_quit = true if fail_fast?
551550
for_filtered_examples(reporter) { |example| example.fail_with_exception(reporter, ex) }
551+
RSpec.world.wants_to_quit = true if reporter.fail_fast_limit_met?
552552
false
553553
ensure
554554
run_after_context_hooks(new('after(:context) hook')) if should_run_context_hooks
@@ -579,7 +579,7 @@ def self.run_examples(reporter)
579579
instance = new(example.inspect_output)
580580
set_ivars(instance, before_context_ivars)
581581
succeeded = example.run(instance, reporter)
582-
if !succeeded && fail_fast? && reporter.fail_fast_limit_met?
582+
if !succeeded && reporter.fail_fast_limit_met?
583583
RSpec.world.wants_to_quit = true
584584
end
585585
succeeded
@@ -598,11 +598,6 @@ def self.for_filtered_examples(reporter, &block)
598598
false
599599
end
600600

601-
# @private
602-
def self.fail_fast?
603-
RSpec.configuration.fail_fast?
604-
end
605-
606601
# @private
607602
def self.declaration_line_numbers
608603
@declaration_line_numbers ||= [metadata[:line_number]] +

lib/rspec/core/option_parser.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def parser(options)
8080
begin
8181
value = Integer(argument)
8282
rescue ArgumentError
83-
RSpec.warning "Non integer specified as fail count."
83+
RSpec.warning "Expected an integer value for `--fail-fast`, got: #{argument.inspect}", :call_site => nil
8484
end
8585
end
8686
set_fail_fast(options, value)

lib/rspec/core/reporter.rb

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,13 @@ def abort_with(msg, exit_status)
199199

200200
# @private
201201
def fail_fast_limit_met?
202-
failures_required <= @failed_examples.size
203-
end
202+
return false unless (fail_fast = @configuration.fail_fast)
204203

205-
# @private
206-
def failures_required
207-
@configuration.fail_fast == true ? 1 : @configuration.fail_fast
204+
if fail_fast == true
205+
@failed_examples.any?
206+
else
207+
fail_fast <= @failed_examples.size
208+
end
208209
end
209210

210211
private
@@ -216,7 +217,7 @@ def close
216217
def mute_profile_output?
217218
# Don't print out profiled info if there are failures and `--fail-fast` is
218219
# used, it just clutters the output.
219-
!@configuration.profile_examples? || (@configuration.fail_fast? && @failed_examples.size > 0)
220+
!@configuration.profile_examples? || fail_fast_limit_met?
220221
end
221222

222223
def seed_used?

spec/rspec/core/configuration_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ module RSpec::Core
3636
end
3737
end
3838

39+
describe "#fail_fast" do
40+
it "defaults to `nil`" do
41+
expect(RSpec::Core::Configuration.new.fail_fast).to be(nil)
42+
end
43+
end
44+
3945
describe '#deprecation_stream' do
4046
it 'defaults to standard error' do
4147
expect($rspec_core_without_stderr_monkey_patch.deprecation_stream).to eq STDERR

spec/rspec/core/example_group_spec.rb

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,8 +1233,7 @@ def extract_execution_results(group)
12331233
end
12341234

12351235
describe "#run_examples" do
1236-
1237-
let(:reporter) { double("reporter").as_null_object }
1236+
let(:reporter) { RSpec::Core::NullReporter }
12381237

12391238
it "returns true if all examples pass" do
12401239
group = RSpec.describe('group') do
@@ -1342,19 +1341,27 @@ def extract_execution_results(group)
13421341
end
13431342

13441343
describe "#run" do
1344+
context "with `fail_fast` set to `nil`" do
1345+
before { RSpec.configuration.fail_fast = nil }
1346+
let(:group) { RSpec.describe }
1347+
let(:reporter) { Reporter.new(RSpec.configuration) }
13451348

1346-
context "with fail_fast and failures_required == 1" do
1347-
let(:group) do
1348-
group = RSpec.describe
1349-
allow(group).to receive(:fail_fast?) { true }
1350-
group
1351-
end
1352-
let(:config) { Configuration.new }
1353-
let(:reporter) do
1354-
the_reporter = Reporter.new config
1355-
allow(the_reporter).to receive(:failures_required) { 1 }
1356-
the_reporter
1349+
it "does not run abort due to failures" do
1350+
examples_run = []
1351+
group().example('example 1') { examples_run << self; fail }
1352+
group().example('example 2') { examples_run << self; fail }
1353+
group().example('example 3') { examples_run << self; fail }
1354+
1355+
group().run(reporter)
1356+
1357+
expect(examples_run.length).to eq(3)
13571358
end
1359+
end
1360+
1361+
context "with fail_fast enabled" do
1362+
before { RSpec.configuration.fail_fast = true }
1363+
let(:group) { RSpec.describe }
1364+
let(:reporter) { Reporter.new(RSpec.configuration) }
13581365

13591366
it "does not run examples after the failed example" do
13601367
examples_run = []
@@ -1370,24 +1377,15 @@ def extract_execution_results(group)
13701377
it "sets RSpec.world.wants_to_quit flag if encountering an exception in before(:all)" do
13711378
group().before(:all) { raise "error in before all" }
13721379
group().example("equality") { expect(1).to eq(2) }
1373-
expect(group().run).to be_falsey
1380+
expect(group().run(reporter)).to be_falsey
13741381
expect(RSpec.world.wants_to_quit).to be_truthy
13751382
end
13761383
end
13771384

1378-
context "with fail_fast and failures_required = 3" do
1379-
let(:group) do
1380-
group = RSpec.describe
1381-
allow(group).to receive(:fail_fast?) { true }
1382-
group
1383-
end
1384-
let(:config) { Configuration.new }
1385-
1386-
let(:reporter) do
1387-
the_reporter = Reporter.new config
1388-
allow(the_reporter).to receive(:failures_required) { 3 }
1389-
the_reporter
1390-
end
1385+
context "with fail_fast set to 3" do
1386+
before { RSpec.configuration.fail_fast = 3 }
1387+
let(:group) { RSpec.describe }
1388+
let(:reporter) { Reporter.new(RSpec.configuration) }
13911389

13921390
it "does not run examples after 3 failed examples" do
13931391
examples_run = []
@@ -1402,11 +1400,25 @@ def extract_execution_results(group)
14021400
expect(examples_run.length).to eq(4)
14031401
end
14041402

1405-
it "sets RSpec.world.wants_to_quit flag if encountering an exception in before(:all)" do
1403+
it "does not set RSpec.world.wants_to_quit flag if encountering an exception in before(:all) causing less than 3 failures" do
14061404
group().before(:all) { raise "error in before all" }
14071405
group().example("equality") { expect(1).to eq(2) }
1408-
expect(group().run).to be_falsey
1409-
expect(RSpec.world.wants_to_quit).to be_truthy
1406+
group().example("equality") { expect(1).to eq(2) }
1407+
1408+
expect(group().run(reporter)).to be false
1409+
1410+
expect(RSpec.world.wants_to_quit).to be_falsey
1411+
end
1412+
1413+
it "sets RSpec.world.wants_to_quit flag if encountering an exception in before(:all) causing at least 3 failures" do
1414+
group().before(:all) { raise "error in before all" }
1415+
group().example("equality") { expect(1).to eq(1) }
1416+
group().example("equality") { expect(1).to eq(1) }
1417+
group().example("equality") { expect(1).to eq(1) }
1418+
1419+
expect(group().run(reporter)).to be false
1420+
1421+
expect(RSpec.world.wants_to_quit).to be true
14101422
end
14111423
end
14121424

spec/rspec/core/option_parser_spec.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,7 @@ def generate_help_text
343343

344344
describe '--fail-fast' do
345345
it 'warns when a non-integer is specified as fail count' do
346-
expect(::Kernel).to receive(:warn) do |message|
347-
expect(message).to match "Non integer specified as fail count"
348-
end
346+
expect_warning_without_call_site a_string_including("--fail-fast", "three")
349347
Parser.parse(%w[--fail-fast=three])
350348
end
351349
end

spec/rspec/core/reporter_spec.rb

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -279,22 +279,5 @@ module RSpec::Core
279279
reporter.finish
280280
end
281281
end
282-
283-
describe "#failures_required" do
284-
it "returns 1 when RSpec.configuration.fail_fast == true" do
285-
config.fail_fast = true
286-
expect(reporter.failures_required).to eq 1
287-
end
288-
289-
it "returns 1 when RSpec.configuration.fail_fast == 1" do
290-
config.fail_fast = 1
291-
expect(reporter.failures_required).to eq 1
292-
end
293-
294-
it "returns RSpec.configuration.fail_fast when RSpec.configuration.fail_fast > 1" do
295-
config.fail_fast = 3
296-
expect(reporter.failures_required).to eq 3
297-
end
298-
end
299282
end
300283
end

0 commit comments

Comments
 (0)