Reputation: 2694
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?
Upvotes: 38
Views: 26606
Reputation: 4450
hashes = [{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}]
expect(hashes)
.to match([
a_hash_including('foo' => '2'),
a_hash_including('foo' => '1')
])
Upvotes: 19
Reputation: 3184
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
Upvotes: 7
Reputation: 1600
how about?
hashes = [{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}]
expect(hashes).to include(include('foo' => '2'))
Upvotes: 51
Reputation: 4982
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
Upvotes: 12
Reputation: 356
If separate testing of hashes is not a strict requirement I would do it this way:
[{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}].map{ |d| d["foo"] }.should include("2")
Upvotes: 0