Jest多describe场景下调用TypeORM清库时afterEach超时如何解决?
问题解决方法
问题根因
- 异步代码写法错误:
clear方法使用了async函数嵌套Promise的反模式,导致异步状态回调异常,容易出现流程挂起 - 外键约束阻塞:表间存在外键关联时,直接调用
delete({})会触发数据库约束校验,执行卡住直到超时 - 删除操作效率低:
repository.delete({})是逐行删除数据,同时记录事务日志,表数据量稍大就会耗时超过Jest默认的5000ms异步超时阈值
修复方案
第一步:重写database.clear方法
去掉冗余的Promise包装,添加外键约束临时禁用逻辑,改用更高效的表清空方式:
const database = { // TypeORM 0.2.x版本用getConnection兼容,0.3.x版本直接使用初始化的DataSource实例即可 async create() { await createConnection(); }, async clear() { console.log("Clear database..."); const dynamicEntities = [ EntityOne, EntityTwo, EntityThree ]; const connection = getConnection(); const queryRunner = connection.createQueryRunner(); try { // 适配MySQL的外键禁用逻辑,PostgreSQL请替换为:await queryRunner.query('SET CONSTRAINTS ALL DEFERRED'); await queryRunner.query('SET FOREIGN_KEY_CHECKS = 0'); for (let entity of dynamicEntities) { const repository = connection.getRepository(entity); // clear方法直接清空整张表,执行效率远高于逐行delete await repository.clear(); } // 恢复外键约束,避免影响后续用例逻辑 await queryRunner.query('SET FOREIGN_KEY_CHECKS = 1'); return "Successfully clear database!!!"; } catch(err) { // 出现异常也需要先恢复外键约束 await queryRunner.query('SET FOREIGN_KEY_CHECKS = 1'); throw err; } finally { // 释放queryRunner避免连接泄漏 await queryRunner.release(); } }, };
第二步:调整Jest超时配置
你可以在测试文件顶部设置全局超时,也可以单独给afterEach钩子设置更长的超时时间:
// 测试文件顶部设置全局异步超时为10秒,可根据实际情况调整时长 jest.setTimeout(10000); describe("testing jest", () => { beforeAll(async () => { await database.create(); }); // 也可以单独给afterEach设置超时,第二个参数为超时时间,单位毫秒 afterEach(async() => { await database.clear(); }, 10000); describe("test 1", () => { it("should return 200", () => { expect(100+100).toBe(200) }); }); describe("test 2", () => { it("should return 100", () => { expect(50+50).toBe(100) }); }); });
额外优化建议
- 表数量较多时,可把循环串行清空改成并行处理,进一步提升清理速度
- 使用PostgreSQL数据库的场景,可以直接用
TRUNCATE TABLE 表名 CASCADE语句一次性清空所有关联表,不需要循环处理每个实体
内容的提问来源于stack exchange,提问作者Andre Lebrao
相关产品推荐
相关产品推荐

