Why when using have_attributes
with multiple argument matchers and only one is a failure, RSpec fails all the rest of matchers ?
Code example
require 'rspec'
Customer = Struct.new(:id, :name)
RSpec.describe 'fail' do
subject { Customer.new(123, 'Some Name') }
it 'fails' do
expect(subject).to have_attributes(
id: kind_of(String),
name: kind_of(String)
)
end
end
Failure
Although only the id
is invalid we see both :name
& :id
as failed.
Why?
When it's time for RSpec to output the failure results it diffs the expected values with the given. In order to diff object rspecs uses RSpec::Support::Differ
that turns them into strings by inspecting them.
Since we use the RSpec::Mocks::ArgumentMatchers::KindOf
argument matcher RSpec matches it with the
RSpec::Support::ObjectFormatter::DescribableMatcherInspector
and then we get the kind of String
.
You can replicate it by running:
RSpec::Support::ObjectFormatter::DescribableMatcherInspector.new(
RSpec::Mocks::ArgumentMatchers::KindOf.new(String)
).inspect
When it's time to compare the diffs we compare the kind of String
with Some Name
and we end up with the red error output although the matcher did not fail for that particular attribute.
Here is a Github issue for that.