I have a react
component which calls an async
function passed in as a prop and then calls another function in the then
function.
I've trivialised it below as an illustration.
E.g.
const Form = ({ doSomething, closeModal }) =>
<form onSubmit={(e) => {doSomething().then(() => closeModal())
}}>
...
</form>
I am attempting to test that closeModal
was called like so:
it('should doSomething then call closeModal', () => {
const doSomethingStub = sinon.stub().resolves()
const closeModalStub = sinon.stub()
const props = {
doSomething: doSomethingStub,
closeModal: closeModalStub
}
const wrapper = shallow(<Form {...props}/>)
wrapper.find(`form`).simulate(`submit`)
expect(doSomethingStub.called).toEqual(true)
expect(closeModalStub.called).toEqual(true)
})
In my example, only the first expectation is true. Have I done something wrong with the sinon.stub setup? or what I'm expecting? it feels like something minor but I can't pin it down
You're exactly right, it just needs a minor change:
then
queues a callback for execution. Callbacks execute when the current synchronous code completes and the event loop grabs whatever is queued next.
The test is running to completion and failing before the callback queued by then
from within onSubmit()
has a chance to run.
Give the event loop a chance to cycle so the callback has a chance to execute and that should resolve the issue. That can be done by making your test function asynchronous and awaiting on a resolved promise where you want to pause the test and let any queued callbacks execute:
it('should doSomething then call closeModal', async () => {
const doSomethingStub = sinon.stub().resolves()
const closeModalStub = sinon.stub()
const props = {
doSomething: doSomethingStub,
closeModal: closeModalStub
}
const wrapper = shallow(<Form {...props}/>)
wrapper.find(`form`).simulate(`submit`);
// Pause the synchronous test here and let any queued callbacks execute
await Promise.resolve();
expect(doSomethingStub.called).toEqual(true)
expect(closeModalStub.called).toEqual(true)
});