Don't silently ignore arbitrary method expectations when combining them with 'and_call_original' #382
Funnily what I thought was a bug, never quite worked the way I thought it was and I refactored the spec after reading his suggestions. Myron asked me to also add an issue for it, though. So here we go :-)
The spec we talked about had used the following expectation.
CachedUser.should_receive(:where) do |args| expect(args[:id]).to have(3).items expect(contact_ids).to include(*args[:id]) end.and_call_original
The values passed to 'where' are sort of random so you can't really setup an argument matcher with 'with'. That's why we tried to verify them in the block. The whole code under test there was also part of an AREL call comparable to this one. That's where the 'and_call_original' came into the game
The spec passed. Though, as Myron pointed out, 'and_call_original' completely replaces the block expectation, resulting in the inner expectations never to be executed.
That was a bit surprising to find out, but to be honest also a fault on my side, since I probably never saw the expectation fail in the first place :-/
To make that behavior more obvious I think it would be good to either raise an exception or to output a warning in that case.
In @BjRo's gist, it also came up that an expression like this:
expect(CachedUser).to receive(:where) do |args| expect(args[:id]).to have(3).items expect(contact_ids).to include(*args[:id]) end.and_call_original
...raises a confusing error (
Hmm, no, but thats a block capture issue... e.g.
expect(user).to receive(:where) do |args| expect(args[:id].size).to eq 3 end.and_call_original
produces the weird error
expect(user).to( receive(:where) do |args| expect(args[:id].size).to eq 3 end.and_call_original )
Ah...I know what's going on: that expression passes the block to
So, I think if we changed