I am having a bit of trouble properly testing my saga. The issue stems from the fact that when running the saga, the reducer is mounted at state: {...initialState}
whereas my saga select
effects are expecting the reducer mounted at state: {authentication: {...initialState}}
Due to this I am unable to fully test the reducer/saga combo, since the shape of the final state object is inconsistent with the actual shape of the store.
The saga being tested:
export default function* rootAuthenticationSaga() {
while (true) {
refreshToken = yield select((state: ApplicationRootState) => state.authentication.refreshToken);
... more code here
}
One of my test is as follows:
test('logs the user in if they provide a valid email and password', () => {
const mockRefreshPoller = createMockTask();
const initialState = {
accessToken: '',
refreshToken: '',
userId: '',
}
return expectSaga(rootAuthenticationSaga)
.withReducer(authenticationReducer, initialState)
.provide([
// some mock providers set up here
])
// ...more asserts here
.put(authenticationActions.saveTokens({accessToken: 'VALID_ACCESS_TOKEN', refreshToken: 'VALID_REFRESH_TOKEN'}))
.hasFinalState({
accessToken: 'VALID_ACCESS_TOKEN',
refreshToken: 'VALID_REFRESH_TOKEN',
userId: 'USER_ID',
})
.dispatch(authenticationActions.login.request({email: 'VALID_EMAIL', password: 'VALID_PASSWORD'}))
.run()
});
In the above test, the select()
fails as the correct path (with injection via withReducer) is at state.refreshToken
not state.authentication.refreshToken
If I inject the state via withState({authentication: {refreshToken, ...}})
then the select
works as expected, but all the reducer actions happen against the state root, with my final state having the (incorrect) shape:
{state:
authentication: {
refreshToken: '',
...
},
refreshToken: 'VALID_REFRESH_TOKEN',
...
}
The trick to this was to "mount" the reducer in question at the right "branch" by creating a
const reducerUnderTest = createReducer({
authentication: authenticationReducer,
})
and passing that into the withReducer(reducerUnderTest, {authentication: {...initialState}}
with the correct shape state.