rspec / rspec-mocks

RSpec's 'test double' framework, with support for stubbing and mocking
https://rspec.info
MIT License
1.16k stars 356 forks source link

Argument matcher prevents diffability of custom matcher #1480

Open jasonkarns opened 2 years ago

jasonkarns commented 2 years ago

Subject of the issue

We have a custom matcher that matches "as_json-able" objects.

RSpec::Matchers.define :as_json do |expected|
  def actual = super.as_json
  match { |actual| values_match? expected, actual }
  diffable
end

For diffing, it redefines the actual.

This matcher correctly emits diffs when used "directly" but when used as an argument matcher within a mock, the diff output no longer respects the redefined actual.

I suspect this may be related to https://github.com/rspec/rspec-expectations/issues/1317

Your environment

Steps to reproduce

https://gist.github.com/jasonkarns/7ac8c418dc155ef3d3555c3a0d9ecc64

Expected behavior

Given the tests in linked gist above, I would expect the failure output to print the diffable values comparing the overridden actual:

something like:

       expected #<JsonAble:0x00000001102b23f0 @a=42> to as json {:oops=>42}
       Diff:
       @@ -1 +1 @@
       -:oops => 42,
       +:alt => 42,

Actual behavior

The argument matcher failure message ignores the overridden actual value of the nested matcher and instead diffs against the original actual:

       #<Double (anonymous)> received :serialize with unexpected arguments
         expected: (as json {:oops=>42})
              got: (#<JsonAble:0x00000001101691b0 @a=42>)
       Diff:
       @@ -1 +1 @@
       -["as json {:oops=>42}"]
       +[#<JsonAble:0x00000001101691b0 @a=42>]
pirj commented 2 years ago

Wondering if https://github.com/rspec/rspec-expectations/pull/1319 fixes this?