redux-saga-test-plan: Testing error throw inside saga
Is there a recommended way to test sagas that throw errors? I’m trying to create a test for this function:
const waitForSocketChannelEvent = function* (socketConnectChannel, delayTimeout = 3000) {
const {event} = yield race({
event: take(socketConnectChannel),
timeout: call(delay, delayTimeout),
});
if (event !== undefined) {
return event;
} else {
throw new Error('Socket Event Timeout');
}
};
The only way I could find to test the function above is using something like this:
test('If the socket event timeouts it should thrown an error', () => {
const fakeSocketChannel = channel();
const delay = 1;
return expectSaga(waitForSocketChannelEvent, fakeSocketChannel, delay)
.run()
.catch(error => {
expect(error).toEqual(new Error('Socket Event Timeout'));
});
});
The problem is that even when the test passes a console.error is throw:
console.error node_modules/redux-saga/lib/internal/utils.js:240
uncaught at waitForSocketChannelEvent
Error: Socket Event Timeout
at waitForSocketChannelEvent$ (/Users/hidalgofdz/development/yellowme/brandon/brandon-web/src/store/socket/socketSagas.js:48:13)
I don’t know if the problem is the function, the test, or both. Is throwing errors inside sagas a good practice? I would really appreciate any feedback.
About this issue
- Original URL
- State: open
- Created 7 years ago
- Reactions: 25
- Comments: 19 (3 by maintainers)
I also came to this problem. In saga.docs/error-handling is this example
but if your generator is written like this (again, taken from docs)
then in Jest the
iterator.throw(...causes unhandled error.You must give iterator chance to step into
try { }block withiterator.next()which moves execution to the first yield, then you canthrow()and it will be caught.like this
I too am trying to test a saga that I expect to throw an error. I can test this as follows:
However I still end up with the error output in my console as described by @hidalgofdz. I’ve tracked this down to the logError function in
redux-saga, which uses the optionaloptions.loggerfunction passed in torunSaga:https://github.com/redux-saga/redux-saga/blob/5f5cb8ab93f68d1e2adfe769e5cce99d7a4bc906/packages/core/src/internal/runSaga.js#L56-L62
Which means that the error logging could be disabled by adding a
logger: () => {}to the options passed torunSagafromexpectSaga. Any reason why this would be a bad idea? Given that the promise returned byrun()will reject on unhandled failure, unexpected errors will still get caught by the test runner/top level code.@cadichris I ran into the same problem. Here is my current workaround
In Jest, this works for me, nothing too special, see the function in expect()
you can also use this
jest.spyOn(global.console, 'error').mockImplementation(jest.fn())like thisit('should do something', () => { jest.spyOn(global.console, 'error').mockImplementation(jest.fn()) // your test here })mockImplementation will kind of hijack the thrown error and run it the way you want, i.e. do nothing while testingThanks for your answers ! @michaeltintiuc I tried your approach but I still see the Exception in the console. Maybe I missed something…are you able to run the test and have no console output ?
@euphocat That’s clever ! With your approach I don’t see the error in the console anymore. 🎉 I extracted a function, so that it can be reused for other tests. I’m not a big fan of the names I came up with…but I couldn’t do better 😄 Here is the extracted function :
The test will also fail if error is not thrown at all.
And I used it like so :
In combination with jest I can do something along the lines:
Hi everyone,
Thanks for the work on #211 and #217
However, I don’t understand how does #211 actually helps in suppressing the error message logged in the console.
Here is a sample code showing I’m not able to make the console error go away.
Production code :
Testing code :
Please note that the above test passes : it’s GREEN, but it produces the following output in console :
As you can see, I still see the Error’s message in the console output.
Exact stack trace
I’m using :
Am I missing something ?