rspec / rspec-support

Common code needed by the other RSpec gems. Not intended for direct use.
https://rspec.info
MIT License
99 stars 103 forks source link

When using `have_attributes` with multiple `kind_of` diff reports all matchers as failures. #579

Closed PanosCodes closed 1 year ago

PanosCodes commented 1 year ago

Subject of the issue

Why when using have_attributes with multiple kind_of matchers and only one is a fails, it reports all of them as failures.

My understanding is when it's time compare the expected with the actual results the differ is given kind of String and that is why is reporting it as a failure.

Since we use the RSpec::Mocks::ArgumentMatchers::KindOf, ObjectFormatter is matching it with RSpec::Support::ObjectFormatter::DescribableMatcherInspector and then we get the kind of String from the KindOf description.

Your environment

Steps to reproduce

# frozen_string_literal: true

begin
  require "bundler/inline"
rescue LoadError => e
  $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
  raise e
end

gemfile(true) do
  source "https://rubygems.org"

  gem "rspec", "3.12"
  gem "rspec-support", "3.12"
end

puts "Ruby version is: #{RUBY_VERSION}"
require 'rspec/autorun'

Customer = Struct.new(:id, :name)

RSpec.describe 'fail' do
  subject { Customer.new(123, 'Some Name') }

  it 'has an id and a name' do
    expect(subject).to have_attributes(
      id: kind_of(String),
      name: kind_of(String)
    )
  end
end

Expected behavior

  expected #<struct Customer id=123, name="Some Name"> to have attributes {:id => kind of String, :name => kind of String} but had attributes {:id => 123, :name => "Some Name"}
  Diff:
  @@ -1,3 +1,3 @@
  -:id => kind of String,
  +:id => 123,
  :name => "Some Name",

Actual behavior

  expected #<struct Customer id=123, name="Some Name"> to have attributes {:id => kind of String, :name => kind of String} but had attributes {:id => 123, :name => "Some Name"}
  Diff:
  @@ -1,3 +1,3 @@
  -:id => kind of String,
  -:name => kind of String,
  +:id => 123,
  +:name => "Some Name",
JonRowe commented 1 year ago

:wave: Sadly this is a known limitation of the current differ, it compares strings so even if they match it produces a diff between the description and the expected, there is some work to change the differ and it may be improved at one point, but as it stands this is a "can't fix" for the current differ,