使用Jest和Enzyme测试React Redux应用Login组件报错如何解决
错误原因及修复方案
核心错误点
- 渲染方法使用错误:用
shallow渲染包裹了Provider的组件时,shallow只会渲染Provider本身,不会向下渲染内部的Login组件,所以查找的元素全部不存在,自然返回false。 - 模拟store属性缺失:
mapStateToProps里用到了isLoggedIn、role、globalmessage、authToken、loggedUserInfo这些属性,但你初始化mock store的时候只传了email和password,会导致组件渲染异常。 - 选择器写错:Email对应的Field组件type属性是
text不是email(查看Login.js代码可确认<Field as={TextField} label="Email" ... type="text" name="email" />),用Field[type='email']无法匹配到目标元素。 - 依赖缺失:组件用到了
useHistory,测试环境没有路由上下文,需要先mock这个hook避免报错。
修复后的完整测试代码
import { mount } from "enzyme"; import Login from "../Login"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; // mock react-router的useHistory jest.mock('react-router', () => ({ ...jest.requireActual('react-router'), useHistory: () => ({ push: jest.fn() }) })) const mockStore = configureStore([]); describe("Login Component", () => { let store; let jsx; beforeEach(() => { // 补全login state所有必填属性 store = mockStore({ login: { email: "", password: "", isLoggedIn: false, role: "", globalmessage: "", authToken: "", loggedUserInfo: { isActive: false } } }); jsx = ( <Provider store={store}> <Login /> </Provider> ); }); it("should render an email input tag", () => { const wrapper = mount(jsx); // 用name属性匹配更精准,不会受type属性修改影响 expect(wrapper.find("Field[name='email']").exists()).toBe(true); }); it("should render a password input tag", () => { const wrapper = mount(jsx); expect(wrapper.find('Field[name="password"]').exists()).toBe(true); }); it("should render a submit button", () => { const wrapper = mount(jsx); expect(wrapper.find('Button[type="submit"]').exists()).toBe(true); }); });
可选优化:轻量单元测试方案
如果只测试组件本身的渲染逻辑,不需要耦合Redux,可以单独导出未被connect包裹的原始Login组件,不用配置mock store:
- 在Login.js末尾新增导出原始组件:
export const RawLogin = Login; // 新增导出 let hof = connect(mapStatetoProps, mapDispatchToProps); export default hof(Login);
- 测试代码可以简化为:
import { shallow } from "enzyme"; import { RawLogin } from "../Login"; jest.mock('react-router', () => ({ ...jest.requireActual('react-router'), useHistory: () => ({ push: jest.fn() }) })) describe("Login Component", () => { const mockProps = { isLoggedIn: false, role: "", globalmessage: "", authToken: "", currentUser: { isActive: false }, login: jest.fn(), flashNotification: jest.fn() } it("should render an email input tag", () => { const wrapper = shallow(<RawLogin {...mockProps} />); expect(wrapper.find("Field[name='email']").exists()).toBe(true); }); // 其余用例同理编写即可 });
内容的提问来源于stack exchange,提问作者pooja thakur
相关产品推荐
相关产品推荐

