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

`.and_call_original` breaks on Ruby 3.2 for methods with keyword arguments #1512

Closed ric2b closed 1 year ago

ric2b commented 1 year ago

Subject of the issue

With Ruby 3.2 rspec-mocks seems to not pass keyword arguments to the original implementation of a method when using .and_call_original

Your environment

Steps to reproduce

I was able to create this minimal test that reproduces the issue:

      it "handles keyword arguments correctly" do
        A = Class.new do
          def initialize(kw:)
          end
        end

        A.new(kw: 42)

        allow(A).to receive(:new).and_call_original

        A.new(kw: 42)
      end

Expected behavior

The test should pass

Actual behavior

The test fails on the second A instantiation with the error: ArgumentError: wrong number of arguments (given 1, expected 0; required keyword: kw)

pirj commented 1 year ago

Thanks for reporting. Does it help to insert

ruby2_keywords msg if respond_to?(:ruby2_keywords, true)

here?

ric2b commented 1 year ago

Doesn't seem to make a difference :/

pirj commented 1 year ago

Can you please check if #1514 fixes this case?

ric2b commented 1 year ago

@pirj Yup, that seems to fix it!

By the way, I'm not sure what the simplest way of running a specific branch of a dependency is, I struggled a bit, here's what I tried:

  1. I first tried bundle add rspec-mocks --github rspec/rspec-mocks --branch ruby-3.2 but got the error (to be clear, the version is not pinned in my Gemfile, this is about Gemfile.lock):

    Your bundle is locked to rspec-mocks (3.12.1) from https://github.com/rspec/rspec-mocks.git (at e9d65cd@e9d65cd), but that version can no longer be found in that source. That means the author of rspec-mocks (3.12.1) has removed it. You'll need to update your bundle to a version other than rspec-mocks (3.12.1) that hasn't been removed in order to install.

  2. So then I tried bundle config set local.rspec-mocks /tmp/rspec-mocks/ (after cloning and using git switch ruby-3.2) and that seemed to set the branch correctly but the test was still failing as bundle was not using my local clone to run the test.

  3. I ran bundle add rspec-mocks --github rspec/rspec-mocks --branch ruby-3.2 again following the docs but it had other failures due to the branch version being 3.13.0.pre. I manually edited it to 3.12.1 and bundle finally seemed to accept my local clone and use it when running the test.

Mange commented 1 year ago

@ric2b Here's how I tested that branch:

  %w[rspec-core rspec-expectations rspec-support rspec-rails].each do |lib|
    gem lib, git: "https://github.com/rspec/#{lib}.git", branch: "main"
  end
  gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git", branch: "ruby-3.2"

It's based on the snippet in the README of this repo, except rspec-mocks use a different branch than the rest.

Note that I also include rspec-rails since my project was using that too.

Mange commented 1 year ago

I had a related problem in that branch. Perhaps this isn't fixed, or perhaps the fix broke something else.

It's detailed in the PR of that branch: https://github.com/rspec/rspec-mocks/pull/1514#issuecomment-1370776293