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

为何Jest测试环境不支持顶层await?配置排查求助

问题描述

我通过顶层await加载应用密钥,代码如下:

// lib/config/secrets.ts
const secrets = await loadSecrets();
export default secrets;

在数据库连接模块中导入该密钥:

// lib/db/index.ts
import { Pool } from "pg";
import secrets from "lib/config/secrets";

const pool = new Pool({
   connectionString: secrets.dbUrl,
   // 其他配置项
});

通过Webpack运行应用时一切正常,但使用Jest执行单元测试时,抛出错误:SyntaxError: await is only valid in async functions and the top level bodies of modules。

我尝试过参考类似问题,但因未使用ts-jest,问题仍未解决,甚至考虑更换密钥加载方式。相关配置如下:

next.config.js(已配置Webpack支持顶层await)

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  webpack: (config) => {
    config.experiments.topLevelAwait = true;
    return config;
  },
};

module.exports = nextConfig;

jest.config.js

const nextJest = require("next/jest");

const createJestConfig = nextJest({
  dir: "./",
});

const customJestConfig = {
  moduleDirectories: ["node_modules", "<rootDir>"],
  modulePaths: ["<rootDir>/lib"],
  moduleNameMapper: {
    "^components/(.*)$": "<rootDir>/components/$1",
    "^lib/(.*)$": "<rootDir>/lib/$1",
    "^pages/(.*)$": "<rootDir>/pages/$1",
  },
  testEnvironment: "jest-environment-jsdom",
};

module.exports = createJestConfig(customJestConfig);

此外还有package.json、.babelrc、tsconfig.json相关配置。

更新尝试:在package.json中添加"type":"module",并将jest.config和next.config后缀改为.cjs,但错误依旧。


解决方案

方案1:Mock密钥模块(推荐用于单元测试)

单元测试无需加载真实密钥,直接mock该模块即可绕过顶层await问题:

// __tests__/db.test.ts
jest.mock("lib/config/secrets", () => ({
  default: {
    dbUrl: "test-db-connection-url",
    // 其他需要mock的密钥字段
  },
}));

import { pool } from "lib/db/index";

// 编写你的测试逻辑
test("数据库连接池初始化正常", async () => {
  const client = await pool.connect();
  expect(client).toBeDefined();
  client.release();
});

方案2:异步函数封装密钥加载

修改原代码,用异步函数替代顶层await,适配Jest的执行环境:

// lib/config/secrets.ts
let cachedSecrets: SecretsType | null = null;

export async function getSecrets() {
  if (!cachedSecrets) {
    cachedSecrets = await loadSecrets();
  }
  return cachedSecrets;
}

对应修改数据库连接模块:

// lib/db/index.ts
import { Pool } from "pg";
import { getSecrets } from "lib/config/secrets";

let cachedPool: Pool | null = null;

export async function getPool() {
  if (!cachedPool) {
    const secrets = await getSecrets();
    cachedPool = new Pool({
      connectionString: secrets.dbUrl,
      // 其他配置项
    });
  }
  return cachedPool;
}

测试时可提前初始化,或在测试用例中异步调用getPool()。

方案3:配置Jest支持ES模块与顶层await

调整Jest和TypeScript配置,让其兼容顶层await:

  1. 修改tsconfig.json的compilerOptions:
{
  "compilerOptions": {
    "module": "ESNext",
    "target": "ES2022",
    // 其他配置...
  }
}
  1. 更新jest.config.cjs配置:
const customJestConfig = {
  // 原有配置...
  extensionsToTreatAsEsm: [".ts", ".tsx"],
  transform: {},
  globals: {
    "ts-jest": {
      useESM: true
    }
  }
};
  1. 确保.babelrc使用Next.js预设:
{
  "presets": ["next/babel"]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 07:40:38