When I run my saga via tests, it doesn't find the state when using yield select. When I run it through the application, it works fine.
Saga:
export function *quitTimer() {
const pomodoro = yield select(selectors.pomodoroSelector);
const state = yield select();
console.log(state); --> UNDEFINED
console.log(pomodoro); --> UNDEFINED
// if (pomodoro) {
// pomodoro.timer.quit();
// }
yield call(pomodoro.timer.quit)
yield put(actions.onPomodoroQuit(pomodoro));
}
Test:
describe('Home sagas', () => {
it('quitTimer Saga test', function (done) {
const generator = sagas.quitTimer(getState);
let next = generator.next();
expect(next.value).toEqual(select(selectors.pomodoroSelector));
next = generator.next();
expect(next.value).toEqual(select());
// TODO: figure out how to test:
next = generator.next();
expect(next.value).toEqual(select(pomodoro.timer.quit));
next = generator.next();
expect(next.value).toEqual(put(actions.onPomodoroQuit(pomodoro)));
done();
});
});
For whatever reason, pomodoro is coming back undefined from state only on the tests, so I'm getting the error:
1) Home sagas quitTimer Saga test:
TypeError: Cannot read property 'timer' of undefined
I can, of course, wrap the call in an if statement, but I think that should be unnecessary.
I've looked over all the examples, and I can't seem to figure out what I'm doing wrong.
Thanks!
Effects are purely declarative, so there is not way for them to have "effect" if you don't run a saga connecting it to a store. In this kind of test, you need to manually mock the returned values. Try:
it('quitTimer Saga test', function (done) {
// This `getState` does not seem to serve any purpose
const generator = sagas.quitTimer(getState);
let next = generator.next();
expect(next.value).toEqual(select(selectors.pomodoroSelector));
next = generator.next(yourExpectedResponseForTheSelectEffect);
// ...
I'm wondering if you got confused by this example that also uses an ignored getState argument.
@jrvidal - Yeah, I definitely saw that the getState was unused... I left mine in there (for no particular reason).
I didn't realize that I needed to send generator.next(THE_EXPECTED_VALUE).
Here's what I ended up with:
saga
export function *quitTimer() {
const pomodoro = yield select(selectors.pomodoroSelector);
yield call(pomodoro.timer.quit)
yield put(actions.onPomodoroQuit(pomodoro));
}
test:
it('quitTimer Saga test', function (done) {
const generator = sagas.quitTimer();
let next = generator.next();
expect(next.value).toEqual(select(selectors.pomodoroSelector));
next = generator.next(getState().pomodoro);
expect(next.value).toEqual(call(pomodoro.timer.quit));
next = generator.next();
expect(next.value).toEqual(put(actions.onPomodoroQuit(pomodoro)));
done();
});
And it works. Thanks @jrvidal !
We can do like this
Saga Generator function
export function* getAuthToken(action) {
try {
const authToken = yield select(makeSelectAuthToken());
} catch (errObj) {
}
}
Test Case
import { runSaga } from 'redux-saga'
const fakeStore = {
getState: () => ({ authReducer: { auth: 'test' } }),
dispatch: (action) => dispatchedActions.push(action)
}
await runSaga(fakeStore, getAuthToken, {
payload: {}
}).done;
expect case you can write here below this
Most helpful comment
@jrvidal - Yeah, I definitely saw that the
getStatewas unused... I left mine in there (for no particular reason).I didn't realize that I needed to send
generator.next(THE_EXPECTED_VALUE).Here's what I ended up with:
saga
test:
And it works. Thanks @jrvidal !