2

RSpec provides a "diff"-style output when comparing multi-line strings. Is there a way to do something similar when comparing arrays (other than converting the array to a multi-line string)?

Zack
  • 6,232
  • 8
  • 38
  • 68
  • Is [`match_array`](http://www.rubydoc.info/github/rspec/rspec-expectations/RSpec/Matchers:match_array) what you're looking for? If not, then what desired behaviour does it lack? – Tom Lord Oct 04 '17 at 13:48
  • 1
    @TomLord `match_array` doesn't take the order of elements into account, i.e. `expect([1,2,3]).to match_array([3,2,1])` passes. – Stefan Oct 04 '17 at 13:50
  • In my case, order is important. – Zack Oct 04 '17 at 13:51
  • Oh sorry, I thought that's what you wanted. But you're actually just after a "nicer" error message when a standard `eq` matcher fails? – Tom Lord Oct 04 '17 at 13:55
  • Yes. That's exactly it. The output is long enough that it can be difficult to find the difference when the matcher fails. – Zack Oct 04 '17 at 13:57
  • What about using a custom error message? https://relishapp.com/rspec/rspec-expectations/v/3-6/docs/customized-message – mabe02 Oct 04 '17 at 13:59
  • A custom error message is a possible solution. The link you shared applies to a specific example only. I wouldn't want to repeat the customization for each example. I was also hoping to avoid having to write my own diff. (Although that is certainly not out of the question.) – Zack Oct 04 '17 at 14:04
  • The solution shown here does what I want --- except for the warning against using `RSpec::Differ` directly. https://stackoverflow.com/questions/12551564/how-to-write-a-diffable-matcher-with-rspec2 – Zack Oct 04 '17 at 14:23

1 Answers1

3

I may be mistaken, but I don't think this feature is built-in to RSpec.

However, you could implement a custom matcher with a custom error message:

RSpec::Matchers.define(:eq_array) do |expected|
  match { |actual| expected == actual }

  failure_message do |actual|
    <<~MESSAGE
      expected: #{expected}
      got:      #{actual}

      diff:     #{Diffy::Diff.new(expected.to_s, actual.to_s).to_s(:color)}
    MESSAGE
  end
end

# Usage:

expect([1, 2, 3]).to eq_array([1, 4, 3])

This demo is using the diffy library; you could implement this however you see fit.

Tom Lord
  • 27,404
  • 4
  • 50
  • 77
  • That's what I was looking for. The key for me was figuring out how to call the built-in differ. An older article cautioned against using the differ directly. https://stackoverflow.com/questions/12551564/how-to-write-a-diffable-matcher-with-rspec2 – Zack Oct 04 '17 at 14:50