rspec / rspec-mocks

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

Rails 7.1 breaks receive().with #1530

Closed palkan closed 1 year ago

palkan commented 1 year ago

Your environment

Steps to reproduce

In a Rails application (i.e., with Rails loaded), define a method expectation:

mock = instance_double("Hash")
allow(mock).to receive(:key?).with(:x) { 1 }

expect(mock.key?(:x)).to eq 1

Expected behavior

Pass.

Actual behavior

ArgumentError:
       wrong number of arguments (given 1, expected 0)
     # ../rails/activesupport/lib/active_support/core_ext/object/with.rb:24:in `with'

What happened?

Rails monkey-patched Object#with https://github.com/rails/rails/pull/46681 /cc @byroot

RSpec receive matcher defines chain methods only for undefined methods: https://github.com/rspec/rspec-mocks/blob/4a1032bf93fe8b47c9e3416413e2b05d604d109f/lib/rspec/mocks/matchers/receive.rb#L58-L59

Since #with is defined on Object, the with modifier is no longer available.

nobu commented 1 year ago

Why does MessageExpectation need to b e a subclass of Object, not BasicObject?

byroot commented 1 year ago

Even then, why would it not redefine existing methods? I'll git blame to see if I can find the reason for this.

byroot commented 1 year ago

Ah, I think the intent is to not redefine methods directly defined in Receive, since we're copying all the matchers. method_defined?(name, false) would fix it I think.

byroot commented 1 year ago

I think I have a fix for it, but GitHub seems to be having issues, I get an error message when trying to create the PR....

Pull request creation failed. Validation failed: You can't perform that action at this time.

https://github.com/rspec/rspec-mocks/compare/rspec:main...casperisfine:receiver-with?expand=1

pirj commented 1 year ago

@byroot I’ve opened one, does it work for you?

byroot commented 1 year ago

Sure, thank you.