spec/unit/support/matchers/be_a_response_like_spec.rb
require 'spec_helper'
RSpec.describe 'be_a_response_like matcher' do
it 'passes when two hashes are identical' do
expect({ 'a' => 1 }).to be_a_response_like({ 'a' => 1 })
end
it 'passes with array values' do
expect({ 'a' => [1, 2] }).to be_a_response_like({ 'a' => [1, 2] })
end
context 'with regular expression matching' do
it 'passes when comparing a string' do
expect({ 'a' => '1' }).to be_a_response_like({ 'a' => /\d+/ })
end
it 'fails when comparing an integer' do
expect do
expect({ 'a' => 1 }).to be_a_response_like({ 'a' => /\d+/ })
end.to raise_expectation_not_met_with_summary_parts('! a:', '- /\d+/', '+ 1')
end
it 'passes when matching an iso8601 timestamp' do
expect({ 'a' => Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ') }).to be_a_response_like({ 'a' => iso8601 })
end
it 'does not interpret strings as regex' do
expect do
expect({ 'a' => '[thing]' }).to be_a_response_like({ 'a' => '[th]' })
end.to raise_expectation_not_met_with_summary_parts('! a:', '- [th]', '+ [thing]')
end
end
it 'fails when values do not match in a top-level key' do
expect do
expect({ 'a' => 1 }).to be_a_response_like({ 'a' => 2 })
end.to raise_expectation_not_met_with_summary_parts('! a:', '- 2', '+ 1')
end
it 'fails when values do not match in a nested key' do
expect do
expect({ 'a' => { 'b' => 1 } }).to be_a_response_like({ 'a' => { 'b' => 2 } })
end.to raise_expectation_not_met_with_summary_parts('! a.b:', '- 2', '+ 1')
end
it 'fails when expected contains a key missing in actual' do
expect do
expect({}).to be_a_response_like({ 'a' => 1 })
end.to raise_expectation_not_met_with_summary(/- a: 1/)
end
it 'fails when actual contains a key missing in expected' do
expect do
expect({ 'a' => 1 }).to be_a_response_like({})
end.to raise_expectation_not_met_with_summary(/\+ a: 1/)
end
it 'fails when array values do not match' do
expect do
expect({ 'a' => [1, 2] }).to be_a_response_like({ 'a' => [1] })
end.to raise_expectation_not_met_with_summary(/\+ a\[1\]: 2/)
end
it 'fails when array values are permuted' do
expect do
expect({ 'a' => [1, 2] }).to be_a_response_like({ 'a' => [2, 1] })
end.to raise_expectation_not_met_with_summary(/\+ a\[0\]: 1\n\s+- a\[2\]: 1/)
end
it 'fails when hash values within arrays do not match' do
expect do
expect({ 'a' => [{ 'b' => 1 }] }).to be_a_response_like({ 'a' => [{ 'b' => 2 }] })
end.to raise_expectation_not_met_with_key_change(expected: '- a[0]: {"b"=>2}', actual: '+ a[0]: {"b"=>1}')
end
it 'fails when hash keys within arrays do not match' do
expect do
expect({ 'a' => [{ 'b' => 1 }] }).to be_a_response_like({ 'a' => [{ 'c' => 1 }] })
end.to raise_expectation_not_met_with_key_change(expected: '- a[0]: {"c"=>1}', actual: '+ a[0]: {"b"=>1}')
end
it 'fails when actual is empty but expected is an empty array' do
expect do
expect({}).to be_a_response_like({ 'a' => [] })
end.to raise_expectation_not_met_with_summary(/- a: \[\]/)
end
it 'fails when actual as a non-empty but expected is an empty array' do
expect do
expect({ 'a' => [{ 'b' => 1 }] }).to be_a_response_like({ 'a' => [] })
end.to raise_expectation_not_met_with_summary(/\+ a\[0\]: \{"b"=>1\}/)
end
it 'fails on deeply nested value mismatches' do
expect do
expect({ 'a' => [{ 'a' => { 'a' => [{ 'a' => 1 }, { 'b' => 2 }] } }] }).to be_a_response_like({ 'a' => [{ 'a' => { 'a' => [{ 'a' => 1 }, { 'b' => 1 }] } }] })
end.to raise_expectation_not_met_with_key_change(expected: '- a[0].a.a[1]: {"b"=>1}',
actual: '+ a[0].a.a[1]: {"b"=>2}')
end
def raise_expectation_not_met_with_summary(ptn)
raise_error(RSpec::Expectations::ExpectationNotMetError, ptn)
end
def raise_expectation_not_met_with_key_change(expected:, actual:)
ptn = Regexp.new(Regexp.escape(expected) + '\n\s+' + Regexp.escape(actual))
raise_error(RSpec::Expectations::ExpectationNotMetError, ptn)
end
def raise_expectation_not_met_with_summary_parts(*parts)
ptn = Regexp.new(parts.map { |part| Regexp.escape(part) }.join('\n\s+'))
raise_error(RSpec::Expectations::ExpectationNotMetError, ptn)
end
end