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?
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.
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 .
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.
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'))
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With