如何用Jest和Enzyme测试含document.getElementByClassName的React componentDidMount
React 16 + Jest/Enzyme 测试 componentDidMount 按钮样式修改失败的解决建议
问题背景
组件的componentDidMount逻辑中直接操作真实DOM修改按钮样式:
componentDidMount() { if (this.props.isSubmissionComplete) { window.location.href = process.env.REACT_APP_BASE_PATH; } if (document.getElementsByClassName("continue-button")[0]) { document .getElementsByClassName("continue-button")[0] .classList.add("hidden"); } if (document.getElementsByClassName("back-button")[0]) { document .getElementsByClassName("back-button")[0] .classList.remove("offset-sm-1"); } //Sets the applicable coverages to the state for use in the post submission pages var coverageList = this.renderCoverageList(); this.props.updateApplicableCoverages(coverageList); }
测试用例尝试通过Enzyme检查样式,但断言失败:
let wrapper; beforeEach(() => { wrapper = mount( <FraudStatement/> ); }); it("should hide the continue button if it exists", () => { expect(wrapper.find(".continue-button").hasClass("hidden")).toBe(true); });
错误信息:
Error: expect(received).toBe(expected) // Object.is equality Expected: true Received: false Jest
解决建议
1. 问题核心:DOM操作的上下文不一致
你的测试用例通过Enzyme的wrapper检查虚拟DOM,但组件逻辑直接操作真实浏览器DOM,两者状态不同步,导致Enzyme无法捕捉到样式变化。
2. 推荐修复:改用React数据流控制样式(符合React设计模式)
放弃直接操作DOM,改用组件状态或Props控制样式,让渲染逻辑完全由React管理:
// 组件内部修改 state = { shouldHideContinueBtn: false }; componentDidMount() { // ...其他逻辑 this.setState({ shouldHideContinueBtn: true }); } render() { return ( <button className={`continue-button ${this.state.shouldHideContinueBtn ? 'hidden' : ''}`} > Continue </button> ); }
对应的测试用例可以直接检查Enzyme虚拟DOM的类名:
it("should hide the continue button after mount", () => { expect(wrapper.find(".continue-button").hasClass("hidden")).toBe(true); });
3. 临时修复:同步真实DOM与Enzyme(不推荐长期使用)
如果暂时无法修改组件逻辑,可在测试中模拟真实DOM环境,并直接检查真实DOM的状态:
it("should hide the continue button if it exists", () => { // 先在真实DOM中添加目标按钮 const continueBtn = document.createElement('button'); continueBtn.className = 'continue-button'; document.body.appendChild(continueBtn); // 重新挂载组件触发componentDidMount wrapper = mount(<FraudStatement/>); // 直接检查真实DOM中的按钮样式 expect(document.querySelector('.continue-button').classList.contains('hidden')).toBe(true); // 测试后清理DOM document.body.removeChild(continueBtn); });
4. 额外优化:隔离测试依赖
测试时需要Mock外部依赖,避免无关逻辑干扰:
beforeEach(() => { // Mock props中的回调函数 const mockUpdateApplicableCoverages = jest.fn(); // 明确传入props,避免默认值触发跳转逻辑 wrapper = mount( <FraudStatement isSubmissionComplete={false} updateApplicableCoverages={mockUpdateApplicableCoverages} /> ); });
内容的提问来源于stack exchange,提问作者Tapesh Patel
相关产品推荐
相关产品推荐

