Dependency injection in redux-observable
Imagine that you have following situation: your calls to external api are using helper modules where all request logic lies. For instance, you have
backendService
:
export const makeRequest = async () => return fetch.get('http://www.some_api.com');
In your epic you use this as follows:
import * as backendService from "./backendService";
const fetchBackendServiceEpic = (action$, store) =>
action$
.filter(isActionOf(YOUR_TRIGGER_ACTION))
.switchMap((action) => Observable.from(backendService.makeRequest()))
.mapTo(YOUR_SUCCESS_ACTION)
.catch((err) => Observable.of(YOUR_ERROR_ACTION));
Everything seems fine but to test this epic you have to mock whole API request to http://www.some_api.com
using for instance nock . Your test starts to get a little bit heavy to write:
describe("fetchBackendServiceEpic", () => {
it.should("fetch service", () => {
const mockStore = configureMockStore();
nock(`http://www.some_api.com`).get().reply(200, {});
return rootEpic(ActionsObservable.from(YOUR_TRIGGER_ACTION), mockStore)
.toArray()
.toPromise()
.then((actions) => {
expect(actions).toEqual([YOUR_TRIGGER_ACTION, YOUR_SUCCESS_ACTION]);
});
});
});
Can you do better?
Yes, using dependency injection. Your epic is depended on backendService
. How can you inject it to your epic? The actual way of doing this is in the documentation : Injecting Dependencies Into Epics · redux-observable. Thanks to that you have your epic with dependency injected:
const fetchBackendServiceEpic = (action$, store, { makeRequest }) =>
action$
.filter(isActionOf(YOUR_TRIGGER_ACTION))
.switchMap((action) => Observable.from(backendService.makeRequest()))
.mapTo(YOUR_SUCCESS_ACTION)
.catch((err) => Observable.of(YOUR_ERROR_ACTION));
To test it you need:
describe("fetchBackendServiceEpic", () => {
it.should("fetch service", () => {
const dependencies = { makeRequest: jest.fn().mockReturnValue([{}]) };
fetchBackendServiceEpic(YOUR_TRIGGER_ACTION, (store = null), dependencies)
.toArray()
.subscribe((actions) => {
expect(actions).toEqual([YOUR_TRIGGER_ACTIONS, YOUR_SUCCESS_ACTION]);
});
});
});
As you see here there is injecting dependency with your desired return value - you are testing logic of your epics and if proper actions are dispatched of your TRIGGER_ACTION
.
Summary
As you can see dependency injection in epics can be a powerful way to ease your testing of epics.