使用Jest编写React SelectLanguage组件单元测试后两个用例失败如何解决
问题原因及修复方案
核心错误点
- Select组件mock传参错误:你mock的Select组件触发onSelect时没有传递
{value: 选项值}格式的参数,导致组件内handleSelect解构value失败,后续逻辑全部异常。 - 事件追踪的spy对象错误:第三个用例你给传入的
handlers.onSelect打了spy,却用它断言eventTracker.track的调用,完全搞混了监听对象。且你没有mockeventMetricsMap所属的helpers模块,也没有给eventTracker.track打spy。 - events mock层级错误:你mock的events对象多套了一层dummyEvents,导致组件内取
events.switchBuildingBlickLanguage为undefined,注意组件内事件名拼写是switchBuildingBlickLanguage(注意是Blick不是Block,确认下是否是组件笔误,这里以组件代码为准)。
修复后的测试代码
import expect from 'expect' import { fireEvent, render } from '@testing-library/react' import SelectLanguage from './select-language' // 先mock helpers模块的eventMetricsMap jest.mock('./helpers', () => ({ eventMetricsMap: { buildingblocks: { from: 'building blocks' } } })) // 正确mock event-tracker,给track打spy const trackSpy = jest.fn() const mockEventName = 'switch building blocks language' jest.mock( 'cm/common/event-tracker', () => ({ eventTracker: { track: trackSpy }, events: { // 注意和组件内的事件名保持一致 switchBuildingBlickLanguage: mockEventName } }) ) const languages = [ { name: 'English', value: 'EN', }, { name: 'Nederlands', value: 'NL' } ] // 修复Select组件mock,点击时传递正确的参数格式 jest.mock( 'cm/components/common/select', () => ({ items, handlers }) => { return (<div className="dropdown"> <div className="dropdown__menu"> {items.map((item) => ( <div key={item.value} className="dropdown__item" onClick={() => handlers.onSelect({ value: item.value })} >{item.name}</div> ))} </div> </div>) } ) const containerPath = '.dropdown' const itemPath = '.dropdown__item' describe('SelectLanguage component', () => { // 每次测试前清空spy调用记录 beforeEach(() => { jest.clearAllMocks() }) it('renders in the document', () => { const { container } = render( <SelectLanguage languages={languages} handlers={{onSelect: jest.fn()}}/> ) const $container = container.querySelector(containerPath) expect($container).toBeTruthy() }) it('renders items', () => { const { container } = render( <SelectLanguage languages={languages} handlers={{onSelect: jest.fn()}}/> ) const $dropdownItems = container.querySelectorAll(itemPath) expect([ ...$dropdownItems ].length).toBe(2) }) it('track select open click', () => { const { container } = render( <SelectLanguage selectedLanguage={{ value: 'EN' }} languages={languages} handlers={{ onSelect: jest.fn() }} /> ) const $dropdownItem = container.querySelector(itemPath) fireEvent.click($dropdownItem) // 断言eventTracker.track的调用 expect(trackSpy).toHaveBeenCalledWith( mockEventName, { from: 'building blocks', language: 'en' } ) }) it('handles action', () => { const spyFn = jest.fn() const { container } = render( <SelectLanguage selectedLanguage={{ value: 'EN' }} languages={languages} handlers={{ onSelect: spyFn }} /> ) const $dropdownItem = container.querySelector(itemPath) fireEvent.click($dropdownItem) expect(spyFn).toHaveBeenCalledWith('EN') }) })
额外注意点
- 组件内useEffect的依赖数组为空,且没有卸载时取消监听hashHistory的逻辑,可能导致内存泄漏,建议补充
unlisten的返回清除逻辑。 - 组件内事件名
switchBuildingBlickLanguage大概率是拼写错误(Blick应该是Block),建议确认修改避免线上埋点丢失。
内容的提问来源于stack exchange,提问作者karo-s
相关产品推荐
相关产品推荐

