Rspec match array of hashes

19,163

Solution 1

You can use the any? method. See this for the documentation.

hashes = [{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}]
expect(hashes.any? { |hash| hash['foo'] == '2' }).to be_true

Solution 2

how about?

hashes = [{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}]
expect(hashes).to include(include('foo' => '2'))

Solution 3

Use Composable Matchers

hashes = [{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}]
expect(hashes)
  .to match([
    a_hash_including('foo' => '2'), 
    a_hash_including('foo' => '1')
  ])

Solution 4

you can use composable matchers

http://rspec.info/blog/2014/01/new-in-rspec-3-composable-matchers/

but I prefer to define a custom matcher like this

require 'rspec/expectations'

RSpec::Matchers.define :include_hash_matching do |expected|
  match do |array_of_hashes|
    array_of_hashes.any? { |element| element.slice(*expected.keys) == expected }
  end
end

and use it in the specs like this

describe RSpec::Matchers do
  describe '#include_hash_matching' do
    subject(:array_of_hashes) do
      [
        {
          'foo' => '1',
          'bar' => '2'
        }, {
          'foo' => '2',
          'bar' => '2'
        }
      ]
    end

    it { is_expected.to include_hash_matching('foo' => '1') }

    it { is_expected.to include_hash_matching('foo' => '2') }

    it { is_expected.to include_hash_matching('bar' => '2') }

    it { is_expected.not_to include_hash_matching('bar' => '1') }

    it { is_expected.to include_hash_matching('foo' => '1', 'bar' => '2') }

    it { is_expected.not_to include_hash_matching('foo' => '1', 'bar' => '1') }

    it 'ignores the order of the keys' do
      is_expected.to include_hash_matching('bar' => '2', 'foo' => '1')
    end
  end
end


Finished in 0.05894 seconds
7 examples, 0 failures
Share:
19,163
Pezholio
Author by

Pezholio

Updated on June 19, 2022

Comments

  • Pezholio
    Pezholio about 2 years

    I have an array of hashes, which for the sake of argument looks like this:

    [{"foo"=>"1", "bar"=>"1"}, {"foo"=>"2", "bar"=>"2"}]
    

    Using Rspec, I want to test if "foo" => "2" exists in the array, but I don't care whether it's the first or second item. I've tried:

    [{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}].should include("foo" => "2"))
    

    But this doesn't work, as the hashes should match exactly. Is there any way to partially test each hash's content?