Next.js+Jest环境中无法Mock JSX/TSX组件的问题排查
解决Jest Mock Next.js组件时的转译错误
问题场景
在使用Next.js、Jest和React Testing Library进行测试时,尝试Mock ui/forms/Field/Field组件,使用以下代码:
jest.mock('ui/forms/Field/Field', () => { const original = jest.requireActual('ui/forms/Field/Field'); return { __esModule: true, ...original, Field: (props: any) => <div ref={props.inputRef}></div>, }; });
执行测试时出现错误:
Property declarations[0] of VariableDeclaration expected node to be of a type ["VariableDeclarator"] but instead got undefined
当前jest.config.js配置如下:
module.exports = { collectCoverage: true, coverageProvider: 'v8', collectCoverageFrom: ['<rootDir>/src/templates/ui/forms/**/*{.tsx,.jsx}'], moduleNameMapper: { '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy', '^.+\\.(css|sass|scss)$': '<rootDir>/jest/mocks/style.js', '^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i': `<rootDir>/jest/mocks/file.js`, '^templates/(.*)$': '<rootDir>/src/templates/$1', '^scripts/(.*)$': '<rootDir>/src/scripts/$1', '^ui/(.*)$': '<rootDir>/src/templates/ui/$1', }, testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'], testEnvironment: 'jsdom', transform: { '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }], }, transformIgnorePatterns: ['/node_modules/', '^.+\\.module\\.(css|sass|scss)$'], };
解决方案
这个错误的核心原因是Jest会将jest.mock的工厂函数提升到模块顶部执行,而此时JSX/TSX语法还未经过Babel转译,Node.js无法识别JSX语法,导致转译报错。可以通过以下两种方式解决:
方案1:用React.createElement替代JSX语法
在jest.mock的工厂函数中,避免直接写JSX,改用React.createElement构造元素:
jest.mock('ui/forms/Field/Field', () => { const React = require('react'); const original = jest.requireActual('ui/forms/Field/Field'); return { __esModule: true, ...original, Field: (props: any) => React.createElement('div', { ref: props.inputRef }), }; });
方案2:使用单独的__mocks__文件
将Mock组件抽离到单独的文件中,让Jest自动加载该Mock,这样文件会正常经过Babel转译:
- 在项目中创建路径:
__mocks__/ui/forms/Field/Field.tsx - 在该文件中编写Mock组件:
import React from 'react'; import * as originalModule from 'ui/forms/Field/Field'; export const Field = (props: any) => <div ref={props.inputRef}></div>; // 导出原模块的其他内容 export default { ...originalModule, Field };
- 在测试文件中只需调用
jest.mock('ui/forms/Field/Field')即可,无需工厂函数:
jest.mock('ui/forms/Field/Field');
额外检查
如果以上方案仍未解决,可确认以下配置:
- 确保
next/babel预设已正确安装(通常Next.js项目默认包含) - 检查
transform配置是否覆盖了所有TSX/JSX文件,当前配置中的'^.+\\.(js|jsx|ts|tsx)$'规则是正确的 - 确认
testEnvironment设置为jsdom(已在配置中设置)
内容的提问来源于stack exchange,提问作者Сапижат Гаджи</think_never_used_51bce0c785ca2f68081bfa7d91973934>
相关产品推荐
相关产品推荐

