ts-jest: [Bug]: verbatimModuleSyntax support

Version

v29.1.0

Steps to reproduce

I have upgraded to TS v5. I had to replace importsNotUsedAsValues: 'error' with verbatimModuleSyntax: true

Expected behavior

No error.

Actual behavior

ESM syntax is not allowed in a CommonJS module when ‘verbatimModuleSyntax’ is enabled.

for import { xxx } from './xxx';

Debug log

https://gist.github.com/simPod/90d2228089b7a8b1b16a827f73aa71f2

Additional context

config

module.exports = {
  preset: 'ts-jest',
};

Environment

System:
    OS: macOS 13.2.1
    CPU: (10) arm64 Apple M1 Max
  Binaries:
    Node: 19.6.1 - /opt/homebrew/bin/node
    Yarn: 4.0.0-rc.42 - /opt/homebrew/bin/yarn
    npm: 9.4.0 - /opt/homebrew/bin/npm

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 1
  • Comments: 24

Commits related to this issue

Most upvoted comments

I haven’t been able to figure out the root cause of this issue, but after reviewing the /examples/ts-only folder I found that the config in jest-esm-isolated.config.mjs resolves the error for my projects. More specifically, setting isolatedModules to true in the ts-jest transfom config object is what fixed the issue for me.

Below is a summary of the changes that I made to get ts-jest working with TypeScript 5; hopefully this will help some folks who come across this issue in the future.

// ./package.json
// (trimmed to just the relevant parts)
"devDependencies": {
	"@types/jest": "^29.5.0",
	"jest": "^29.5.0",
	"ts-jest": "^29.1.0",
	"typescript": "^5.0.4"
}
// ./tsconfig.json
// (trimmed to just the relevant parts)
 		"esModuleInterop": true,
-		"importsNotUsedAsValues": "error",
-		"isolatedModules": true,
 		"module": "esnext",
 		"moduleResolution": "node",
 		"strict": true,
 		"target": "es2022",
+		"verbatimModuleSyntax": true
 	}
 }
// ./config/jest.config.js
// (trimmed to just the relevant parts)
 	transform: {
-		".ts": ["ts-jest"],
+		".ts": [
+			"ts-jest",
+			{
+				// Note: We shouldn't need to include `isolatedModules` here because it's a deprecated config option in TS 5,
+				// but setting it to `true` fixes the `ESM syntax is not allowed in a CommonJS module when
+				// 'verbatimModuleSyntax' is enabled` error that we're seeing when running our Jest tests.
+				isolatedModules: true,
+				useESM: true,
+			},
+		],
 	},

I haven’t been able to figure out the root cause of this issue, but after reviewing the /examples/ts-only folder I found that the config in jest-esm-isolated.config.mjs resolves the error for my projects. More specifically, setting isolatedModules to true in the ts-jest transfom config object is what fixed the issue for me.

Below is a summary of the changes that I made to get ts-jest working with TypeScript 5; hopefully this will help some folks who come across this issue in the future.

// ./package.json
// (trimmed to just the relevant parts)
"devDependencies": {
	"@types/jest": "^29.5.0",
	"jest": "^29.5.0",
	"ts-jest": "^29.1.0",
	"typescript": "^5.0.4"
}
// ./tsconfig.json
// (trimmed to just the relevant parts)
 		"esModuleInterop": true,
-		"importsNotUsedAsValues": "error",
-		"isolatedModules": true,
 		"module": "esnext",
 		"moduleResolution": "node",
 		"strict": true,
 		"target": "es2022",
+		"verbatimModuleSyntax": true
 	}
 }
// ./config/jest.config.js
// (trimmed to just the relevant parts)
 	transform: {
-		".ts": ["ts-jest"],
+		".ts": [
+			"ts-jest",
+			{
+				// Note: We shouldn't need to include `isolatedModules` here because it's a deprecated config option in TS 5,
+				// but setting it to `true` fixes the `ESM syntax is not allowed in a CommonJS module when
+				// 'verbatimModuleSyntax' is enabled` error that we're seeing when running our Jest tests.
+				isolatedModules: true,
+				useESM: true,
+			},
+		],
 	},

@dustin-ruetz Thanks, this answer is useful. But it seems to conflict with "moduleResolution": "bundler" of tsconfig, and it will be invalid after adding. In order to solve this error, I configured a tsconfig specifically for jest, fortunately it is useful.

// jest.config.js
transform: {
+    '.ts': ['ts-jest', { tsconfig: './tsconfig.jest.json' }],
},

tsconfig.jest.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "verbatimModuleSyntax": false
  }
}

That solution doesn’t work for me 🙁

I get the error when parsing the actual jest.config.ts file. So the solution has to be somewhere else.

That solution doesn’t work for me 🙁

I get the error when parsing the actual jest.config.ts file. So the solution has to be somewhere else.

yup - same here. the issue always happened when resolving any ESM jest config file (including ts config files), it gave the original error: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.

