rubyrspecruby-hash

How to use `eq` matcher with `hash_including` matcher for an array of hashes in rspec


I have an array of hashes and I'm trying to assert that the array has exactly a certain number of hashes in a certain order that have a certain key.

So let's say I have an array of fruits.

fruits = [
  { name: 'apple', count: 3 },
  { name: 'orange', count: 14 },
  { name: 'strawberry', count: 7 },
]

When I use the eq matcher with hash_including (or include which is its alias), the assertion fails.

# fails :(
expect(fruits).to eq([
  hash_including(name: 'apple'),
  hash_including(name: 'orange'),
  hash_including(name: 'strawberry'),
])

It's weird that this doesn't work and I've always found a way around it and moved on, but it's been bothering me for a while, so I decided to post about it this time.

What I'm not looking for

Obviously this works but I like the other syntax because that's kinda the point of these matchers: so I don't have to transform my data structures by hand and have more readable specs.

fruit_names = fruits.map { |h| h.fetch(:name) }
expect(fruit_names).to eq(['apple', 'orange', 'strawberry'])

contain_exactly and include work but I care about the exact size of the array and the order of elements, which they fail to assert.

# passes but doesn't assert the size of the array or the order of elements
expect(fruits).include(
  hash_including(name: 'apple'),
  hash_including(name: 'orange'),
  hash_including(name: 'strawberry'),
)

# passes but doesn't assert the exact order of elements
expect(fruits).contain_exactly(
  hash_including(name: 'apple'),
  hash_including(name: 'orange'),
  hash_including(name: 'strawberry'),
)

Solution

  • Looks like you just need to use match

    fruits = [
      { name: 'apple', count: 3 },
      { name: 'orange', count: 14 },
      { name: 'strawberry', count: 7 },
    ]
    
    expect(fruits).to match([
      include(name: 'apple'),
      include(name: 'orange'),
      include(name: 'strawberry'),
    ])
    

    This test will fail if some array element is missing or extra

    This test will fail if some of hashes doesn't include specified key-value pair

    This test will fail in case of wrong array elements order