如何测试React useEffect钩子内调用的react-router push方法参数正确性
测试代码存在的3个核心问题
- 未实际执行组件渲染:你只声明了
render函数,没有调用它,组件从未初始化,自然不会触发useEffect逻辑
- 未实际执行组件渲染:你只声明了
- 测试的是高阶组件包裹后的实例:你默认导出的组件是经过
withRouter、aCustomHigherOrderC两层HOC包裹后的产物,shallow渲染只会渲染最外层的HOC容器,不会触发内部真实MyComponent的逻辑
- 测试的是高阶组件包裹后的实例:你默认导出的组件是经过
- 断言参数与实际传参不匹配:组件内
push方法接收的是一个包含pathname、search属性的对象,你的断言里传入的是拼接后的字符串,就算push被触发也会断言失败
- 断言参数与实际传参不匹配:组件内
正确测试方案
第一步:修改组件导出,暴露未被HOC包裹的原始组件
给业务组件增加命名导出,测试时直接测原始组件即可,HOC的逻辑可以单独验证,不需要耦合在组件单测里:
import React from 'react'; import { compose } from 'redux'; import { withRouter } from 'react-router'; // 增加命名导出,专门用于测试 export const MyComponent = ({ router: { push, location }, }) => { const version = 'v2'; React.useEffect(() => { push({ pathname: `/${version}/new_path`, search: location.search ? location.search: '', }); }, []); return <div>Sample div text</div> }; const higherOrder = compose( withRouter, aCustomHigherOrderC, ); export default higherOrder(MyComponent);
第二步:修改测试代码
import React from 'react'; import { shallow } from 'enzyme'; // 导入未被HOC包裹的原始组件 import { MyComponent } from '../src/components/MyComponent'; const props = { router: { push: jest.fn(), location: { search: '?param=1', }, }, }; describe('MyComponent component tests', () => { it('should push correct route when mounted', () => { // 直接渲染组件 shallow(<MyComponent {...props} />); // 断言参数和组件内实际传参结构一致 expect(props.router.push).toHaveBeenCalledWith({ pathname: '/v2/new_path', search: '?param=1' }); // 也可以额外验证拼接后的完整路径 const calledParams = props.router.push.mock.calls[0][0]; expect(`${calledParams.pathname}${calledParams.search}`).toBe('/v2/new_path?param=1'); }); });
补充说明
如果你的项目要求必须测试经过HOC包裹的默认导出组件,可以把shallow改成mount完整渲染整个组件树,同时要给withRouter提供外层的Router上下文,不过这种方式会增加单测复杂度,更推荐直接测试原始组件的逻辑。
内容的提问来源于stack exchange,提问作者stacky
相关产品推荐
相关产品推荐

