In all the examples I've found everyone is using yield call()
, yield put()
, etc. on their sagas. Right now I have a saga that just executes a function without using yield call()
. This function is executed after a select effect and before a call effect (see code below for the service
variable. This function returns an instance of a class, it's not a network request or a promise.
The saga works fine, but I'm not sure how to test it like this. Using redux-sagas-test-plan
while having the effects works fine, but as soon as I remove the effect (which I remove from the .provide()
, the test fails.
Saga
export function* getDetails() {
try {
const config = yield select(getProperties());
const service = getService(config);
const data = yield call([service, service.getDetails]);
yield put(success(data));
} catch(e) {
yield put(failure());
}
}
Test
import { getDetails as detailsSaga } from '...';
const data = {};
it('should succeed getting details', async () => {
await expectSaga(detailsSaga)
.provide([
[select(getProperties), {}],
[call([serviceMock, serviceMock.getDetails]), data]
])
.put(success(data))
.dispatch(fetchDetails())
.silentRun();
});
The expected result from the test is tu have the success(data)
creator to execute but instead I get the failure()
creator as the actual value.
Expected
--------
{ '@@redux-saga/IO': true,
combinator: false,
type: 'PUT',
payload:
{ channel: undefined,
action:
{ type: 'FETCH_DETAILS_SUCCESS',
data: { } } } }
Actual:
------
1. { '@@redux-saga/IO': true,
combinator: false,
type: 'PUT',
payload:
{ channel: undefined,
action: { type: 'FETCH_DETAILS_FAILURE' } } }
Based on other examples I found, this was my solution:
import { call } from 'redux-saga-test-plan/matchers';
beforeEach(() => {
service = getService({});
data = { /* ... */ });
});
it('should succeed getting details', async () => {
await expectSaga(detailsSaga)
.provide([
[select(getProperties), {}],
[call.fn(service.getDetails), data]
])
.put(success(data))
.dispatch(fetchDetails())
.silentRun();
});
I have to use the call effect from redux-saga-test-plan/matchers
and create an actual instance returned by getService. For some reason a mock doesn't work here.
The details of why this works are not that clear to me, but I'm writing this answer just in case someone is trying to achieve this as well. Note: I agree with the other answer, that all functions should be called using yield call
but I've been asked not to do that here.