如何用Jest为React组件的componentDidMount和componentDidUpdate编写单元测试
解决Chatlist组件Jest测试的PropType错误及覆盖不全问题
嘿,我来帮你搞定这两个问题!先从你遇到的id propType期望为字符串的错误说起,再聊聊怎么让测试覆盖完整组件生命周期。
一、PropType不匹配的核心原因
你在Chatlist里给子组件(WatsonMessageBox、ErrorMessageBox、StudentMessageBox)传递的id是数字类型的index,但这些子组件的propTypes里应该定义了id: React.PropTypes.string(或者新版的PropTypes.string),所以Jest会抛出类型不匹配的错误。
修复方案二选一:
方案1:修改子组件的PropType定义
如果子组件的id确实可以接受数字,把它们的propType改成数字类型:
// 以WatsonMessageBox为例 WatsonMessageBox.propTypes = { id: React.PropTypes.number, // 若使用React 15.5+,需换成import PropTypes from 'prop-types'后写PropTypes.number // 其他prop定义... };
方案2:在Chatlist里把id转为字符串
保持子组件的PropType为字符串,传递id时把数字转成字符串:
// 在Chatlist的render方法中修改三处子组件的id传递: // WatsonMessageBox部分 <WatsonMessageBox id={index.toString()} message={arg.chatText} isLOEO={isLOEO} label={arg.chatLabel} index={index + 10} showBar={this.props.messages.length - 1 > index} /> // ErrorMessageBox部分 <ErrorMessageBox id={index.toString()} message={arg.chatText} index={index + 10} /> // StudentMessageBox部分 <StudentMessageBox id={index.toString()} key={index} isError={arg.isRetry} retryAction={this.props.retryAction} retryMessage={this.props.retryMessage} message={arg.chatText} label={arg.chatLabel} index={index + 10} />
二、完善测试覆盖组件生命周期
你的现有测试还没覆盖componentDidMount和componentDidUpdate,下面给你补充实用的测试用例:
1. 测试componentDidMount
用mount(而非shallow)渲染组件,检查DOM元素的tabIndex是否设置正确:
test('componentDidMount sets correct tabIndex for scroll element', () => { const wrapper = mount(<Chatlist messages={mockMessages} />); const scrollChild = document.querySelector('.scrollDM').firstChild; expect(scrollChild.tabIndex).toBe(-1); });
2. 测试componentDidUpdate
模拟组件更新,验证滚动到底部的逻辑和样式修改是否生效:
test('componentDidUpdate triggers scroll to bottom and styles last message', () => { const wrapper = mount(<Chatlist messages={mockMessages} updateComponent={false} />); // 模拟scrollbars的scrollToBottom方法 wrapper.instance().refs.scrollbars.scrollToBottom = jest.fn(); // 更新组件,触发componentDidUpdate wrapper.setProps({ updateComponent: true }); // 验证滚动方法被调用 expect(wrapper.instance().refs.scrollbars.scrollToBottom).toHaveBeenCalled(); // 验证最后一条消息的样式修改 const lastMessageNode = wrapper.find('.scrollDM').children().last(); expect(lastMessageNode).toHaveStyle('border-radius: 6px'); expect(lastMessageNode).toHaveStyle('width: 11px'); expect(lastMessageNode.children().first()).toHaveStyle('background-color: #c4c4c4'); });
3. 覆盖不同消息类型的渲染
确保watson、err、student三种消息类型都能正确渲染对应子组件:
test('renders correct message component for each senderId', () => { const testMessages = [ { senderId: 'watson', chatText: 'Watson test msg', chatLabel: {} }, { senderId: 'err', chatText: 'Error test msg' }, { senderId: 'student', chatText: 'Student test msg' } ]; const wrapper = shallow(<Chatlist messages={testMessages} />); expect(wrapper.find(WatsonMessageBox)).toHaveLength(1); expect(wrapper.find(ErrorMessageBox)).toHaveLength(1); expect(wrapper.find(StudentMessageBox)).toHaveLength(1); });
三、其他注意事项
- 你的测试代码里
mockStudentMessages被截断了,记得补全完整的测试数据,避免测试报错 - 若使用React 15.5+,
React.PropTypes已迁移到独立的prop-types库,建议替换为import PropTypes from 'prop-types' - 可以用
jest.mock模拟jquery和react-custom-scrollbars,减少测试对真实DOM或第三方组件内部逻辑的依赖
内容的提问来源于stack exchange,提问作者user2119252
相关产品推荐
相关产品推荐

