Search code examples
javascriptreduxredux-sagaredux-saga-test-plan

How to test selector function with redux-saga-test-plan


I am testing my redux-saga-flow, and I have an issue with testing selector method with select.

Selector

const selector = (state) => {
   console.log("selector");
   return data;
}

Redux saga flow

export function* testedSagaFlow() {
  const data = yield select(selector);
  if (!data) {
    return;
  }
  yield put (otherAction)
  ...
}

Test for flow

test("Get data from store", () => {
  return expectSaga(testedSagaFlow)
  .provide([[mathchers.select.selector(selector), null]])
  .select(selector)
  .not.put(otherAction)
  .run()
})

After running a test, a do not have console.log("selector"); and also this line of code did not covered by test.

How can I test a selectors?

The same does not work with unit test.

test("Unit test flow", () => {
   const saga = testSaga(testedSagaFlow);
   saga
    .next()
    .select(selector)
    .next(null)
    .isDone()
})

Solution

  • "redux-saga-test-plan": "^4.0.1".

    Option 1. Use withState:

    For static state, you can just use the withState method to allow select effects to work.

    Option 2. Use static provider

    You can provide mock values in a terse manner via static providers. Pass in an array of tuple pairs (array pairs) into the provide method. For each pair, the first element should be a matcher for matching the effect and the second effect should be the mock value you want to provide.

    E.g.

    saga.ts:

    import { put, select } from 'redux-saga/effects';
    
    const otherAction = { type: 'OTHER_ACTION' };
    
    export const selector = (state) => {
      console.log('selector');
      return state.data;
    };
    
    export function* testedSagaFlow() {
      const data = yield select(selector);
      if (!data) {
        return;
      }
      yield put(otherAction);
    }
    

    saga.test.ts:

    import { expectSaga } from 'redux-saga-test-plan';
    import { select } from 'redux-saga/effects';
    import { selector, testedSagaFlow } from './saga';
    
    describe('70199170', () => {
      test('should dispatch other action', () => {
        const state = { data: true };
        return expectSaga(testedSagaFlow).withState(state).put({ type: 'OTHER_ACTION' }).run();
      });
    
      test('should return if data is nil', () => {
        const state = { data: null };
        return expectSaga(testedSagaFlow).withState(state).not.put({ type: 'OTHER_ACTION' }).run();
      });
    });
    
    describe('70199170 - use provider', () => {
      test('should dispatch other action', () => {
        return expectSaga(testedSagaFlow)
          .provide([[select(selector), true]])
          .put({ type: 'OTHER_ACTION' })
          .run();
      });
    
      test('should return if data is nil', () => {
        return expectSaga(testedSagaFlow)
          .provide([[select(selector), null]])
          .not.put({ type: 'OTHER_ACTION' })
          .run();
      });
    });
    

    Test result:

     PASS   redux-saga-examples  packages/redux-saga-examples/src/stackoverflow/70199170/saga.test.ts
      70199170
        ✓ should dispatch other action (30 ms)
        ✓ should return if data is nil (4 ms)
      70199170 - use provider
        ✓ should dispatch other action (2 ms)
        ✓ should return if data is nil (3 ms)
    
      console.log
        selector
    
          at selector (packages/redux-saga-examples/src/stackoverflow/70199170/saga.ts:6:11)
    
      console.log
        selector
    
          at selector (packages/redux-saga-examples/src/stackoverflow/70199170/saga.ts:6:11)
    
    Test Suites: 1 passed, 1 total
    Tests:       4 passed, 4 total
    Snapshots:   0 total
    Time:        2.934 s, estimated 3 s
    Ran all test suites related to changed files.