为什么 redux-mock-store 不显示在 catch promises 中调度的动作?
Why does redux-mock-store don't show an action dispatched in catch promises?
题主问题我想的很烂,不好意思。
我的问题:
我正在按照建议对我的异步 redux 操作进行单元测试 in the docs。我使用 nock
模拟 API 调用,并使用 redux-mock-store
检查已分派的操作。到目前为止效果很好,但我有一个测试失败了,尽管它显然确实有效。调度的操作既不会出现在 store.getActions()
返回的数组中,也不会在 store.getState()
中更改状态。我确信它确实发生了,因为我可以在手动测试时看到它并使用 Redux Dev Tools 观察它。
这个动作调度中唯一不同的是它在另一个承诺的捕获中被调用。 (我知道这听起来很混乱,看看代码就知道了!)
我的代码是什么样的:
动作:
export const login = (email, password) => {
return dispatch => {
dispatch(requestSession());
return httpPost(sessionUrl, {
session: {
email,
password
}
})
.then(data => {
dispatch(setUser(data.user));
dispatch(push('/admin'));
})
.catch(error => {
error.response.json()
.then(data => {
dispatch(setError(data.error))
})
});
};
}
此 httpPost
方法只是 fetch
的包装器,如果状态代码不在 200-299 范围内则抛出该方法,并且如果它已经将 json 解析为一个对象不会失败。如果它看起来相关,我可以在这里添加它,但我不想让它比现在更长。
没有出现的动作是dispatch(setError(data.error))
。
测试:
it('should create a SET_SESSION_ERROR action', () => {
nock(/example\.com/)
.post(sessionPath, {
session: {
email: fakeUser.email,
password: ''
}
})
.reply(422, {
error: "Invalid email or password"
})
const store = mockStore({
session: {
isFetching: false,
user: null,
error: null
}
});
return store.dispatch(actions.login(
fakeUser.email,
""))
.then(() => {
expect(store.getActions()).toInclude({
type: 'SET_SESSION_ERROR',
error: 'Invalid email or password'
})
})
});
感谢阅读。
编辑:
setError
动作:
const setError = (error) => ({
type: 'SET_SESSION_ERROR',
error,
});
httpPost
方法:
export const httpPost = (url, data) => (
fetch(url, {
method: 'POST',
headers: createHeaders(),
body: JSON.stringify(data),
})
.then(checkStatus)
.then(response => response.json())
);
const checkStatus = (response) => {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
};
因为您在 catch 方法中使用嵌套异步函数 - 您需要 return 承诺:
.catch(error => {
return error.response.json()
.then(data => {
dispatch(setError(data.error))
})
});
否则,dispatch 将在您断言后调用。
查看原始示例:
https://jsfiddle.net/d5fynntw/ - 没有 returning
https://jsfiddle.net/9b1z73xs/ - 随着 returning
题主问题我想的很烂,不好意思。
我的问题:
我正在按照建议对我的异步 redux 操作进行单元测试 in the docs。我使用 nock
模拟 API 调用,并使用 redux-mock-store
检查已分派的操作。到目前为止效果很好,但我有一个测试失败了,尽管它显然确实有效。调度的操作既不会出现在 store.getActions()
返回的数组中,也不会在 store.getState()
中更改状态。我确信它确实发生了,因为我可以在手动测试时看到它并使用 Redux Dev Tools 观察它。
这个动作调度中唯一不同的是它在另一个承诺的捕获中被调用。 (我知道这听起来很混乱,看看代码就知道了!)
我的代码是什么样的:
动作:
export const login = (email, password) => {
return dispatch => {
dispatch(requestSession());
return httpPost(sessionUrl, {
session: {
email,
password
}
})
.then(data => {
dispatch(setUser(data.user));
dispatch(push('/admin'));
})
.catch(error => {
error.response.json()
.then(data => {
dispatch(setError(data.error))
})
});
};
}
此 httpPost
方法只是 fetch
的包装器,如果状态代码不在 200-299 范围内则抛出该方法,并且如果它已经将 json 解析为一个对象不会失败。如果它看起来相关,我可以在这里添加它,但我不想让它比现在更长。
没有出现的动作是dispatch(setError(data.error))
。
测试:
it('should create a SET_SESSION_ERROR action', () => {
nock(/example\.com/)
.post(sessionPath, {
session: {
email: fakeUser.email,
password: ''
}
})
.reply(422, {
error: "Invalid email or password"
})
const store = mockStore({
session: {
isFetching: false,
user: null,
error: null
}
});
return store.dispatch(actions.login(
fakeUser.email,
""))
.then(() => {
expect(store.getActions()).toInclude({
type: 'SET_SESSION_ERROR',
error: 'Invalid email or password'
})
})
});
感谢阅读。
编辑:
setError
动作:
const setError = (error) => ({
type: 'SET_SESSION_ERROR',
error,
});
httpPost
方法:
export const httpPost = (url, data) => (
fetch(url, {
method: 'POST',
headers: createHeaders(),
body: JSON.stringify(data),
})
.then(checkStatus)
.then(response => response.json())
);
const checkStatus = (response) => {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
};
因为您在 catch 方法中使用嵌套异步函数 - 您需要 return 承诺:
.catch(error => {
return error.response.json()
.then(data => {
dispatch(setError(data.error))
})
});
否则,dispatch 将在您断言后调用。
查看原始示例:
https://jsfiddle.net/d5fynntw/ - 没有 returning
https://jsfiddle.net/9b1z73xs/ - 随着 returning