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

Express+TypeScript项目Jest配置及测试代码报错求助

问题排查:Express+TypeScript API测试的编译与Mock配置错误

编译错误:watchTimeFactory.build() 提示类型不可调用

错误信息:

This expression is not callable.
Type 'WatchTime' has no call signatures.ts(2349)

相关代码

测试文件 /test/unit/services/episodeService.spec.ts 片段:

it('When has no watchTime then create it', async ()=> {
    const watchTime: WatchTime =  watchTimeFactory.build() 
    // ... 其他代码
})

工厂文件 /test/factories/watchTime.ts:

/*some imports*/
export const watchTimeFactory = Factory.makeFactory<WatchTime>(() => ({
    userId: Number(faker.random.numeric()),
    episodeId: Number(faker.random.numeric()),
    seconds: Number(faker.random.numeric()),
    createdAt: new Date(),
    updatedAt: new Date()
}))

运行时错误:Mock方法无mockReturnValue

将工厂调用移到测试用例外部后,编译错误消失,但出现新错误:

TypeError: episodesQueryServiceMock.findByUserIdAndEpisodeId.mockReturnValue is not a function

相关测试代码片段

beforeEach(() =>{
    jest.mock('../../../src/services/queries/episodesQueryService')
    jest.mock('../../../src/models/')
    jest.mock('../../../src/models/WatchTime')
    episodesQueryServiceMock =  episodesQueryService as jest.Mocked<typeof episodesQueryService>
})

Jest配置文件 ./jest.config.ts

import type {Config} from '@jest/types';
const config: Config.InitialOptions = {
    verbose: true,
    transform: {
        '^.+\\.tsx?$': 'ts-jest',
    },
    setupFiles: ['<rootDir>/test/setup.ts'],
    testEnvironment: 'node',
    maxWorkers: 1,
    preset: 'ts-jest'
};
export default config;

解决方案

1. 修复工厂函数编译错误

  • 检查测试文件中WatchTime的导入:确保导入的是类型定义(接口/类型别名)而非类。如果WatchTime是ORM模型类,应使用InstanceType<typeof WatchTime>作为工厂的泛型参数,而非类本身。
  • 调整工厂泛型类型:
    // 假设WatchTime是模型类
    import { WatchTime } from '../../src/models/WatchTime';
    export const watchTimeFactory = Factory.makeFactory<InstanceType<typeof WatchTime>>(() => ({
        // ... 字段定义
    }))
    
  • 测试文件中对应调整类型注解:
    const watchTime: InstanceType<typeof WatchTime> = watchTimeFactory.build();
    

2. 修复Mock方法运行时错误

  • 将jest.mock移到文件顶部:Jest会自动将jest.mock提升到模块作用域最顶部,放在beforeEach中不会正确生效,导致原模块未被Mock替换。
  • 调整测试文件结构:
    /*some imports*/
    // 移到文件顶部
    jest.mock('../../../src/services/queries/episodesQueryService')
    jest.mock('../../../src/models/')
    jest.mock('../../../src/models/WatchTime')
    
    describe('Episodes Service', () => {
        let episodesQueryServiceMock: jest.Mocked<typeof episodesQueryService>
        let watchTimeInstance: jest.Mocked<WatchTimeInstance>
    
        beforeEach(() =>{
            // 重置Mock状态
            jest.clearAllMocks();
            episodesQueryServiceMock = episodesQueryService as jest.Mocked<typeof episodesQueryService>
        })
    
        // ... 测试用例
    })
    
  • 确认导出方式:如果episodesQueryService是默认导出,需调整Mock获取方式:
    episodesQueryServiceMock = require('../../../src/services/queries/episodesQueryService').default as jest.Mocked<typeof episodesQueryService>
    

3. 额外检查点

  • 确认ts-jest与TypeScript版本兼容,避免版本冲突导致类型解析异常。
  • 检查WatchTimeInstance定义:确保它是模型实例的正确类型,而非类本身,避免watchTimeInstance未被正确Mock。

内容的提问来源于stack exchange,提问作者Jose Luiz Junior

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 06:03:18