diff --git a/lib/rspec/core/configuration.rb b/lib/rspec/core/configuration.rb index cef3e813a..f8430e79f 100644 --- a/lib/rspec/core/configuration.rb +++ b/lib/rspec/core/configuration.rb @@ -477,6 +477,12 @@ def pending_failure_output=(mode) @pending_failure_output = mode end + # @macro force_line_number_for_spec_rerun + # Display the line number (`my_spec.rb:10`), as opposed to the example id (`my_spec.rb[1:1:1]`) + # for shared or nested examples (defaults to `false`). + # return [Boolean] + add_setting :force_line_number_for_spec_rerun + # Determines which bisect runner implementation gets used to run subsets # of the suite during a bisection. Your choices are: # @@ -580,6 +586,7 @@ def initialize @world = World::Null @shared_context_metadata_behavior = :trigger_inclusion @pending_failure_output = :full + @force_line_number_for_spec_rerun = false define_built_in_hooks end diff --git a/lib/rspec/core/notifications.rb b/lib/rspec/core/notifications.rb index 72768ef4e..0342d4bf9 100644 --- a/lib/rspec/core/notifications.rb +++ b/lib/rspec/core/notifications.rb @@ -401,7 +401,9 @@ def fully_formatted(colorizer=::RSpec::Core::Formatters::ConsoleCodes) def rerun_argument_for(example) location = example.location_rerun_argument + return location unless duplicate_rerun_locations.include?(location) + return location if RSpec.configuration.force_line_number_for_spec_rerun conditionally_quote(example.id) end diff --git a/spec/integration/location_rerun_spec.rb b/spec/integration/location_rerun_spec.rb new file mode 100644 index 000000000..aebd19765 --- /dev/null +++ b/spec/integration/location_rerun_spec.rb @@ -0,0 +1,133 @@ +require 'support/aruba_support' + +RSpec.describe 'Failed spec rerun location' do + include RSpecHelpers + include_context "aruba support" + + before do + setup_aruba + + # Setup some shared examples and call them in a separate file + # from where they are called to demonstrate how nested example ids work + write_file_formatted "some_examples.rb", " + RSpec.shared_examples_for 'a failing spec' do + it 'fails' do + expect(1).to eq(2) + end + + context 'when you reverse it' do + it 'still fails' do + expect(2).to eq(1) + end + end + end + " + + file = cd('.') { "#{Dir.pwd}/some_examples.rb" } + load file + + write_file_formatted "non_local_shared_examples_spec.rb", " + RSpec.describe do + context 'the first context' do + it_behaves_like 'a failing spec' + end + + context 'the second context' do + it_behaves_like 'a failing spec' + end + end + " + + # Setup some shared examples in the same file as where they are called + write_file_formatted "local_shared_examples_spec.rb", " + RSpec.describe do + shared_examples_for 'a failing spec' do + it 'fails' do + expect(1).to eq(2) + end + + context 'when you reverse it' do + it 'still fails' do + expect(2).to eq(1) + end + end + end + + context 'the first context' do + it_behaves_like 'a failing spec' + end + + context 'the second context' do + it_behaves_like 'a failing spec' + end + end + " + end + + context "when config.force_line_number_for_spec_rerun is set to false" do + it 'prints the example id of the failed assertion' do + run_command("#{Dir.pwd}/tmp/aruba/local_shared_examples_spec.rb") + + expect(last_cmd_stdout).to include unindent(<<-EOS) + Failed examples: + + rspec './local_shared_examples_spec.rb[1:1:1:1]' # the first context behaves like a failing spec fails + rspec './local_shared_examples_spec.rb[1:1:1:2:1]' # the first context behaves like a failing spec when you reverse it still fails + rspec './local_shared_examples_spec.rb[1:2:1:1]' # the second context behaves like a failing spec fails + rspec './local_shared_examples_spec.rb[1:2:1:2:1]' # the second context behaves like a failing spec when you reverse it still fails + EOS + end + + context "and the shared examples are defined in a separate file" do + it 'prints the example id of the failed assertion' do + run_command("#{Dir.pwd}/tmp/aruba/non_local_shared_examples_spec.rb") + + expect(last_cmd_stdout).to include unindent(<<-EOS) + Failed examples: + + rspec './non_local_shared_examples_spec.rb[1:1:1:1]' # the first context behaves like a failing spec fails + rspec './non_local_shared_examples_spec.rb[1:1:1:2:1]' # the first context behaves like a failing spec when you reverse it still fails + rspec './non_local_shared_examples_spec.rb[1:2:1:1]' # the second context behaves like a failing spec fails + rspec './non_local_shared_examples_spec.rb[1:2:1:2:1]' # the second context behaves like a failing spec when you reverse it still fails + EOS + end + end + end + + context "when config.force_line_number_for_spec_rerun is set to true" do + before do + allow(RSpec.configuration).to receive(:force_line_number_for_spec_rerun).and_return(true) + end + + context "when the shared examples are defined in the same file as the spec" do + + it 'prints the line number where the assertion failed in the local file' do + run_command("#{Dir.pwd}/tmp/aruba/local_shared_examples_spec.rb") + + expect(last_cmd_stdout).to include unindent(<<-EOS) + Failed examples: + + rspec ./local_shared_examples_spec.rb:3 # the first context behaves like a failing spec fails + rspec ./local_shared_examples_spec.rb:8 # the first context behaves like a failing spec when you reverse it still fails + rspec ./local_shared_examples_spec.rb:3 # the second context behaves like a failing spec fails + rspec ./local_shared_examples_spec.rb:8 # the second context behaves like a failing spec when you reverse it still fails + EOS + end + end + + context "and the shared examples are defined in a separate file" do + it 'prints the line number where the `it_behaves_like` was called in the local file' do + run_command("#{Dir.pwd}/tmp/aruba/non_local_shared_examples_spec.rb") + + expect(last_cmd_stdout).to include unindent(<<-EOS) + Failed examples: + + rspec ./non_local_shared_examples_spec.rb:3 # the first context behaves like a failing spec fails + rspec ./non_local_shared_examples_spec.rb:3 # the first context behaves like a failing spec when you reverse it still fails + rspec ./non_local_shared_examples_spec.rb:7 # the second context behaves like a failing spec fails + rspec ./non_local_shared_examples_spec.rb:7 # the second context behaves like a failing spec when you reverse it still fails + EOS + end + end + end +end diff --git a/spec/rspec/core/configuration_spec.rb b/spec/rspec/core/configuration_spec.rb index 165990f5a..19512f166 100644 --- a/spec/rspec/core/configuration_spec.rb +++ b/spec/rspec/core/configuration_spec.rb @@ -1,6 +1,5 @@ require 'tmpdir' require 'rspec/support/spec/in_sub_process' - module RSpec::Core RSpec.describe Configuration do include RSpec::Support::InSubProcess @@ -2979,6 +2978,17 @@ def emulate_not_configured_expectation_framework end end + describe "#force_line_number_for_spec_rerun" do + it "defaults to false" do + expect(config.force_line_number_for_spec_rerun).to eq false + end + + it "is configurable" do + config.force_line_number_for_spec_rerun = true + expect(config.force_line_number_for_spec_rerun).to eq true + end + end + # assigns files_or_directories_to_run and triggers post-processing # via `files_to_run`. def assign_files_or_directories_to_run(*value)