
本文详解 Next.js 项目中 Jest 测试因 SVG 等静态资源未被正确 mock 而报 SyntaxError: Unexpected Token ‘
本文详解 next.js 项目中 jest 测试因 svg 等静态资源未被正确 mock 而报 `syntaxerror: unexpected token ‘
在 Next.js 项目中集成 Jest 进行组件单元测试时,直接导入 SVG、PNG 等静态资源(如 import Logo from “@/assets/logo.svg”)是常见做法。但 Jest 默认无法解析 XML/HTML 格式的 SVG 文件(以
SyntaxError: Unexpected token '<' .../public/assets/Branch1.svg:1 <?xml version="1.0" encoding="UTF-8"?> ^
该错误并非因 fileMock.js 内容有误,也不是 moduleNameMapper 未启用,而极大概率源于正则表达式匹配失效 —— 导致 SVG 文件未被重定向到 mock 模块,而是被 Jest 尝试当作 JavaScript 执行。
? 根本原因:正则未覆盖 SVG(大小写敏感 + 转义问题)
你配置中的关键规则为:
"^.+.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i"
表面看已添加 svg 并启用了忽略大小写的 /i 标志,但 Jest 的 moduleNameMapper 在 Node.js 环境下对正则的解析存在隐式限制:
- 某些 Jest 版本(尤其是 v29+ 与 ESM 项目结合时)对 ^(行首锚点)和 $(行尾锚点)在路径匹配中行为不稳定;
- 更关键的是,.svg 文件在实际路径中常以小写 .svg 出现,但部分构建工具或操作系统可能生成混合大小写(如 .SVG),而 /i 标志在某些 Node 正则引擎中对 Unicode 扩展名支持不一致;
- 最常被忽略的陷阱:.svg 中的反斜杠 . 在字符串中需双重转义,但在 JS 对象字面量里,”.svg” 才能正确表示字面量 .svg —— 而你当前写法 “^.+.(…|svg)$” 中的 . 实际只转义了一个 ,导致正则逻辑失效。
✅ 正确且健壮的写法应去除锚点,使用更宽松、明确的匹配:
// ✅ 推荐:移除 ^ $,用 .* 避免路径锚点干扰,显式双转义点号 ".*.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$": "<rootDir>/__mocks__/fileMock.js"
? 提示:.* 比 ^.+ 更安全,因 Jest 匹配的是模块请求路径(如 ./public/assets/Branch1.svg),而非文件系统绝对路径,无需严格锚定。
✅ 完整可运行配置(含验证步骤)
-
确认 __mocks__/fileMock.js 存在且导出有效对象(支持 ESM):
// __mocks__/fileMock.js export default { src: "/mocked-image.png", height: 24, width: 24, blurDataURL: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==", }; -
更新 jest.config.js 中的 moduleNameMapper:
moduleNameMapper: { // ... 其他规则保持不变 ".*.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$": "<rootDir>/__mocks__/fileMock.js", // ⚠️ 注意:此行必须放在 CSS 规则之后,避免被更宽泛的规则覆盖 } -
确保 jest.setup.js 或 setupFilesAfterEnv 中无冲突逻辑(例如未意外启用 jest.mock(…) 覆盖了自动 mock)。
-
验证是否生效:在测试文件中临时添加调试日志:
// __tests__/index.test.js import BRANCH_1_SVG from "@/public/assets/Branch1.svg"; console.log("SVG import resolved to:", BRANCH_1_SVG); // 应输出 fileMock.js 中的对象
⚠️ 注意事项与进阶建议
- ESM 项目特别注意:若 package.json 含 “type”: “module”,确保 fileMock.js 使用 export default(而非 module.exports =),且 Jest 版本 ≥ 29.4(对 ESM mock 支持更完善)。
- SVG 作为 React 组件? 若你使用 @svgr/webpack 将 SVG 转为 React 组件,则 mock 应返回一个简易 JSX 元素:
// __mocks__/fileMock.js export default function MockSvg() { return <svg data-testid="mock-svg" width="24" height="24" />; } - 避免全局污染:不要在 setupFilesAfterEnv 中 jest.mock() 图片扩展名,这会覆盖 moduleNameMapper 的声明式配置,降低可维护性。
- 覆盖率提示:fileMock.js 不会被计入测试覆盖率(因其为测试基础设施),无需为其编写测试。
通过修正正则表达式并遵循上述配置,即可彻底解决 Next.js + Jest 中图片/SVG 导入导致的语法解析错误,让测试稳定运行。核心原则始终是:让 moduleNameMapper 精准、无歧义地捕获所有目标资源路径。