Skip to content

Commit

Permalink
Print a usable re-run command for specs defined in external files.
Browse files Browse the repository at this point in the history
Fixes #793.
  • Loading branch information
myronmarston committed Jan 3, 2015
1 parent 2470f99 commit cc865dc
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 4 deletions.
3 changes: 3 additions & 0 deletions Changelog.md
Expand Up @@ -51,6 +51,9 @@ Bug Fixes:
implementation rather than Minitest's. (Jonathan Rochkind, #1822)
* Fix `NameError` caused when duplicate example group aliases are defined and
the DSL is not globally exposed. (Aaron Kromer, #1825)
* When a shared example defined in an external file fails, use the host
example group (from a loaded spec file) for the re-run command to
ensure the command will actually work. (Myron Marston, #1835)

### 3.1.8 Development

Expand Down
11 changes: 11 additions & 0 deletions lib/rspec/core/example.rb
Expand Up @@ -92,6 +92,17 @@ def inspect_output
inspect_output
end

def rerun_command
# TODO: move this into `RSpec.configuration` and memoize it there.
loaded_spec_files = RSpec.configuration.files_to_run.inject(Set.new) do |files, f|
files << File.expand_path(f)
end

Metadata.ascend(metadata) do |meta|
return meta[:location] if loaded_spec_files.include?(File.expand_path meta[:file_path])
end
end

# @attr_reader
#
# Returns the first exception raised in the context of running this
Expand Down
13 changes: 13 additions & 0 deletions lib/rspec/core/metadata.rb
Expand Up @@ -50,6 +50,19 @@ def self.relative_path(line)
nil
end

# @private
# Iteratively walks up from the given example metadata through all
# example group ancestors, yielding each metadata hash along the way.
def self.ascend(example_metadata)
yield example_metadata
group_metadata = example_metadata.fetch(:example_group)

loop do
yield group_metadata
break unless (group_metadata = group_metadata[:parent_example_group])
end
end

# @private
# Used internally to build a hash from an args array.
# Symbols are converted into hash keys with a value of `true`.
Expand Down
4 changes: 2 additions & 2 deletions lib/rspec/core/notifications.rb
Expand Up @@ -404,8 +404,8 @@ def colorized_totals_line(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
def colorized_rerun_commands(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
"\nFailed examples:\n\n" +
failed_examples.map do |example|
colorizer.wrap("rspec #{example.location}", RSpec.configuration.failure_color) + " " +
colorizer.wrap("# #{example.full_description}", RSpec.configuration.detail_color)
colorizer.wrap("rspec #{example.rerun_command}", RSpec.configuration.failure_color) + " " +
colorizer.wrap("# #{example.full_description}", RSpec.configuration.detail_color)
end.join("\n")
end

Expand Down
39 changes: 39 additions & 0 deletions spec/integration/shared_example_rerun_commands_spec.rb
@@ -0,0 +1,39 @@
require 'support/aruba_support'

RSpec.describe 'Shared Example Rerun Commands' do
include_context "aruba support"
before { clean_current_dir }

it 'prints a rerun command for shared examples in external files that works to rerun' do
write_file "spec/support/shared_examples.rb", """
RSpec.shared_examples 'a failing example' do
example { expect(1).to eq(2) }
end
"""

write_file "spec/host_group_spec.rb", """
load File.expand_path('../support/shared_examples.rb', __FILE__)
RSpec.describe 'A group with shared examples' do
include_examples 'a failing example'
end
RSpec.describe 'A group with a passing example' do
example { expect(1).to eq(1) }
end
"""

run_command ""
expect(last_cmd_stdout).to include("2 examples, 1 failure")
run_rerun_command_for_failing_spec
expect(last_cmd_stdout).to include("1 example, 1 failure")
# There was originally a bug when doing it again...
run_rerun_command_for_failing_spec
expect(last_cmd_stdout).to include("1 example, 1 failure")
end

def run_rerun_command_for_failing_spec
command = last_cmd_stdout[/Failed examples:\s+rspec (\S+) #/, 1]
run_command command
end
end
23 changes: 22 additions & 1 deletion spec/rspec/core/formatters/base_text_formatter_spec.rb
Expand Up @@ -31,14 +31,35 @@
end

it "includes command to re-run each failed example" do
allow(RSpec.configuration).to receive(:files_to_run) { [__FILE__] }

example_group = RSpec.describe("example group") do
it("fails") { fail }
end
line = __LINE__ - 2

expect(output_from_running example_group).to include("rspec #{RSpec::Core::Metadata::relative_path("#{__FILE__}:#{line}")} # example group fails")
end

context "for an example defined in an file required by the user rather than loaded by rspec" do
it "looks through ancestor metadata to find a workable re-run command" do
allow(RSpec.configuration).to receive(:files_to_run) { [__FILE__] }

line = __LINE__ + 1
example_group = RSpec.describe("example group") do
# Using eval in order to make it think this got defined in an external file.
instance_eval "it('fails') { fail }", "some/external/file.rb", 1
end

expect(output_from_running example_group).to include("rspec #{RSpec::Core::Metadata::relative_path("#{__FILE__}:#{line}")} # example group fails")
end
end

def output_from_running(example_group)
example_group.run(reporter)
examples = example_group.examples
send_notification :dump_summary, summary_notification(1, examples, examples, [], 0)
expect(output.string).to include("rspec #{RSpec::Core::Metadata::relative_path("#{__FILE__}:#{line}")} # example group fails")
output.string
end
end

Expand Down
12 changes: 11 additions & 1 deletion spec/support/aruba_support.rb
Expand Up @@ -10,12 +10,22 @@ module ArubaLoader
let(:stderr) { StringIO.new }
let(:stdout) { StringIO.new }

attr_reader :last_cmd_stdout, :last_cmd_stderr

def run_command(cmd)
temp_stdout = StringIO.new
temp_stderr = StringIO.new

in_current_dir do
RSpec::Core::Runner.run(cmd.split, stderr, stdout)
RSpec::Core::Runner.run(cmd.split, temp_stderr, temp_stdout)
end
ensure
RSpec.reset

@last_cmd_stdout = temp_stdout.string
@last_cmd_stderr = temp_stderr.string
stdout.write(@last_cmd_stdout)
stderr.write(@last_cmd_stderr)
end

def in_current_dir
Expand Down
1 change: 1 addition & 0 deletions spec/support/formatter_support.rb
Expand Up @@ -194,6 +194,7 @@ def example
:full_description => "Example",
:execution_result => result,
:location => "",
:rerun_command => "",
:metadata => {
:shared_group_inclusion_backtrace => []
}
Expand Down

0 comments on commit cc865dc

Please sign in to comment.