为何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:
- 修改tsconfig.json的
compilerOptions:
{ "compilerOptions": { "module": "ESNext", "target": "ES2022", // 其他配置... } }
- 更新jest.config.cjs配置:
const customJestConfig = { // 原有配置... extensionsToTreatAsEsm: [".ts", ".tsx"], transform: {}, globals: { "ts-jest": { useESM: true } } };
- 确保.babelrc使用Next.js预设:
{ "presets": ["next/babel"] }
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