seems like the issue has to do with parsing the config file in ESM, but typescript is used (I believe) to do so, but TypeScript keeps complaining about "verbatimModuleSyntax" even when you specify a custom tsconfig config or config file in the "transform" key… soo the trick is to just disable the "verbatimModuleSyntax" TS config, BUT you can’t use the new transform key, because that is exactly what is breaking, and so you have to use the now deprecated "globals" key instead, and it just worked for me:

// jest.config.cjs
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
+   globals: {
+     'ts-jest': {
+       useESM: true,
+       tsconfig: {
+         verbatimModuleSyntax: false,
+       },
+     },
+   },
- transform: {
-    '.ts': ['ts-jest', { tsconfig: './tsconfig.jest.json' }],
- },
  preset: 'ts-jest/presets/default-esm',
  testEnvironment: 'node',
};

when i run jest cli, I do get this annoying warning, but tests are running

> jest

ts-jest[ts-jest-transformer] (WARN) Define `ts-jest` config under `globals` is deprecated. Please do
transform: {
    <transform_regex>: ['ts-jest', { /* ts-jest config goes here in Jest */ }],
},
 PASS  test/test1.spec.ts
...

this method very simply disables the "verbatimModuleSyntax" tsconfig value to false when TS is used as a transformer in my tests files, but the normal tsconfig.json still works for the test files in my editor

it seems to me likely that ts-jest is the culprit here as there is strictly different behaviour happening with the globals and the transform keys. pretty clear ts-jest doesn’t support “verbatimModuleSyntax” whatsoever in the like 12 permutations of settings i tried with ESM jest config file. i really did try eveyrthing in this thread and had to give up on “everything” being TS/ESM. is it so hard to use TS for everything and use jest? apparently yes it is haha

don’t exactly have time to create a new issue from this, but is very reproducible if you just switch the place of the tsconfig object/path from transform to globals if anyone else wants to create a new issue for this ongoing bug

Sorry the doc was a bit outdated, there is warning about using transform and preset see https://kulshekhar.github.io/ts-jest/docs/getting-started/options

the doc for ESM needs to be updated accordingly.

the error you saw came from TS type checking similar to tsc which we can’t control which options require ESM.

you should follow the manual configuration under ESM support doc which gives more control

Just commenting here in case most of you are using verbatimModuleSyntax as a linting mechansim so that your eslint auto fixes your imports to type only imports.

https://johnnyreilly.com/typescript-5-importsnotusedasvalues-error-eslint-consistent-type-imports

If you are, then it appears that you only need:

      "rules": {
        "@typescript-eslint/consistent-type-imports": "error"
      }

and if you’re using vscode, then also this in .vscode/settings.json or your *.code-workspace.json#settings

    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.fixAll.eslint": "always", // or explicit
      "source.fixAll": "always",  // or explicit
    },

    "eslint.enable": true,
    "eslint.format.enable": true,

You can can avoid all these errors by not using that option, but still get the eslint behaviour.

Yes i just suggested fixing the problem by turning the errors off. 😅

@juanjoDiaz You can use this PR example to try out https://github.com/kulshekhar/ts-jest/pull/4083 note that, this new tsconfig option only works with ESM mode so you need to choose the correct jest config file in one of those examples

The solution from @seanblonien does not work for me as well. (It’s February 2024). I decided to bury Jest and go with Vitest. In my Svelte project that works out of the box. The question remains as to how long this system will work.

Hi @ahnpnl ,

Thanks for the quick response.

I tried

import preset from 'ts-jest/presets/index.js'

/** @type {import('ts-jest').JestConfigWithTsJest} */
export default {
  ...preset.defaultsESM,
  transform: {
    '^.+\\.tsx?$': [
      'ts-jest',
      {
        useESM: true,
      },
    ],
  },
}

as per the PR but I’m getting the same error.

Can you be a bit more specific on where the issue is and what setting in the config would allow me to treat the “jest.config.ts” as an esm module?

Hi @ahnpnl ,

I’m still facing this issue.

I’ve tried the default preset:

{
  preset: 'ts-jest/presets/default-esm', // or other ESM presets
  moduleNameMapper: { '^(\\.{1,2}/.*)\\.js$': '$1' },
  testEnvironment: 'node',
  testMatch: ['<rootDir>/**/test/*.ts', '<rootDir>/**/test/types/*.ts'],
  collectCoverageFrom: ['src/**'],
}

and the manual config:

{
  extensionsToTreatAsEsm: ['.ts', '.tsx', '.mts'],
  transform: {
    '^.+\\.tsx?$': [
      'ts-jest',
      { useESM: true, isolatedModules: false },
    ],
  },
  moduleNameMapper: { '^(\\.{1,2}/.*)\\.js$': '$1' },
  testEnvironment: 'node',
  testMatch: ['<rootDir>/**/test/*.ts', '<rootDir>/**/test/types/*.ts'],
  collectCoverageFrom: ['src/**'],
}

However, none of them worked. I keep getting jest.config.ts:12:1 - error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.

Any suggestion?