match_array diffs are much larger than eq diffs
maxnotarangelo opened this issue · 2 comments
I just started using this gem, and I noticed that while it does a great job with showing only the differences in array elements when you use the eq
matcher in RSpec, it just shows the entirety of each different element when you use match_array
. It would be quite useful if it was able to show a similarly clean diff.
Here's an example.
require "rails_helper"
RSpec.describe Book, type: :model do
it "matches" do
new_books = Fabricate.times(2, :book, published_date: 1.day.ago)
old_books = Fabricate.times(2, :book, published_date: 1.year.ago)
expect(new_books).to eq(old_books)
end
end
This produces the following output (I have the diff elision setting enabled):
However, switching the expectation to
expect(new_books).to match_array(old_books)
produces a much larger diff, which is much harder to read:
Hi @maxnotarangelo,
Thanks for bringing this up. From a matcher perspective, match_array
works on a different premise than eq
.
In the case of eq
, we can assume there is a one-to-one correlation between the items in the expected
and actual
arrays. So even if you have two separate objects with different contents, we can assume that there is a relationship between the two — i.e., you either meant the "expected" version or the "actual" version — and so we ask you to choose one.
match_array
is different, though. The docs for match_array
say:
An alternate form of
contain_exactly
that accepts the expected contents as a single array arg rather that splatted out as individual items.
The docs for contain_exactly
say:
Passes if actual contains all of the expected regardless of order.
So when you use match_array
(or contain_exactly
), you're saying, I don't know in which order the items in the array I'm providing will appear, and I don't care. So we can't make the same assumptions as for eq
. In other words, if there are two items, one in expected
, the other in actual
, at the same index, we need to know that they are similar enough to each other that we can put them next to each other in the diff. In your example, this is a bit difficult. In fact we could say all of the objects in the array are similar to each other because they have the same attributes, so there's really no "best" way to arrange them.
Because of this, there's not a great way for us to get match_array
to act like eq
.
If you want to keep using eq
but achieve the same goals as match_array
, you could sort both of your arrays before making the assertion:
expect(new_books.sort_by(&:created_at)).to eq(old_books.sort_by(&:created_at))
This might not help your diff right now, because both arrays are completely different, but it might help when you're doing this sort of thing in the future.
Does that make sense?
Yeah, that makes sense. I was thinking that there might be some standard ordering of the array elements that match_array used, but even if there were, it wouldn't necessarily be a useful way to sort it.
Thanks for the explanation!