H ithere.
In my opinion, it would be really cool to have a sinon.stub() method (maybe for mocks, too) to make the stub return the result of a specified callback.
Usage example:
const stub = sinon.stub();
stub.returnsCallbackResult( () => new Foo() ); // Foo being some constructor method
I obviously don't want to use sinon.stub().returns( new Foo() ) here, because this would actually create the Foo object now, which is too early, if needed at all, that is.
I hope this makes sense. :)
Thanks,
Thorsten
P.S.: if this issue gets a Go, I'm happy to provide a PR for this.
I am not totally sure what you are trying to achieve here, but it seems to me like you should get to know our friend stub#yields(). See the docs. Are you trying to recreate this?
The example code really does not make much sense to me. Could you create create some imaginary code that displays what you are aiming for? Setup code, exercise code and assertions.
yields (in whatever version) doesn't seem to be what I'm looking for, no. But maybe I just don't understand it...
Let's say I would like to create a jQuery-like stub. Code could be like so:
export default function jQueryObject( customMembers = {} ) {
const members = _.extend( {
length: 1,
find: sinon.stub(),
val: sinon.stub()
}, customMembers );
Object.keys( members ).forEach( ( key ) => {
this[ key ] = members[ key ];
} );
}
What I really would like here, is to make find not only be a stub, but also dictate what it returns when being executed. This would then be another jQueryObject object, which constructor method we're in here.
So writing find: sinon.stub().returns( new jQueryObject() ) would, of course, lead to an infinite loop (i.e., eventually the call stack runs full), because I actually create a new jQueryObject here. What I want to do instead, is to return the result of a function that in turn returns a new object.
So I would like to write find: sinon.stub().returnsCallbackResult( () => new jQueryObject() ).
Is this more clear?
@fatso83 any news on this?
I'd be happy to provide a PR to make this even more clear. :)
As this would lead to a new returns* method, however, this is related to #440.
I am really not seeing the need for this, as this seems perfectly doable today.
Instead of your suggestion of making it possible to do this:
find : sinon.stub().returnsCallbackResult( () => new jQueryObject() )
you could just do this with todays implementation:
find : s.spy(() => new jQueryObject())
Easier to read and understand IMHO. The current API surface seems more than big enough as it is, so I am not to keen on adding even more to it without seeing a real need for it.
this seems perfectly doable today.
Well, not really. At least not the greater picture.
Just making a _thing_ return a callback's result is doable by using a spy, that's right.
But you'd lose all stub-specific aspects, and you lose the stub's (or in this case, the spy's) inner state. You cannot do .returns() (or any other returns*() variant) on a spy. You'd have to create a new one instead, wrapping the callback. Right?
What I'd like to have, however, is a stub, that behaves some certain way, and then, at some point in time, I make it behave differently. Or you could think of something like this:
const factoryStub = sinon.stub();
factoryStub
.withArgs( 'foo' ).returnsCallbackResult( createFoo )
.withArgs( 'bar' ).returnsCallbackResult( createBar );
You really don't think something like is useful? :)
I also think that your use case is too specific to justify an extension to the API. The examples you provide can all be done with a custom function wrapped in a spy as @fatso83 suggested. This makes clear what is going on and is less confusing to read.
I had another case: I needed one of stubs with special args to call passed callback two times, haven't found method for that, but returnsCallbackResult might also help with case like mine
I had another case: I needed one of stubs with special args to call passed callback two times, haven't found method for that, but
returnsCallbackResultmight also help with case like mine
I have done this with:
sinon.stub(model, 'functionToStub').callsFake((cb) => {
cb(null, response);
});
WDYT @mkusher @tfrommen ?
@orubin yeah, I've finished up with something similar
Most helpful comment
I had another case: I needed one of stubs with special args to call passed callback two times, haven't found method for that, but
returnsCallbackResultmight also help with case like mine