In my spec i have the following response structure
something: { foo: [{bar: 'baz'}, {one: 'two'}] }
I try to compare it but the order inside of foo-array is random. I've found this article: link, and in it, there is the following code:
Use a_collection_containing_exactly when you have an array, but can’t determine the order of elements
expected = { "data" => a_collection_containing_exactly( a_hash_including("id" => "1"), a_hash_including("id" => "2") ) } expect(response.parsed_body).to include(expected)
But it does not work for me as the comparison is seeing matcher a_collection_containing_exactly
as part of the hash like
{"base_matcher"=>{"expected"=>[{bar: 'baz'}, {one: 'two'}]}}
What is that I have missed? Is there any better solution?
Edit: To clarify, here is a minimal reproducible example
expected_value = { something: { foo: [{ bar: 'baz' }, { one: 'two' }] }}
expect(response.parsed_body).to eq(expected_value)
CodePudding user response:
I think the RSpec match_array
matcher is what you need:
array_of_hashes = [{bar: "baz"},{one: "two"}]
expect(response.parsed_body[:foo]).to match_array(array_of_hashes)
if your top-level hash has many keys, you can write a custom matcher:
# in spec/matchers/match_sort_indifferent.rb:
require 'rspec/expectations'
RSpec::Matchers.define :match_sort_indifferent do |expected|
match do |actual|
expected.keys.each do |key|
expect(actual[key]).to match_array expected[key]
end
expect(expected.keys.length).to eq actual.keys.length
end
end
# in spec/models/test_spec.rb
require 'rails_helper'
require 'matchers/match_sort_indifferent'
result = {foo: [{bar: "baz"},{qux: "dak"}]}
describe {
it {
expect(result).to match_sort_indifferent({foo: [{qux: "dak"},{bar: "baz"}]})
expect(result).not_to match_sort_indifferent({foo: [{qux: "sum"},{bar: "baz"}]})
}
}
CodePudding user response:
Thanks for the answers. I solved the problem with a help of Rspec-json-expectations gem and UnorderedArray
So my solution looks like this:
expected_value = { something: { foo: UnorderedArray({ bar: 'baz' }, { one: 'two' }) }}
and the matcher
expect(response.parsed_body).to include_json expected_value
The downside is that it only checks if the expected values are present, and doesn't catch the extra ones.