What is the point of unit testing reduction sag observers?

To get 100% coverage of my Saga files, I learn how to test observers.

I was looking for search queries, there are several answers on HOW to test observers. That is a saga that does takeEvery or takeLatest .

However, all testing methods seem to basically copy the implementation. So, what's the point of writing a test if it's the same?

Example:

 // saga.js import { delay } from 'redux-saga' import { takeEvery, call, put } from 'redux-saga/effects' import { FETCH_RESULTS, FETCH_COMPLETE } from './actions' import mockResults from './tests/results.mock' export function* fetchResults () { yield call(delay, 1000) yield put({ type: FETCH_COMPLETE, mockResults }) } export function* watchFetchResults () { yield takeEvery(FETCH_RESULTS, fetchResults) } 

Test Method 1:

 import { takeEvery } from 'redux-saga/effects' import { watchFetchResults, fetchResults } from '../sagas' import { FETCH_RESULTS } from '../actions' describe('watchFetchResults()', () => { const gen = watchFetchResults() // exactly the same as implementation const expected = takeEvery(FETCH_RESULTS, fetchResults) const actual = gen.next().value it('Should fire on FETCH_RESULTS', () => { expect(actual).toEqual(expected) }) }) 

Test Method 2: with an assistant, such as the Redaga Saga Test Plan
This is a different way of writing, but again, we basically do the same thing as the implementation.

 import testSaga from 'redux-saga-test-plan' import { watchFetchResults, fetchResults } from '../sagas' import { FETCH_RESULTS } from '../actions' it('fire on FETCH_RESULTS', () => { testSaga(watchFetchResults) .next() .takeEvery(FETCH_RESULTS, fetchResults) .finish() .isDone() }) 

Instead, I would just like to know if watchFestchResults all FETCH_RESULTS. Or even if it fires takeEvery() . No matter how it should be.

Or is this really a way to do this?

+7
unit-testing redux-saga
source share
2 answers

It seems that the purpose of testing is to achieve 100% testing coverage.

There are some things you can unit test, but this is doubtful if you need to.

It seems to me that this situation may be the best candidate for the integration test. Something that does not check just one method, but how several methods work together as a whole. Perhaps you could trigger an action that starts the reducer that uses your saga, and then check the repository for the change that was triggered? This would be much more meaningful than testing the saga alone.

+4
source share

I agree with John Meyer's answer that this is better for an integration test than for a unit test. This issue is the most popular on GitHub based on votes. I would recommend reading it.

One suggestion is to use the redux-saga-tester package created by the problem opener. It helps to create an initial state, run saga helpers (takeEvery, takeLatest), send messages that the saga listens to, monitor the status, retrieve the history of actions and listen to specific actions.

I use it with axios-mock-adapter , but there are some examples in the codebase using nock .

Saga

 import { takeLatest, call, put } from 'redux-saga/effects'; import { actions, types } from 'modules/review/reducer'; import * as api from 'api'; export function* requestReviews({ locale }) { const uri = `/reviews?filter[where][locale]=${locale}`; const response = yield call(api.get, uri); yield put(actions.receiveReviews(locale, response.data[0].services)); } // Saga Helper export default function* watchRequestReviews() { yield takeLatest(types.REVIEWS_REQUEST, requestReviews); } 

Jest Test Example

 import { takeLatest } from 'redux-saga/effects'; import { types } from 'modules/review/reducer'; import SagaTester from 'redux-saga-tester'; import MockAdapter from 'axios-mock-adapter'; import axios from 'axios'; import watchRequestReviews, { requestReviews } from '../reviews'; const mockAxios = new MockAdapter(axios); describe('(Saga) Reviews', () => { afterEach(() => { mockAxios.reset(); }); it('should received reviews', async () => { const services = [ { title: 'Title', description: 'Description', }, ]; const responseData = [{ id: '595bdb2204b1aa3a7b737165', services, }]; mockAxios.onGet('/api/reviews?filter[where][locale]=en').reply(200, responseData); // Start up the saga tester const sagaTester = new SagaTester({ initialState: { reviews: [] } }); sagaTester.start(watchRequestReviews); // Dispatch the event to start the saga sagaTester.dispatch({ type: types.REVIEWS_REQUEST, locale: 'en' }); // Hook into the success action await sagaTester.waitFor(types.REVIEWS_RECEIVE); expect(sagaTester.getLatestCalledAction()).toEqual({ type: types.REVIEWS_RECEIVE, payload: { en: services }, }); }); }); 
+2
source share

All Articles