Redux-saga select testing with conditional statement
Asked Answered
S

1

5

I created a saga that retrieves a value from the store with select and according to this value runs a statement or another:

const {id} = action.payload;
try {
  const cache = yield select(state => state.cache);
  if (cache[id]) {
    // Do something
  } else {
    // Do something else
} catch (e) {
  // errors
}

I tried to mock the store with react-mock-store :

import configureStore from 'redux-mock-store';
import createSagaMiddleware from 'redux-saga';
import { expect } from 'chai';
import { getCacheSaga } from '../../../src/js/sagas/cache-saga';
import { GET_CACHE } from '../../../src/js/actions/cache-actions';

const middlewares = [createSagaMiddleware()];
const mockStore = configureStore(middlewares);
mockStore({ cache: { foo: {} } });

describe('get cache saga', () => {
  describe('getCacheSaga', () => {
    it('retrieves data from cache', () => {
    const iterator = getFormSaga({
      payload: { id: 'foo' },
    });
    const cache = iterator.next();
    console.log(cache); // undefined
  });
});

but that does not work. Any ideas?

Successor answered 20/6, 2017 at 10:36 Comment(0)
C
8

Sagas only declare effects w/o actually performing one. That is basically why it can be test w/o mocking at all.

So you don't need to mock anything. Test effects descriptions.

expose you selector

// cache-selector

export default state => state.cache

Inside test

import getCache from './cache-selector'

describe('get cache saga', () => {
  describe('getCacheSaga', () => {
    it('retrieves data from cache', () => {
    const iterator = getFormSaga({
      payload: { id: 'foo' },
    });
    expect(iterator.next().value).to.be.deep.equal(select(getCache))

    // fake effect
    const fakeCache = { foo: 'bar'}
    const nextEffect = iterator.next(fakeCache)

    // next assertion

    expect(nextEffect.value).to.be.deep.equal(...)


  });
})

Long Read

Consider the following example

Suppose you need to test a function that does the following

function roll() {
  if(Math.random() > 0.5) {
    console.log('OK')
  } else {
    console.error('FAIL')
  }
}

How to test it? Simple answer would be mocking. And here you need to mock Math.random, console.log, console.error

With saga you could do it w/o mocking. First rewrite using declarative effects

function* rollSaga() {
  const random = yield call(Math.random)

  if(random > 0.5) {
     yield call(console.log, 'OK')
  } else {
     yield call(console.log, 'FAIL'
  }
}

Then test

it('should call Math.random', () => {
   const iter = rollSaga()

   expect(iter.next().value).to.be.deep.equal(call(Math.random))
})

it('should log OK if random is > 0.5', () => {
   const iter = rollSaga()

   iter.next() // call random

   expect(iter.next(0.6).value).to.be.deep.equal(call(console.log, 'OK'))
})

it('should show error if random is < 0.5', () => {
   const iter = rollSaga()

   iter.next() // call random

   expect(iter.next(0.4).value).to.be.deep.equal(call(console.error, 'FAIL'))
})
Chelseachelsey answered 20/6, 2017 at 11:4 Comment(2)
Thank you for your answer, that's less fuzzy now.Successor
Superb explanation. You can also use a library such as npmjs.com/package/redux-saga-testing for easier testing of sagas. (disclaimer: I wrote this lib)Endora

© 2022 - 2024 — McMap. All rights reserved.