Next.js12(SWC替代Babel)中Jest与React测试库动态导入测试失败
解决Next.js 12(SWC)+ Jest测试动态导入组件的报错问题
问题背景
技术栈:
- NextJS 12(使用SWC,不依赖Babel)
- React 18
- Jest + React Testing Library
测试使用next/dynamic动态导入组件的页面时,触发如下错误:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
原因分析
Jest默认无法正确解析Next.js的dynamic异步导入逻辑,在SWC编译环境下,动态导入的组件在测试阶段无法被同步加载,最终返回undefined导致渲染失败。
可行解决方案
方案1:Mock next/dynamic实现同步加载
在测试文件头部或全局jest.setup.js中添加mock代码,让动态导入强制同步返回组件:
jest.mock('next/dynamic', () => ({ __esModule: true, default: (importFunc) => { // 直接解析异步导入的Promise,同步返回组件默认导出 const component = importFunc(); return component.then(mod => mod.default); }, }));
方案2:添加测试环境的静态导入分支
修改页面组件代码,通过环境变量判断,在测试环境下跳过动态导入,直接静态加载组件:
import styles from '@/pages/index.module.css'; import dynamic from 'next/dynamic'; // 测试环境用静态导入,避免动态加载的 Jest 兼容问题 const Hello = process.env.NODE_ENV === 'test' ? require('../components/Hello').default : dynamic(() => import('../components/Hello')); export default function Home() { return ( <div className={styles.container}> {/* 原有页面代码 */} <Hello /> </div> ); }
方案3:配置SWC支持动态导入解析
在jest.config.js中调整SWC的转换规则,确保其能正确处理动态导入语法:
module.exports = { transform: { '^.+\\.(ts|tsx)$': ['@swc/jest', { jsc: { parser: { syntax: 'typescript', jsx: true, dynamicImport: true, // 启用动态导入解析 }, transform: { react: { runtime: 'automatic', }, }, }, }], }, };
验证测试
调整后重新运行测试,确认组件能被正常渲染:
import { render, screen } from '@testing-library/react'; import Home from '@/pages/index'; describe('Home', () => { it('renders heading and Hello component', () => { render(<Home />); const heading = screen.getByRole('heading', { name: /welcome to next\.js!/i, }); expect(heading).toBeInTheDocument(); expect(screen.getByText('Hello')).toBeInTheDocument(); }); });
内容的提问来源于stack exchange,提问作者san
相关产品推荐
相关产品推荐

