我正在为一个组件编写集成测试,该组件应该根据异步(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);
我想编写一个测试来断言组件已重定向到预期路径。
我正在使用this technique用于检查实际的重定向路径(它并不完美,但不是这个问题的重点)。
我陷入困境的地方是 redux/thunk 操作之后 .then()
中的状态更改。因为这是一个 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 中。 (查看上面的链接以获取此黑客攻击的完整说明。)因此,现在我的测试(正确)识别了 thunk 操作正在进行时出现的加载屏幕,而不是到达预期的路线。
我认为执行此操作的正确方法是模拟来自asyncThunkAction
的响应,以便它返回具有匹配数据的已解决的 promise ,但到目前为止我还没有能够弄清楚如何做到这一点。我按照 manual mocks 上的 Jest 文档进行操作并创建了相应的模拟文件:
// __mocks__/actions.js
const asyncThunkAction = function(){
return Promise.resolve({foo: 'bar'});
};
export { asyncThunkAction };
...但我的测试仍然“看到”加载状态。我什至不认为它正在查看我的模拟文件/操作。
执行此操作的正确方法是什么?
最佳答案
这是我如何让它发挥作用的“秘诀”......
使用testing-library/react ...
import { render, fireEvent, waitForElement, act } from '@testing-library/react';
(对此建议+1 给@tmahle)
通过创建一个“manual mock”来模拟axios(或者在我的例子中是包装它的API模块),这基本上需要创建一个__mocks__
包含同名文件的实际文件旁边的目录。然后导出一个对象,其属性替换 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');
所有这些都在各种文档和问题中“存在”......但我花了很长时间才将它们拼凑在一起。希望这可以节省您的时间。
关于javascript - 如何测试调度 Redux/Thunk 操作的 React 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58808887/