Jest+Enzyme测试React组件报错无法读取undefined的showPrev属性
错误原因
运行时抛出TypeError: Cannot read property 'showPrev' of undefined是多重代码问题共同导致的:
- 核心传参类型错误:组件入口第一行就直接对
actionButtonsManager做对象解构,提取showPrev、showNext等配置项,说明这个prop的预期类型是平面对象,但测试mock数据里错误地把配置对象包裹在数组中,同时shallow调用存在语法错误(缺少闭合括号),导致props解析异常,最终actionButtonsManager实际拿到undefined,解构时直接触发报错。 - 其余props不符合组件约定:
error传了布尔值false,但组件内部renderError方法会对error做对象解构提取错误信息,传原始值会触发后续解构报错currentFormType传了空数组,组件内部将其作为字符串做=== "update"判断,类型不匹配- 缺失必填prop
ffClient,组件内部会调用getFeatureFlagValue(ffClient, ...),不传会触发函数调用错误 customButtons传了空数组,组件判断customButtons !== null后会直接将其作为函数执行,传数组会触发"is not a function"报错- 没有mock组件依赖的
helpers工具模块、Notification、Spinner组件,shallow渲染时会因为找不到依赖抛出异常
修复方案
1. 修正mock props的格式和类型
去掉actionButtonsManager外层的数组包裹,将所有props调整为组件预期的类型,事件处理函数统一用jest.fn()模拟:
const defaultProps = { onDraft: jest.fn(), onCancel: jest.fn(), onPrev: jest.fn(), onNext: jest.fn(), onSubmit: jest.fn(), error: { // 按组件解构要求传对象结构 isError: false, errorMessage: "", errorFromWhere: "" }, currentFormType: "create", // 传字符串类型 ffClient: {}, // 传空对象占位即可 actionButtonsManager: { // 去掉外层[],直接传配置对象 showPrev: false, showNext: false, showDraft: false, showCancel: true, showSubmit: true, customButtons: null, // 不需要自定义按钮时传null,避免被误判为函数执行 disableNext: true, disableDraft: true, disableCancel: false, disableSubmit: false, draftLoading: true, showSpinner: false } };
2. 修复shallow调用的语法错误
补全shallow方法的闭合括号,规范JSX格式:
it("Action Buttons are rendered", () => { // 补全shallow的右括号 const wrapper = shallow(<ActionButtons {...defaultProps} />); expect(wrapper.find(".action-buttons-wrapper")).toExist(); });
3. 提前mock所有外部依赖
在测试文件顶部添加mock,避免渲染时找不到内部模块、第三方组件:
// mock工具方法 jest.mock("../../helpers", () => ({ get: jest.fn((_, __, defaultValue) => defaultValue), appConfig: {}, getFeatureFlagValue: jest.fn(() => false) })); // mock业务子组件 jest.mock("../../components/Notification/Notification", () => () => <div />); // mock第三方组件 jest.mock("@vmware-react/clarity/dist/spinner", () => ({ Spinner: () => <div /> }));
修复后完整可运行测试代码
import React from "react"; import { shallow } from "enzyme"; import ActionButtons from "./ActionButtons"; // 初始化mock jest.mock("../../helpers", () => ({ get: jest.fn((_, __, defaultValue) => defaultValue), appConfig: {}, getFeatureFlagValue: jest.fn(() => false) })); jest.mock("../../components/Notification/Notification", () => () => <div />); jest.mock("@vmware-react/clarity/dist/spinner", () => ({ Spinner: () => <div /> })); const defaultProps = { onDraft: jest.fn(), onCancel: jest.fn(), onPrev: jest.fn(), onNext: jest.fn(), onSubmit: jest.fn(), error: { isError: false, errorMessage: "", errorFromWhere: "" }, currentFormType: "create", ffClient: {}, actionButtonsManager: { showPrev: false, showNext: false, showDraft: false, showCancel: true, showSubmit: true, customButtons: null, disableNext: true, disableDraft: true, disableCancel: false, disableSubmit: false, draftLoading: true, showSpinner: false } }; describe("Action Buttons", () => { it("Action Buttons are rendered", () => { const wrapper = shallow(<ActionButtons {...defaultProps} />); expect(wrapper.find(".action-buttons-wrapper")).toExist(); }); });
后续如果要测试按钮显隐、点击逻辑、自定义按钮渲染等场景,只需要修改对应配置项的值,或者在单个用例中重写props即可。
内容的提问来源于stack exchange,提问作者Gareema
相关产品推荐
相关产品推荐

