添加JEST自定义报告器引发编译错误:Class extends value undefined
问题分析与解决方案
你遇到的错误 Class extends value undefined is not a constructor or null 本质是在加载 country.model.ts 时,某个被继承的类(比如 ORM 的基类)未被正确解析,导致其值为 undefined。结合你的配置和场景,以下是针对性的解决方案:
1. 使用动态导入避免加载顺序问题
问题大概率出在模块加载顺序上:Jest 加载自定义报告器时,项目内的模块(如 Resolver、Model)可能还未完成初始化,或者存在循环依赖导致类未被正确解析。
修改 test-reporter.ts,将顶层导入改为 onRunComplete 内的动态导入:
import { Reporter, TestContext } from '@jest/reporters'; import { AggregatedResult } from '@jest/test-result'; import { Config } from '@jest/types'; import config from '../config/config'; import { buildSchema } from 'type-graphql'; type CustomReporter = Pick<Reporter, 'onRunComplete'>; interface Options { useReporter: boolean; } export default class TestReporter implements CustomReporter { constructor(private config: Config.InitialOptions, private options: Options) {} async onRunComplete(context: Set<TestContext>, results: AggregatedResult) { console.log('Your report is available!'); // 动态导入 Resolver,避免初始化阶段的加载问题 const { FundMutationResolver, FundQueryResolver } = await import('@src/investorPortal/funds/resolvers/app/fund.resolver'); const schema = await buildSchema({ resolvers: [FundMutationResolver, FundQueryResolver], authChecker: () => true, }); } }
2. 验证 tsconfig-paths 配置正确性
确保报告器的路径解析与项目一致,可在 test-reporter/index.js 中添加日志排查:
require('reflect-metadata'); const tsNode = require('ts-node'); const tsConfigPaths = require("tsconfig-paths"); const path = require('path'); const tsconfigPath = path.join(__dirname, '../../tsconfig.json'); const tsconfig = require(tsconfigPath); // 打印关键路径,确认是否正确指向项目根目录 console.log('tsconfigPath:', tsconfigPath); console.log('baseUrl:', path.dirname(tsconfigPath)); tsNode.register({ compilerOptions: tsconfig.compilerOptions, transpileOnly: true, }); tsConfigPaths.register({ baseUrl: path.dirname(tsconfigPath), paths: tsconfig.compilerOptions.paths }); // 测试路径解析是否正常 const resolverPath = require.resolve('@src/investorPortal/funds/resolvers/app/fund.resolver'); console.log('Resolved resolver path:', resolverPath); module.exports = require('./test-reporter');
如果路径解析错误,调整 tsconfigPath 的相对路径,确保指向项目根目录的 tsconfig.json。
3. 预编译报告器为 JavaScript
避免在 Jest 运行时使用 ts-node 编译报告器,直接预编译为 CommonJS 模块:
- 在项目根目录添加编译脚本(如
scripts/compile-reporter.js):
const { execSync } = require('child_process'); execSync('tsc --project ./e2e/test-reporter/tsconfig.json', { stdio: 'inherit' });
- 为报告器单独创建
tsconfig.json(e2e/test-reporter/tsconfig.json):
{ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "./dist", "rootDir": "./" }, "include": ["*.ts"] }
- 修改
jest.config.js指向编译后的报告器:
reporters: ['default', '<rootDir>/e2e/test-reporter/dist/test-reporter.js'],
- 运行测试前先执行编译脚本。
4. 排查循环依赖
使用工具(如 madge)检查项目内的循环依赖:
npm install -g madge madge --circular src/
如果发现 country.model.ts 与其他模块存在循环依赖,重构代码打破循环(比如提取公共接口、使用依赖注入)。
内容的提问来源于stack exchange,提问作者Karim Chaari
相关产品推荐
相关产品推荐

