[英]How to test a React component that dispatches a Redux / Thunk action
我正在为应该重定向到特定路径的组件编写集成测试,具体取决于来自异步(thunk)redux 操作的响应。
这是我的组件的简化版本:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
redirect: false
}
this.props.dispatch(asyncThunkAction())
.then( () => this.setState({redirec: true}) )
.catch( (err) => console.log('action failed') )
}
...
render() {
if (this.state.redirect) {
return <Redirect to='/whocares' />
}
...
}
}
function mapStateToProps(state) {
return {
...
};
}
export default connect(mapStateToProps)(MyComponent);
我想编写一个测试,断言组件重定向到预期的路径。
我正在使用这种技术来检查实际的重定向路径(它并不完美,但它不是这个问题的重点)。
我被卡住的地方是在 redux/thunk 操作之后 .then .then()
中的 state 更改。 因为它是 promise,重定向发生在我的expect
语句之后,所以我无法测试它。
这是我的测试的样子:
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
test('redirects after thunk action', () => {
const redirectUrl = '/whocares'
const data = {};
jest.mock('../actions');
act(() => {
ReactDOM.render(
<TestRouter
ComponentWithRedirection={<MyComponent store={mockStore(data)} />}
RedirectUrl={redirectUrl}
/>,
container);
});
expect(container.innerHTML).toEqual(
expect.stringContaining(redirectUrl)
)
})
我的 TestRouter 只是将预期的重定向 URL 打印到 DOM 中。 (查看上面的链接以获取有关此 hack 的完整说明。)因此,现在我的测试(正确地)识别了在 thunk 操作正在进行时出现的加载屏幕,而不是到达预期的路线。
我认为正确的方法是模拟来自asyncThunkAction
的响应,以便它返回具有匹配数据的已解析 promise,但到目前为止我还没有弄清楚如何做到这一点。 我按照手动模拟的 Jest 文档并创建了相应的模拟文件:
// __mocks__/actions.js
const asyncThunkAction = function(){
return Promise.resolve({foo: 'bar'});
};
export { asyncThunkAction };
...但我的测试仍然“看到”加载 state。 我什至不认为它正在查看我的模拟文件/动作。
这样做的正确方法是什么?
这是我如何让这个工作的“食谱”......
使用测试库/反应...
import { render, fireEvent, waitForElement, act } from '@testing-library/react';
(为此建议向@tmahle +1)
通过创建一个“手动模拟”来模拟 axios(或者在我的情况下是包装它的 API 模块),这基本上需要在包含同名文件的真实文件旁边创建一个__mocks__
目录。 然后导出一个 object ,其属性替换get
方法(或您的代码使用的任何一个)。
//__mocks__/myclient.js
export default {
get: jest.fn(() => Promise.resolve({ data: {} }))
};
即使你没有在测试中调用模拟代码,你也需要在测试文件中import
它......
import myapi from '../api/myapi';
jest.mock('../api/myai');
您可以像这样模拟来自模拟的 API 调用的响应:
myapi.get.mockResolvedValueOnce({
data: { foo: "bar" },
});
我在这部分有点模糊......即使模拟的 API 请求立即响应已解决的 promise,您可能需要wait
它写入expects
const { getByText, getByTestId, container } = render(<MyComponent />);
await wait(() => getByText('Some text that appears after the '));
expect(container.innerHTML).toEqual('whatever');
所有这些都在各种文档和 SO 问题中“存在”……但我花了很长时间才将它们拼凑在一起。 希望这可以节省您的时间。
诚然,这是对您的问题的一个侧面回答,但我建议尝试测试库及其体现的理想,特别是对于集成测试。
它在 DOM 和 React 两种风格中都可用,使用哪一种可能取决于你的重定向发生在什么抽象级别:
https://github.com/testing-library/dom-testing-library https://github.com/testing-library/react-testing-library
使用这种范例,您不会试图断言用户被重定向到正确的路径,而是在他们被重定向后正确的东西在屏幕上。 您还将 mocking 限制为绝对必需品(如果您正在进行真正的集成测试,可能没有或只有浏览器 API 是您的测试环境无法模拟的)。
这里的整体方法可能会让你的 mocking 输出更少,并且可能渲染应用程序的更大部分。 可以在这里找到一个可能有用的示例: https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples/tree/master/?fontsize=14&module=%2Fsrc%2F__tests__%2Freact -router.js&previewwindow=测试
因为这种方法中的 mocking 较少,所以如何实现这一点的细节可能来自您给出的示例的 scope 之外,但上面的示例链接应该对入门有很大帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.