Skip to content →

Failing RSpec `have_attributes` with arguments matchers

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

Failing spec with have_attributes & kind_of

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.

Published in Code explorations