使用Jest测试NestJS项目时@IsValidMobileNumber装饰器报错求助
NestJS Jest测试报错:TypeError: IsValidMobileNumber is not a function
问题概述
运行jest ./auth.controller.spec.ts时测试套件启动失败,报错TypeError: (0 , decorator_1.IsValidMobileNumber) is not a function,该错误出现在src/user/dto/client-validate.param.dto.ts第30行的自定义装饰器@IsValidMobileNumber()调用处,该装饰器导出自src/_core/decorator/index.ts。
完整错误栈
> jest ./auth.controller.spec.ts FAIL src/auth/auth.controller.spec.ts ● Test suite failed to run TypeError: (0 , decorator_1.IsValidMobileNumber) is not a function 28 | @IsNotEmpty() 29 | @IsString() > 30 | @IsValidMobileNumber() | ^ 31 | mobileNumber: string; 32 | } 33 | at Object.<anonymous> (src/user/dto/client-validate.param.dto.ts:30:23) at Object.<anonymous> (src/user/controller/client.controller.ts:95:1) at Object.<anonymous> (src/user/user.module.ts:4:1) at Object.<anonymous> (src/user/index.ts:2:1) at Object.<anonymous> (src/_core/decorator/is-email-unique.decorator.ts:10:1) at Object.<anonymous> (src/_core/decorator/index.ts:11:1) at Object.<anonymous> (src/auth/auth.controller.ts:3:1) at Object.<anonymous> (src/auth/auth.controller.spec.ts:2:1)
相关配置
package.json中的Jest配置
"jest": { "moduleFileExtensions": [ "js", "json", "ts" ], "roots": [ "src" ], "moduleNameMapper": { "^@core/(.*)$": "<rootDir>/src/_core/$1", "^@module/activity/(.*)$": "<rootDir>/src/activity/$1", "^@module/auth$": "<rootDir>/src/auth/index", "^@module/role/(.*)$": "<rootDir>/src/role/$1", "^@module/user/(.*)$": "<rootDir>/src/user/$1", "^@module/health/(.*)$": "<rootDir>/src/health/$1", "^@module/notification/(.*)$": "<rootDir>/src/notification/$1", "^@module/report/(.*)$": "<rootDir>/src/report/$1", "^@module/file/(.*)$": "<rootDir>/src/file/$1", }, "testRegex": ".*\\.spec\\.ts$", "transform": { "^.+\\.(t|j)s$": "ts-jest" }, "collectCoverageFrom": [ "**/*.(t|j)s" ], "coverageDirectory": "../coverage", "testEnvironment": "node" }
tsconfig.json路径配置
{ "compilerOptions": { "module": "commonjs", "declaration": true, "removeComments": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "allowSyntheticDefaultImports": true, "target": "es2017", "sourceMap": true, "outDir": "./dist", "baseUrl": "./", "incremental": true, "skipLibCheck": true, "strictNullChecks": false, "noImplicitAny": false, "strictBindCallApply": false, "forceConsistentCasingInFileNames": false, "noFallthroughCasesInSwitch": false, "paths": { "@core/config": [ "src/_core/config/index" ], "@core/database": [ "src/_core/database/index" ], "@core/email": [ "src/_core/email/index" ], "@core/enum": [ "src/_core/enum/index" ], "@core/guard": [ "src/_core/guard/index" ], "@core/interceptor": [ "src/_core/interceptor/index" ], "@core/interface": [ "src/_core/interface/index" ], "@core/middleware": [ "src/_core/middleware/index" ], "@core/notification": [ "src/_core/notification/index" ], "@core/strategy": [ "src/_core/strategy/index" ], "@core/utils": [ "src/_core/utils/index" ], "@core/logger": [ "src/_core/logger/index" ], "@core/service": [ "src/_core/service/index" ], "@core/decorator": [ "src/_core/decorator/index" ], "@core/event": [ "src/_core/event/index" ], "@core/swagger": [ "src/_core/swagger/index" ], "@core/error": [ "src/_core/error/index" ], "@module/activity/*": [ "src/activity/*" ], "@module/auth": [ "src/auth/index" ], "@module/role/*": [ "src/role/*" ], "@module/user/*": [ "src/user/*" ], "@module/health/*": [ "src/health/*" ], "@module/notification/*": [ "src/notification/*" ], "@module/report/*": [ "src/report/*" ], "@module/address/*": [ "src/address/*" ], "@module/file/*": [ "src/file/*" ], "@module/whitelist/*": [ "src/whitelist/*" ], } } }
根因排查与解决方案
1. 循环依赖问题(核心原因)
从错误栈的依赖链可看出明显的循环引用:auth.controller.spec.ts → auth.controller.ts → _core/decorator/index.ts → is-email-unique.decorator.ts → user/index.ts → user.module.ts → client.controller.ts → client-validate.param.dto.ts → 回到IsValidMobileNumber装饰器
解决方法:
- 重构代码打破循环:将
is-email-unique.decorator.ts中对user模块的依赖迁移到服务层,或者使用NestJS的forwardRef来延迟依赖解析 - 调整导入方式:避免导入整个模块,改为导入具体的服务或类,减少耦合
2. 装饰器导出/导入错误
检查点:
- 确认
is-valid-mobile-number.decorator.ts中装饰器的导出方式是否正确,需使用命名导出:export function IsValidMobileNumber() { // 装饰器逻辑 } - 确认
src/_core/decorator/index.ts是否正确聚合导出该装饰器:export { IsValidMobileNumber } from './is-valid-mobile-number.decorator'; // 或使用 export * from './is-valid-mobile-number.decorator';
3. Jest路径映射不匹配
tsconfig中@core/decorator映射到src/_core/decorator/index,但Jest的moduleNameMapper中仅配置了^@core/(.*)$,会导致Jest解析@core/decorator时指向目录而非index.ts文件。
解决方法:
在Jest的moduleNameMapper中添加单独的映射规则:
"moduleNameMapper": { // 原有规则... "^@core/decorator$": "<rootDir>/src/_core/decorator/index", }
内容的提问来源于stack exchange,提问作者Koala
相关产品推荐
相关产品推荐

