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

在Jest E2E测试中使用typeorm-fixtures-cli刷新数据库遇错

Jest 环境销毁后执行数据库刷新函数报错的解决办法

我写了一个用于测试套件刷新数据库的助手函数,用来重置数据库数据、执行迁移并加载测试 fixtures。函数在全局设置里运行正常,但放到 afterAll 或 beforeAll 中执行时,抛出了环境销毁后禁止导入的错误,报错位置在加载 fixture 文件的代码行。

助手函数代码

export const refreshDb = async () => {
  const dataSource = new DataSource({
    ...config.dbConfig,
  });

  await dataSource.initialize();
  await dataSource.dropDatabase();
  await dataSource.runMigrations();

  const fixturePaths = await glob(resolve(__dirname, '../fixtures/**/*.yml'));
  const loader = new Loader();
  for (const fixturePath of fixturePaths) {
    loader.load(fixturePath);
  }

  const resolver = new Resolver();
  const fixtures = resolver.resolve(loader.fixtureConfigs);
  const builder = new Builder(dataSource, new Parser(), false);

  for (const fixture of fixturesIterator(fixtures)) {
    const entity: any = await builder.build(fixture);
    await dataSource.getRepository(fixture.entity).save(entity);
  }

  await dataSource.destroy();
};

报错信息

ReferenceError: You are trying to import a file after the Jest environment has been torn down. ...

24 |   const loader = new Loader();
  25 |   for (const fixturePath of fixturePaths) {
> 26 |     loader.load(fixturePath);
     |                                      ^
  27 |   }

问题原因

Jest 在 afterAll 阶段会逐步销毁测试环境,此时任何动态导入操作(比如 fixture 加载器内部的文件导入)都会被拦截,导致报错。核心是异步操作未在环境销毁前完成,或者加载器的导入逻辑与 Jest 的生命周期冲突。

解决步骤

1. 确保异步操作等待完成

把 refreshDb 放入 afterAll 时,必须用 await 确保 Jest 等待函数执行完毕后再销毁环境:

afterAll(async () => {
  await refreshDb();
});

2. 调整 Jest 缓存配置

修改 Jest 配置,避免提前销毁模块缓存:

{
  "testEnvironment": "node",
  "clearMocks": true,
  "resetMocks": false,
  "restoreMocks": false
}

3. 替换动态加载逻辑

如果 Loader.load 内部使用了动态 import,改成同步读取解析 fixture 文件,避开环境销毁阶段的导入限制:

const fs = require('fs');
const yaml = require('js-yaml');

// 替换原加载循环
for (const fixturePath of fixturePaths) {
  const content = fs.readFileSync(fixturePath, 'utf8');
  const fixtureData = yaml.load(content);
  // 手动处理 fixture 数据,替代原 loader.load 的逻辑
}

4. 使用全局钩子替代测试用例钩子

如果是全局数据库刷新,把 refreshDb 放到 Jest 的全局配置文件中:

// globalSetup.ts
export default async () => {
  await refreshDb();
};

然后在 Jest 配置里指定:

{
  "globalSetup": "./globalSetup.ts"
}

全局钩子在测试环境初始化前执行,不会和测试用例的生命周期冲突。

内容的提问来源于stack exchange,提问作者Sviatoslav Ronskyi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 20:52:35