I'm trying to update my NodeJS12 & TypeScript app to Node16, one if the reasons is the need to use top-level-awaits.
The code compiles correctly after the update, but Jest won't accept the specific top-level-await code:
ts-jest[ts-compiler] (WARN) src/xxx.ts:11:17 - error TS1378: Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', or 'nodenext', and the 'target' option is set to 'es2017' or higher.
11 const project = await client.getProjectId();
~~~~~
FAIL src/xxx.test.ts
● Test suite failed to run
Jest encountered an unexpected token
package.json:
{
"name": "functions",
"scripts": {
"lint": "eslint --ext .js,.ts .",
"lint:fix": "eslint --ext .js,.ts . --fix",
"build": "tsc -b",
"build:watch": "tsc-watch",
"serve": "...",
"test": "env-cmd -f .env.json jest --runInBand --verbose"
},
"type": "module",
"engines": {
"node": "16"
},
"main": "lib/index.js",
"exports": "./lib/index.js",
"dependencies": {
"test": "^1.0.0"
},
"devDependencies": {
"@google-cloud/functions-framework": "^2.1.0",
"@types/busboy": "^1.3.0",
"@types/compression": "1.7.2",
"@types/cors": "^2.8.12",
"@types/express": "^4.17.12",
"@types/express-serve-static-core": "^4.17.28",
"@types/google-libphonenumber": "^7.4.23",
"@types/jest": "^27.4.0",
"@types/jsonwebtoken": "^8.5.7",
"@types/luxon": "^2.0.9",
"@types/node-zendesk": "^2.0.6",
"@types/sinon": "^10.0.6",
"@types/supertest": "^2.0.11",
"@types/swagger-ui-express": "^4.1.3",
"@types/uuid": "^8.3.4",
"@types/yamljs": "^0.2.31",
"@typescript-eslint/eslint-plugin": "^5.9.0",
"@typescript-eslint/parser": "^5.9.0",
"env-cmd": "^10.1.0",
"eslint": "^8.6.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react-hooks": "^4.2.1-beta-a65ceef37-20211130",
"jest": "^27.4.7",
"prettier": "^2.5.1",
"sinon": "^12.0.1",
"supertest": "^6.2.1",
"ts-jest": "^27.1.3",
"ts-node": "^10.4.0",
"tsc-watch": "^4.6.0",
"typescript": "^4.5.4"
},
"private": true
}
tsconfig.json:
{
"compilerOptions": {
"module": "es2022",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"sourceMap": false,
"strict": true,
"target": "es2021",
"moduleResolution": "Node",
"resolveJsonModule": true
},
"compileOnSave": true,
"include": [
"src"
],
"ts-node": {
"moduleTypes": {
"jest.config.ts": "cjs"
}
}
}
jest.config.ts:
export default {
roots: [
'<rootDir>/src'
],
setupFiles: ['./src/setupJestEnv.ts'],
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['/node_modules/'],
coverageDirectory: './coverage',
coveragePathIgnorePatterns: ['node_modules', 'src/database', 'src/test', 'src/types'],
globals: { 'ts-jest': { diagnostics: false } },
};
I can't really understand what's wrong here. Any idea?
It occurred to me lately, as far as I know, CJS doesn't support top-level await, meaning that you need to use ts-jest with esm.
my jest.config.json
{
"extensionsToTreatAsEsm": [".ts"],
"globals": {
"ts-jest": {
"useESM": true
}
},
"preset": "ts-jest/presets/default-esm",
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testEnvironment": "node",
"testRegex": "spec.ts$",
"modulePathIgnorePatterns": ["<rootDir>/dist/", "<rootDir>/node_modules/"],
"moduleNameMapper": {
"^src/(.*)": "<rootDir>/src/$1"
},
"collectCoverage": true,
"coverageDirectory": "./coverage",
"collectCoverageFrom": ["src/**/*.(t|j)s"],
"coveragePathIgnorePatterns": [
".module.ts$",
".spec.ts$",
"src/database/",
"src/server.ts"
],
"verbose": true
}
You will also need to run jest with --experimental-vm-modules option
node --experimental-vm-modules -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand --config jest.overall.json