redux-saga-test-plan expectSaga- 使用状态分支测试 reducer
redux-saga-test-plan expectSaga- Testing reducer with state branch
我在正确测试我的 saga 时遇到了一些麻烦。问题源于这样一个事实,即当 运行 saga 时,减速器安装在 state: {...initialState}
而我的 saga select
效果期望减速器安装在 state: {authentication: {...initialState}}
因此我无法完全测试 reducer/saga 组合,因为最终状态对象的形状与商店的实际形状不一致。
正在测试的传奇:
export default function* rootAuthenticationSaga() {
while (true) {
refreshToken = yield select((state: ApplicationRootState) => state.authentication.refreshToken);
... more code here
}
我的一个测试如下:
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()
});
在上面的测试中,select()
失败了,因为正确的路径(通过 withReducer 注入)在 state.refreshToken
而不是 state.authentication.refreshToken
如果我通过 withState({authentication: {refreshToken, ...}})
注入状态,那么 select
会按预期工作,但是所有 reducer 操作都是针对状态根发生的,我的最终状态具有(不正确的)形状:
{state:
authentication: {
refreshToken: '',
...
},
refreshToken: 'VALID_REFRESH_TOKEN',
...
}
这样做的诀窍是 "mount" 通过创建
右边 "branch" 的减速器
const reducerUnderTest = createReducer({
authentication: authenticationReducer,
})
并以正确的形状状态将其传递到 withReducer(reducerUnderTest, {authentication: {...initialState}}
。
我在正确测试我的 saga 时遇到了一些麻烦。问题源于这样一个事实,即当 运行 saga 时,减速器安装在 state: {...initialState}
而我的 saga select
效果期望减速器安装在 state: {authentication: {...initialState}}
因此我无法完全测试 reducer/saga 组合,因为最终状态对象的形状与商店的实际形状不一致。
正在测试的传奇:
export default function* rootAuthenticationSaga() {
while (true) {
refreshToken = yield select((state: ApplicationRootState) => state.authentication.refreshToken);
... more code here
}
我的一个测试如下:
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()
});
在上面的测试中,select()
失败了,因为正确的路径(通过 withReducer 注入)在 state.refreshToken
而不是 state.authentication.refreshToken
如果我通过 withState({authentication: {refreshToken, ...}})
注入状态,那么 select
会按预期工作,但是所有 reducer 操作都是针对状态根发生的,我的最终状态具有(不正确的)形状:
{state:
authentication: {
refreshToken: '',
...
},
refreshToken: 'VALID_REFRESH_TOKEN',
...
}
这样做的诀窍是 "mount" 通过创建
右边 "branch" 的减速器const reducerUnderTest = createReducer({
authentication: authenticationReducer,
})
并以正确的形状状态将其传递到 withReducer(reducerUnderTest, {authentication: {...initialState}}
。