I have a top-level await to load application secrets as follows:
// lib/config/secrets.ts
const secrets = await loadSecrets();
export default secrets;
I import this in other modules for db connection setup, etc:
// lib/db/index.ts
import { Pool } from "pg";
import secrets from "lib/config/secrets";
const pool = new Pool({
connectionString: secrets.dbUrl,
...
});
This works fine when running my application via Webpack, but when running unit tests with jest, I get the following error:
SyntaxError: await is only valid in async functions and the top level bodies of modules
.
I've been stuck on this for some time and have even considered other avenues to avoid the asynchronous secret loading altogether since I haven't found a solution. I've seen this similar question Jest won't accept top-level-awaits with NodeJS16 & TypeScript, but I'm not using ts-jest
in my project. Is there anything obvious about my configuration that would cause this issue during tests, or is this just not supported?
My next.config.js
to support top-level await via Webpack:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
webpack: (config) => {
config.experiments.topLevelAwait = true;
return config;
},
};
module.exports = nextConfig;
My jest.config.js
:
const nextJest = require("next/jest");
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: "./",
});
// Add any custom config to be passed to Jest
const customJestConfig = {
moduleDirectories: ["node_modules", "<rootDir>"],
modulePaths: ["<rootDir>/lib"],
// setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
moduleNameMapper: {
// Handle module aliases (this will be automatically configured for you soon)
"^components/(.*)$": "<rootDir>/components/$1",
"^lib/(.*)$": "<rootDir>/lib/$1",
"^pages/(.*)$": "<rootDir>/pages/$1",
},
testEnvironment: "jest-environment-jsdom",
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);
My package.json
:
{
"name": "app",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
...
},
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.199.0",
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@mui/icons-material": "^5.3.1",
"@mui/material": "^5.4.0",
"install": "^0.13.0",
"next": "^12.1.0",
"next-auth": "^4.2.1",
"npm": "^8.4.1",
"pg": "^8.7.3",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@babel/preset-env": "^7.16.11",
"@babel/preset-typescript": "^7.16.7",
"@types/aws-lambda": "^8.10.108",
"@types/jest": "^27.4.1",
"@types/node": "17.0.8",
"@types/pg": "^8.6.5",
"@types/react": "17.0.38",
"@typescript-eslint/eslint-plugin": "^5.11.0",
"@typescript-eslint/parser": "^5.11.0",
"babel-jest": "^27.5.1",
"esbuild": "^0.15.12",
"eslint": "8.6.0",
"eslint-config-next": "12.0.8",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"eslint-plugin-unused-imports": "^2.0.0",
"jest": "^27.5.1",
"prettier": "^2.6.2",
"typescript": "4.5.4"
}
}
My .babelrc
:
{
"presets": ["next/babel"],
"plugins": []
}
My tsconfig.json
:
{
"compilerOptions": {
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"baseUrl": ".",
"paths": {
"components": ["components/"],
"lib": ["lib/"],
"sql": ["sql/"],
"styles": ["styles/"]
}
},
"include": ["types/*.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
Update:
I tried adding "type":"module"
to the package.json
and updating the jest.config and next.config extensions to .cjs
. It still produces the same error: SyntaxError: await is only valid in async functions and the top level bodies of modules
.