Jest测试集成react-leaflet的React组件报export语法错误如何解决
测试集成react-leaflet的React组件时,触发如下语法错误:
C:\digital-booking-ui\node_modules\react-leaflet\lib\index.js:1 ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { useMap, useMapEvent, useMapEvents } from './hooks.js'; ^^^^^^ SyntaxError: Unexpected token 'export' 1 | import React from "react"; 2 | import { makeStyles } from "@material-ui/core"; > 3 | import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet"; | ^ 4 | 5 | const Map = () => { 6 | const classes = useStyles(); at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14) at Object.<anonymous> (src/components/accomodation/Map.js:3:1)
所有引入react-leaflet的组件在测试渲染时都会触发该错误,示例测试代码如下:
import { render, screen, prettyDOM } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect' import App from './App'; import { BrowserRouter } from 'react-router-dom'; import { ThemeProvider } from '@material-ui/core'; import theme from "./theme"; let component = null; beforeEach(() => { component = render( <BrowserRouter> <ThemeProvider theme={theme}> <App /> </ThemeProvider> </BrowserRouter> ); } ); test('render App', () => { expect(component).toBeTruthy(); });
问题本质:Jest默认运行在CommonJS环境,且默认不会转译node_modules下的依赖,而react-leaflet v3+版本为原生ES模块格式,使用ESM的export语法,直接被Jest加载时就会抛出语法错误。
1. 修改Jest转译配置,将react-leaflet相关依赖加入转译白名单
不要只单独添加react-leaflet,它的内部依赖@react-leaflet/core、底层依赖leaflet高版本也都是ESM格式,需要全部加入转译范围。
如果项目使用独立的jest.config.js配置文件,修改transformIgnorePatterns字段:
// jest.config.js module.exports = { // 保留原有其他配置 transform: { // 确保js/jsx文件走babel-jest转译 '^.+\\.(js|jsx)$': 'babel-jest' }, transformIgnorePatterns: [ // 排除react-leaflet相关依赖,不忽略转译 'node_modules/(?!(react-leaflet|@react-leaflet|leaflet)/)' ] }
如果是未eject的Create React App项目,直接在package.json的jest字段下添加上述transformIgnorePatterns配置即可。
如果使用craco/react-app-rewired等配置覆盖工具,对应修改jest配置项即可。
2. 配置Babel支持ESM转译
确保项目的Babel配置(.babelrc/babel.config.js)包含@babel/preset-env,配置示例:
// babel.config.js module.exports = { presets: [ ['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-react' ] }
3. (可选,稳定性更高)测试环境直接mock react-leaflet组件
地图组件依赖浏览器环境的尺寸API、地理定位API,jsdom环境没有完整实现这些能力,即使转译通过也可能触发其他运行时错误。单元测试不需要验证第三方库本身的逻辑,可以直接在测试全局setup文件中mock react-leaflet的导出,彻底规避ESM加载问题和DOM依赖问题:
在src/setupTests.js(Jest默认的setup文件)中添加:
// 先保留原有setup逻辑,比如@testing-library/jest-dom的导入 jest.mock('react-leaflet', () => ({ MapContainer: ({ children }) => <div data-testid="map-container">{children}</div>, TileLayer: () => <div data-testid="tile-layer" />, Marker: ({ children }) => <div data-testid="marker">{children}</div>, Popup: ({ children }) => <div data-testid="popup">{children}</div>, useMap: () => ({ setView: jest.fn(), fitBounds: jest.fn(), getZoom: jest.fn(() => 13) }), useMapEvent: jest.fn(), useMapEvents: jest.fn(() => ({})) })) // mock leaflet默认图标,避免静态资源路径报错 jest.mock('leaflet', () => { const actual = jest.requireActual('leaflet') return { ...actual, Icon: { Default: { mergeOptions: jest.fn(), prototype: { options: {} } } } } })
4. 清空Jest缓存后重新运行测试
配置修改完成后执行以下命令清空缓存,避免旧的缓存文件导致错误复现:
npx jest --clearCache
- 只把
react-leaflet加入转译白名单,漏了@react-leaflet/core依赖,依然会报同样的Unexpected token 'export'错误 - 配置修改后没有清空Jest缓存,旧的未转译文件被缓存加载
- Babel配置没有覆盖node_modules下的上述依赖,导致转译不生效
内容的提问来源于stack exchange,提问作者Ramon Colmenares

