Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux-saga select testing with conditional statement

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?

like image 844
untemps Avatar asked Jun 20 '17 10:06

untemps


People also ask

What is function * In Redux saga?

In Redux saga, yield is a built in function which allows to use generator functions sequentially. When used in Javascript, the generator functions will allow to yield all values from the nested functions.

Why is select method used in Redux saga?

a library that aims to make application side effects (i.e. asynchronous things like data fetching and impure things like accessing the browser cache) easier to manage. The select effect is just used to get a slice of the current Store's state .

How do I test a saga file?

There are two main ways to test Sagas: testing the saga generator function step-by-step or running the full saga and asserting the side effects.


1 Answers

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'))
})
like image 151
Yury Tarabanko Avatar answered Oct 21 '22 11:10

Yury Tarabanko