rspec-expectations icon indicating copy to clipboard operation
rspec-expectations copied to clipboard

It would be nice to add `.to receive(...).with_block`

Open ioquatix opened this issue 6 years ago • 15 comments

There is no easy way to verify a method would be called with a block.

It would be nice to have

expect(thing).to receive(:method).with_block

ioquatix avatar Jul 02 '18 01:07 ioquatix

Hello @ioquatix

This is probably not what you are asking but have you seen? https://github.com/rspec/rspec-expectations/blob/v3.7.0/features/custom_matchers/define_block_matcher.feature

Also, it's funny because factory_bot have a matcher for block with the name you mentioned. https://github.com/thoughtbot/factory_bot/blob/40c8708c473279d3f812a825ff979f2c93451e05/spec/support/matchers/trait.rb

Used like this: https://github.com/thoughtbot/factory_bot/blob/ad107bea15aa75b60decbbebbc86980fd3e85d34/spec/factory_bot/definition_proxy_spec.rb#L127-L130

Bye

benoittgt avatar Jul 02 '18 18:07 benoittgt

@benoittgt I think @ioquatix is talking about receive(...) from rspec-mocks, so that you can expect to receive a message with a block. You can currently deal with this by passing a block to receive:

expect(thing).to receive(:method) do |&block|
  expect(block).not_to be_nil
end

If we wanted to add more explicit support for this, I'd rather not add a new with_block API; instead maybe something like:

expect(thing).to receive(:method).with(a_block)

Where a_block is a "special" argument matcher like any_args or no_args that doesn't match on a positional arg but instead rspec-mocks handles internally.

@ioquatix does the approach I suggested above work for you?

myronmarston avatar Jul 02 '18 18:07 myronmarston

Thanks, @myronmarston for clarification. I agree with your proposal.

benoittgt avatar Jul 02 '18 19:07 benoittgt

Yep it would be fine. Does it work with arguments too?

ioquatix avatar Jul 02 '18 21:07 ioquatix

Yep it would be fine. Does it work with arguments too?

I'm not sure what you mean by "work with arguments". Can you provide an example of what you mean?

myronmarston avatar Jul 02 '18 21:07 myronmarston

expect(thing).to receive(:method).with(1, 2, 3, a_block)

ioquatix avatar Jul 02 '18 22:07 ioquatix

it's actually not that important to my use case, just thought it might be useful in the general case.

ioquatix avatar Jul 02 '18 22:07 ioquatix

Hopefully, yes, we could make that work.

Do you want to take a stab at adding it. Improving RSpec is largely a self-service operation unless one of the core team members wants to take this work on (which often doesn't happen; we all have lives and jobs!).

myronmarston avatar Jul 02 '18 22:07 myronmarston

Sure, that makes sense.

If I have time, I will mention here I am starting work. Otherwise, this is free for anyone who is interested to implement it. If someone else picks it up, please mention it here so we don't duplicate effort :)

ioquatix avatar Jul 02 '18 22:07 ioquatix

@myronmarston I've tried taking a stab at this in kaiwren/1065-with-a-block - am able to get this working at the cucumber feature level, but I'm missing something on the sad path spec which I'm unable to get to pass (even though it works fine in the cuke). I'm unable to figure out why I'm not able to catch the exception; probably missing something really obvious...

Would be grateful if I could get a quick review and some feedback. If my approach isn't flawed, will complete this and raise a PR.

kaiwren avatar Sep 16 '18 20:09 kaiwren

Maybe @ioquatix can provide a review too?

https://github.com/kaiwren/rspec-mocks/commit/524637dfe8de2078c58d0683c3a59222940a05ca

benoittgt avatar Sep 17 '18 05:09 benoittgt

It looks pretty good.

ioquatix avatar Sep 17 '18 08:09 ioquatix

I've expanded on @kaiwren's work over on rspec/rspec-mocks#1237, it's worth noting we already had the and_yield expectation, and I think there are actually a few issues with a_block, what happens when used positionally? and does it always mean the supplied &block argument? After all object.msg(proc {}, proc {}) is valid Ruby, should we expect on this with .with(a_block, a_block) and how do we differentiated that from msg(proc{}) { }.

JonRowe avatar Sep 17 '18 10:09 JonRowe

Did this ever get merged in? Looking at it 4 years later, and still think it would be useful.

alexpapworth avatar Sep 12 '22 10:09 alexpapworth

I don't think so!

ioquatix avatar Sep 12 '22 12:09 ioquatix