From 6a964ed8c6c2c085fd282919def074f8fe7ad7b4 Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Mon, 14 Aug 2023 17:58:20 +0900 Subject: [PATCH] Respect extra_failure_lines in RSpec metadata RSpec tests can have associated metadata, which is just a hash of content. One magic metadata property is `extra_failure_lines`. If this property is set, then RSpec will read its content and include it in the output it prints if the test fails. This property particularly comes into play in RSpec system specs, a wrapper around Rails system tests. If a system test fails, a screenshot is automatically taken of the page (provided the driver supports it) and a message is printed which details the path to the screenshot. RSpec's wrapper will capture output generated while the test is running and then store it in `extra_failure_lines`. By doing this, output (including the screenshot path, but potentially other information as well) is effectively moved to the spec failure message. This gem, as it patches key parts of `rspec-rails`, doesn't support `extra_failure_lines`, so anything in this metadata property is effectively discarded. This commit restores support. Co-authored-by: willnet --- lib/super_diff/rspec/monkey_patches.rb | 23 ++++++++- spec/integration/rspec/magic_metadata_spec.rb | 51 +++++++++++++++++++ spec/support/integration/helpers.rb | 11 +++- 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 spec/integration/rspec/magic_metadata_spec.rb diff --git a/lib/super_diff/rspec/monkey_patches.rb b/lib/super_diff/rspec/monkey_patches.rb index ee2868f6..bf2eed8e 100644 --- a/lib/super_diff/rspec/monkey_patches.rb +++ b/lib/super_diff/rspec/monkey_patches.rb @@ -218,7 +218,10 @@ def failure_line_groups } end end - + @failure_line_groups << { + lines: extra_failure_lines, + already_colorized: true + } @failure_line_groups end end @@ -241,6 +244,24 @@ def failure_slash_error_lines lines end + # Override to ensure that each item in the array returned is one and + # only one line and doesn't contain any newline characters + def extra_failure_lines + @extra_failure_lines ||= + begin + original_lines = Array(example.metadata[:extra_failure_lines]) + normalized_lines = + original_lines.flat_map { |line| line.split("\n") } + unless normalized_lines.empty? + unless normalized_lines.first == "" + normalized_lines.unshift("") + end + normalized_lines.push("") unless normalized_lines.last == "" + end + normalized_lines + end + end + # Exclude this file from being included in backtraces, so that the # SnippetExtractor prints the right thing def find_failed_line diff --git a/spec/integration/rspec/magic_metadata_spec.rb b/spec/integration/rspec/magic_metadata_spec.rb new file mode 100644 index 00000000..89f914b2 --- /dev/null +++ b/spec/integration/rspec/magic_metadata_spec.rb @@ -0,0 +1,51 @@ +require "spec_helper" + +RSpec.describe "Integration with RSpec's magic metadata", type: :integration do + it "includes extra_failure_lines in failure messages" do + as_both_colored_and_uncolored do |color_enabled| + snippet = <<~TEST.strip + RSpec.describe "test" do + it { expect(true).to be(false) } + + after do + RSpec.current_example.metadata[:extra_failure_lines] = "foo\nbar" + end + end + TEST + program = + make_plain_test_program( + snippet, + color_enabled: color_enabled, + preserve_as_whole_file: true + ) + + expected_output = + build_expected_output( + color_enabled: color_enabled, + test_name: "test is expected to equal false", + snippet: "it { expect(true).to be(false) }", + expectation: + proc do + line do + plain "Expected " + actual "true" + plain " to equal " + expected "false" + plain "." + end + end, + extra_failure_lines: + proc do + indent by: 5 do + line "foo" + line "bar" + end + end + ) + + expect(program).to produce_output_when_run(expected_output).in_color( + color_enabled + ) + end + end +end diff --git a/spec/support/integration/helpers.rb b/spec/support/integration/helpers.rb index e30ac813..ab42fd41 100644 --- a/spec/support/integration/helpers.rb +++ b/spec/support/integration/helpers.rb @@ -48,15 +48,17 @@ def build_expected_output( color_enabled:, snippet:, expectation:, + test_name: "test passes", key_enabled: true, newline_before_expectation: false, indentation: 7, - diff: nil + diff: nil, + extra_failure_lines: nil ) colored(color_enabled: color_enabled) do line "Failures:\n" - line "1) test passes", indent_by: 2 + line "1) #{test_name}", indent_by: 2 line indent_by: 5 do bold "Failure/Error: " @@ -106,6 +108,11 @@ def build_expected_output( newline end end + + if extra_failure_lines + newline + evaluate_block(&extra_failure_lines) + end end end