You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 12+Jest 28运行测试时SVG转换失败引发组件渲染报错

Next.js 12 + Jest 28 导入SVG组件测试报「Element type is invalid」修复方案

问题场景

  • 技术栈版本:Next.js 12.0.7、Jest 28.1.0,通过next-react-svg实现组件内SVG资源直接作为组件导入
  • 已尝试方案:在jest.config.js中配置自定义转换规则,指向__mocks__目录下自行编写的jest-svg-transformer.js,将SVG文件转换为可渲染的React函数组件;后续替换为官方jest-svg-transformer库处理SVG转换,问题未解决
  • 报错表现:执行yarn test或jest命令运行单元测试时,引入Logo.svg组件的Loader组件渲染抛出错误:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object

错误提示指向Loader组件的render方法。

根因说明

报错本质是Jest处理SVG导入后,返回值不是可渲染的React组件类型,而是普通对象/字符串,核心诱因有3个:

  • 转换规则优先级错误:SVG文件被静态资源通用转换规则提前处理为文件路径对象,没有走到SVG专用的组件转换逻辑
  • Transformer导出格式不兼容:自定义转换脚本没有同时适配next-react-svg支持的默认导入、命名导入ReactComponent两种写法,存在ESM/CommonJS互操作问题
  • Jest缓存干扰:修改转换配置后旧的转换缓存未清除,一直使用错误的旧转换结果

修复步骤

1. 修正jest.config.js配置优先级

将SVG的转换规则放在所有transform规则的最顶部(Jest按规则从上到下匹配,先匹配到的规则优先生效),移除moduleNameMapper中对SVG文件的匹配规则,避免和transform逻辑冲突:

// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  transform: {
    // SVG转换规则必须放在最前面
    '^.+\\.svg$': '<rootDir>/__mocks__/jest-svg-transformer.js',
    // 如果使用官方jest-svg-transformer,替换上面一行为:
    // '^.+\\.svg$': 'jest-svg-transformer',
    '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
  },
  moduleNameMapper: {
    // 其他静态资源(图片、字体等)的mock规则不要包含svg后缀
    '^.+\\.(png|jpg|jpeg|gif|webp|woff|woff2|ttf)$': '<rootDir>/__mocks__/fileMock.js',
    // 路径别名配置保留
    '@/(.*)$': '<rootDir>/src/$1',
  },
  // 确保next-react-svg不被忽略转换
  transformIgnorePatterns: [
    '/node_modules/(?!next-react-svg)',
  ],
}

如果使用官方jest-svg-transformer,请先安装适配Jest 28的版本:

yarn add -D jest-svg-transformer@^1.1.0

2. 修正自定义SVG转换脚本

如果使用自写的__mocks__/jest-svg-transformer.js,确保导出逻辑同时兼容两种SVG导入方式:

// __mocks__/jest-svg-transformer.js
module.exports = {
  process: (_, filePath) => {
    // 提取SVG文件名生成组件名,避免重名冲突
    const fileName = filePath.split(/[\\/]/).pop();
    const componentName = fileName.replace(/\.svg$/, 'SvgMock').replace(/[^a-zA-Z0-9]/g, '_');

    return `
      const React = require('react');
      function ${componentName}(props) {
        return React.createElement('svg', {
          'data-testid': 'mock-svg',
          ...props
        }, null);
      }
      ${componentName}.displayName = '${componentName}';
      module.exports = ${componentName};
      module.exports.default = ${componentName};
      module.exports.ReactComponent = ${componentName};
    `;
  },
};

3. 统一组件内SVG导入写法

确保Loader组件中导入SVG的写法和next.config.js里next-react-svg的配置一致,不要混用导入方式:

// 示例:Loader组件正确写法
import Logo from './Logo.svg';
// 如果next-react-svg配置为仅支持命名导入,则使用:
// import { ReactComponent as Logo } from './Logo.svg';

export default function Loader() {
  return (
    <div className="loader-container">
      <Logo className="loader-logo" width={40} height={40} />
    </div>
  );
}

4. 清除Jest缓存重新执行测试

Jest默认会缓存所有文件的转换结果,修改配置后必须先清除缓存再运行测试:

yarn test --clearCache
yarn test

验证方式

修复后测试用例可正常渲染Loader组件,不会抛出类型错误,可正常断言SVG元素存在:

import { render } from '@testing-library/react';
import Loader from './Loader';

test('loader renders logo correctly', () => {
  const { getByTestId } = render(<Loader />);
  expect(getByTestId('mock-svg')).toBeInTheDocument();
});

内容的提问来源于stack exchange,提问作者bonnopc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 14:21:20