如何在单元测试中Mock react-leaflet提供的useMapEvents?解决‘初始化前无法访问map’的报错问题
如何在单元测试中Mock react-leaflet提供的useMapEvents?解决‘初始化前无法访问map’的报错问题
嘿,我之前也踩过这个坑,咱们来一步步搞定这个问题!
首先得搞清楚为啥会报「初始化前无法访问map」这个错:你组件里的map变量是useMapEvents的返回值,而click回调里直接引用了这个变量。正常运行时react-leaflet会正确注入真实的map实例,但写单元测试mock的时候,要是没正确模拟useMapEvents的返回值,组件里的map就会变成未定义或者还没赋值的状态,回调一调用就炸了。
正确的Mock方案
咱们分几步来实现正确的mock:
1. 先准备一个模拟的Map实例
在测试文件里创建一个模拟的map对象,包含你组件用到的所有方法——比如你这里用到了locate,就给它mock一个对应的方法:
const mockMapInstance = { locate: jest.fn().mockResolvedValue(undefined), // 要是你组件还用到了map的其他方法,比如setView,就在这儿加上对应的mock };
2. 正确Mock useMapEvents方法
接下来修改你的jest.mock代码,重点是要让useMapEvents返回咱们的模拟实例,同时保留react-leaflet其他组件(比如MapContainer)的原有实现,这样测试时不用额外mock这些组件:
import { render } from '@testing-library/react'; import { useMapEvents } from 'react-leaflet'; import MyMapComponent from '.'; const mockMapInstance = { locate: jest.fn().mockResolvedValue(undefined), }; jest.mock('react-leaflet', () => ({ ...jest.requireActual('react-leaflet'), useMapEvents: jest.fn().mockImplementation((eventHandlers) => { // 这里可以根据需求验证事件回调的注册情况,不需要的话也可以留空 return mockMapInstance; }), }));
3. 编写验证用例
现在咱们可以写测试逻辑,验证组件的行为是否符合预期——比如点击事件触发后,map.locate()是否被正确调用:
describe('MyMapComponent', () => { beforeEach(() => { // 每次测试前重置所有mock,避免不同用例之间互相影响 jest.clearAllMocks(); }); it('能正常渲染,且点击地图时会调用locate方法', () => { render(<MyMapComponent />); // 先验证useMapEvents有没有被组件正确调用 expect(useMapEvents).toHaveBeenCalledTimes(1); // 获取传给useMapEvents的事件处理对象 const eventHandlers = useMapEvents.mock.calls[0][0]; // 模拟用户点击地图的行为 eventHandlers.click(); // 最后验证map的locate方法是否被调用了一次 expect(mockMapInstance.locate).toHaveBeenCalledTimes(1); }); });
补个小说明:为啥之前的Mock会出错?
你之前的mock只简单替换了useMapEvents,但没返回一个有效的map实例。组件执行时map变量会被赋值为undefined,当回调试图访问map.locate()时,自然就触发「初始化前无法访问map」的错误啦。
备注:内容来源于stack exchange,提问作者Chi Ming Pun
相关产品推荐
相关产品推荐

