How to test Redux Saga with dependencies

Let’s think about an alternative approach to build your sagas.

How do your sagas look like?

Let’s take some common scenario — you have a form that updates a product/user/whatever via backend API. I assume you have something like this

What’s wrong with it?

This approach works well for a demo. But in real life things get complicated. In real life, you will have much more sagas and configureSaga function will grow a lot. Saga registration and management become uneasy but still, it’s not a big issue.

What about a better solution

If we don’t have dependencies we can go with a functional approach without any pain. But when we need dependencies it becomes a problem since we cannot effectively replace them with the instances that we can test. So what do we need? Right - Dependency Injection. Basically, approach #3 has it, we inject dependencies via function arguments. And the test works very well. The problem is it’s catastrophically uncomfortable to pass dependencies inside the action. What if we could pass dependencies separately? So we need some internal state inside the saga. Are you thinking the same thing as me? I’m thinking about classes.

  • we’ve added new function *register it should simplify watchers registration. I’ll tell about it in the next part of this article.
  • yield takeEvery(SAVE_PRODUCT, this.saveProduct());will return absolutely the same generator function as we had before but this time we can use backenApi and history that have been injected in the constructor.
  • now when we can inject dependencies we don’t have a problem with mocking and successfully resolve the problem that we had with approach #3.

How to configure sagas?

Wait! but how/where are you going to construct all your sagas and pass all required dependencies. That’s the right question. We have to build and register saga only once. Moreover, ISaga that we used above can help us simplify saga registration.

What do we have at the end of the day

  • easy saga testing with dependencies
  • pure unit test, we don’t need to integrate saga with anything. Easy to maintain, runs faster, use fewer resources
  • easy saga registration with ISaga. We can add many takeEvery inside one saga. SAVE_PRODUCT, REFRESH_PRODUCT
  • initiate dependencies only once. No more dozen of createBrowserHistory() in different parts for the app.

Enjoy turning complex systems into intelligible architectures chilling in my garden.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store