Closed nfantone closed 6 years ago
Thanks for providing a good issue and test case! I will look into it, and it seems we might also need to update/add to the docs on this matter.
@fatso83 You're welcome. Let me know if you need something else.
@fatso83 Just tried with newly released 2.1.0
and the same thing happens, unfortunately. No idea if this was actually tackled (probably not, seen as this issue is still open), but just thought you'd like to know.
One thing that could be problematic is the usage of sinon-chai
which has an explicit peerDependency on sinon < 2
. Doesn't explain why using the old syntax would actually work, though.
Hi @nfantone, since I know the Chai codebase and a bit about a few of its plugins I'll take a look at how sinon-chai works and I'll let you know my findings.
If you have any other ideas or code examples please let me know.
For now you can just use spies instead of stubbing a method with itself, this is probably causing the infinite recursion you're dealing with. Anyway, your use case should be supported and I really think we should fix it.
How would I go about turning my stubs into spies? Would spies call a fake method as well? Could you give me an example? Say we have something like my original case:
sinon.stub(channel, 'assertQueue', channel.assertQueue);
What should the new syntax look like using spies?
By doing this you are just telling your stub to call the original channel.assertQueue
method, which is exactly the same as just using a spy, which allows you to keep track of calls, arguments and other important pieces of information while still calling the old behavior.
You could, for example, turn this:
sinon.stub(channel, 'assertQueue', channel.assertQueue);
Into this:
sinon.spy(channel, 'assertQueue');
If you just want to keep track of calls and other information use a spies
, if you need to change behavior use a stubs
.
@lucasfcosta Well, it turned out you were right. I wasn't aware that .spy
would actually call the original method you are spying on. I replaced most .stub
calls with .spy
and now all tests are passing.
I still have that little issue about the syntax update warning on things like:
this.stub(seneca, 'export').withArgs('transport/utils').returns(transportUtils);
How should that be updated?
I actually need the callsFake
behavior and it seems to fail for me, too. I mean the stubbed function is simply returning undefined
. I've tried debugging it and it looks like the fake
is recorded but this.fakes
is still empty in the spy.
Going back to the original 3-args syntax works.
Hi @emirotin, can you please provide a reproducible example? I had a hard time reproducing this in a concise example, which makes things a lot easier for me to detect and fix possible bugs.
@nfantone Sorry for the delay on answering you, I've been very busy in the last days.
I tried to reproduce the warnings you mentioned by using the following test code and I couldn't get any warnings, both using the master branch and the tagged v2.0.0
commit:
var stub = sinon.stub;
var obj = {
bla: function () { return 'foo' }
}
stub(obj, 'bla').withArgs('lol').returns('bar');
assert(obj.bla('lol'), 'bar')
Can you provide a small reproducible example so I can dig into this more deeply?
Huh I can't reproduce in the simplistic cases. That's really strange as I have a project where it's reproducible. Let me create a reduced version of it
Ah, here it is!
Looks like reset
is erasing the fake:
var sinon = require('sinon')
var x = {
a: function() {
return 'Fail'
}
}
var sandbox = sinon.sandbox.create();
sandbox.stub(x, 'a').callsFake(function() {
return 'OK'
})
console.log(x.a())
sandbox.reset();
console.log(x.a()) // <-- undefined
Thanks @emirotin!
So, according to the docs I believe this is correct behavior, right?
Let's wait for @nfantone's answer so we can fix and hopefully close this.
Also, the docs for sandboxes seem to have markdown problems:
Do you know how can I fix it? I'm trying to edit both docs/_releases
and docs/release-source
but none of them seem to change the docs served by my local server.
I'm not sure it's correct even according to the docs. And definitely works against my intuition. I reset to reset the state of fakes, but not remove the fakes from the stub. Like it's expected to reset the call counts, last args, last result, things like that.
My expectations from callsFake
is that it's part of the setup and shouldn't be gone after reset which I read as "make everything look as right after the original setup".
And definitely it's different from the previous 3-arg form but it's advertised by the warning as the new equivalent to it. But the old API is immune to resets.
@emirotin I agree with you regarding the name consistency.
I've commented the same thing at #1371. I think we must have consistent names for the reset API.
I'll be more than happy to make a PR for that if the project's maintainers agree with this change.
Let's wait to hear the maintainers' thoughts.
@lucasfcosta Sorry for the delay here.
Can you provide a small reproducible example so I can dig into this more deeply?
The test suite included in seneca-amqp-transport reproduces the issue and outputs the warning.
Just clone the repo, install deps, run npm test
. You should see something like:
the handleMessage() function
✓ should handle the request when a message is consumed
sinon.stub(obj, 'meth', fn) is deprecated and will be removed from the public API in a future version of sinon.
Use stub(obj, 'meth').callsFake(fn).
Codemod available at https://github.com/hurrymaplelad/sinon-codemod
That corresponds to the following test:
it('should handle the request when a message is consumed',
sinon.test(function(done) {
var handleRequest = this.spy(transportUtils, 'handle_request');
// This is the sub throwing the warning
this.stub(seneca, 'export')
.withArgs('transport/utils').returns(transportUtils);
var listener = Listener(seneca, options);
listener.listen()
.then(() => {
handleRequest.should.have.been.calledOnce();
handleRequest.should.have.been.calledWith(seneca, { foo: 'bar' },
DEFAULT_OPTIONS, sinon.match.func);
})
.asCallback(done);
}));
I know it may not be a small example, but it sure is real and reproducible.
On a side note, I agree with @emirotin sentiment on the .reset
and .callsFake
behaviour. If the new API is meant to be a "compatible replacement", that is.
Took me quite some time to figure out, because for me the simple replacement with .callsFake
wasn't working, too. When replacing all reset()
calls with resetHistory()
, as @emirotin discovered, it actually works again. This should really be part of the deprecation/update guide.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Promise.then
not work in callsFake
method?
// first way
// if no await will not arrived
await store.dispatch(deleteById(id)).then(()=>{
// can arrived here
})
// second way
sinon.stub(wrapper.find(Account).instance(), "_deleteById").callsFake(async (id)=>{
// truly http request by axios
await store.dispatch(deleteById(id)).then(()=>{
// can't arrived here
})
});
in aciton
export function deleteById(id){
return dispatch=>{
return axios.put(url,data).then(()=>{
// can't arrived here second way but first arrived
})
}
}
@mqliutie it would appear so, at least in latest Chrome on MacOS, bumped into this in Cypress Graphql Stubbing (https://github.com/cypress-io/cypress-documentation/issues/122)
@MichaelHindley Call done()
will work. I don't know is this right way
I don't think done()
helps my particular use case since I'm stubbing the window.fetch
function in order to load mocked GraphQL data and I must return a "thennable" Promise for apollo 😢 thanks for the input though!
I think I reopened this accidentally. Closing, as the docs explicitly mention this.
2.0.0
7.7.3
sinon-test
,sinon-chai
,chai
.What did you expect to happen? Migrating
sinon.stub
syntax from1.x
to2.0.0
either manually or usingsinon-codemod
should not alter test output.What actually happens All tests using a stubbed object fail with an endless stacktrace (excerpt shown below).
Reverting back to the old syntax prints out a warning, but makes all tests work as expected:
Also, calls like these will show the exact same warning - although I'm not really sure what's the new expected syntax there:
How to reproduce In my scenario, it was as simple as replacing calls like this:
With the new
2.0.0
stub API:You can also try and pull the entire failing test suite from
seneca-amqp-transport
repo: