Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: verbatimModuleSyntax support #4081

Closed
simPod opened this issue Apr 3, 2023 · 33 comments
Closed

[Bug]: verbatimModuleSyntax support #4081

simPod opened this issue Apr 3, 2023 · 33 comments
Labels
🚀 Feature Request new suggested feature

Comments

@simPod
Copy link

simPod commented Apr 3, 2023

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
@ahnpnl
Copy link
Collaborator

ahnpnl commented Apr 3, 2023

The error says that option only works with ESM mode while you are using commonjs mode. You can check documentation how to enable ESM mode. Thanks.

@ahnpnl ahnpnl closed this as completed Apr 3, 2023
@ahnpnl ahnpnl added Not An Issue Not ts-jest issue and removed Bug Report Needs Triage labels Apr 3, 2023
@simPod
Copy link
Author

simPod commented Apr 3, 2023

Thanks for reply. I have never seen the docs since I've used jest without esm mode until now with no issues.

However, I've followed the docs. And getting the same error even wit modified config:

/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
  },
  preset: 'ts-jest/presets/default-esm',
  transform: {
    '^.+\\.tsx?$': [
      'ts-jest',
      { useESM: true },
    ],
  },
};

@ahnpnl
Copy link
Collaborator

ahnpnl commented Apr 3, 2023

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

@simPod
Copy link
Author

simPod commented Apr 3, 2023

I have inspected default-esm preset which basically just sets extensionsToTreatAsEsm: ['.ts', '.tsx', '.mts'].
Not sure whether I'm missing something in your reply about we can’t control which options require ESM but I see the same error still.

/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  extensionsToTreatAsEsm: ['.ts', '.tsx', '.mts'],
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
  },
  transform: {
    '^.+\\.tsx?$': [
      'ts-jest',
      { useESM: true },
    ],
  },
};

tsconfig has "module": "ESNext",

@ahnpnl
Copy link
Collaborator

ahnpnl commented Apr 3, 2023

Would you please put a reproduce example with this https://github.com/kulshekhar/ts-jest/tree/main/examples/ts-only

@simPod
Copy link
Author

simPod commented Apr 3, 2023

on it

@simPod
Copy link
Author

simPod commented Apr 3, 2023

#4082

@juanjoDiaz
Copy link

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?

@ahnpnl
Copy link
Collaborator

ahnpnl commented Apr 9, 2023

@juanjoDiaz You can use this PR example to try out #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

@juanjoDiaz
Copy link

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?

@ahnpnl
Copy link
Collaborator

ahnpnl commented Apr 9, 2023

jest.config.ts is not handled by ts-jest but Jest itself does.

@juanjoDiaz
Copy link

But Jest is a js-only solution, right?

If my jest config is a TS file, it must be parsed by ts-node isn't it?
That's where the issue seems to be.

@ahnpnl
Copy link
Collaborator

ahnpnl commented Apr 10, 2023

Jest handles loading config while ts-jest handles transforming test files, source files which are used by test files. Indeed Jest uses ts-node to parse your config file.

@juanjoDiaz
Copy link

Indeed.
So, the issue that I am seeing when parsing the jest config file using the verbatimModuleSyntax option is related to ts-node.
Isn't that related to ts-jest?
Or does jest include its own ts-node to parse config files?

@ahnpnl
Copy link
Collaborator

ahnpnl commented Apr 10, 2023

ts-jest only executes after Jest finishes processing tsconfig. Jest requires you to install ts-node to process Jest ts config. ts-jest doesn’t interfere with how Jest processes config file.

@dustin-ruetz
Copy link

dustin-ruetz commented Apr 11, 2023

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,
+			},
+		],
 	},

@juanjoDiaz
Copy link

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.

@mengxinssfd
Copy link

mengxinssfd commented Apr 20, 2023

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
  }
}

@skjnldsv
Copy link

If you use a jest.config.ts file name, you also need to fix the main tsconfig :/

diff --git a/__tests__/tsconfig.json b/__tests__/tsconfig.json
--- /dev/null
+++ b/__tests__/tsconfig.json
@@ -0,0 +1,6 @@
+{
+	"extends": "../tsconfig.json",
+	"compilerOptions": {
+		"verbatimModuleSyntax": false
+	}
+}
diff --git a/jest.config.ts b/jest.config.ts
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -55,6 +55,10 @@ const config: Config = {
 		// process `*.js` files with `babel-jest`
 		'^.+\\.js$': 'babel-jest',
 		'^.+\\.vue$': '@vue/vue2-jest',
+		'^.+\\.ts$': ['ts-jest', {
+			// @see https://github.com/kulshekhar/ts-jest/issues/4081
+			tsconfig: './__tests__/tsconfig.json',
+		}],
 	},
 	transformIgnorePatterns: [
 		'node_modules/(?!(' + ignorePatterns.join('|') + ')/)',
diff --git a/tsconfig.json b/tsconfig.json
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -19,7 +19,8 @@
 		// these options are overrides used only by ts-node
 		// same as our --compilerOptions flag and our TS_NODE_COMPILER_OPTIONS environment variable
 		"compilerOptions": {
-			"module": "commonjs"
+			"module": "commonjs",
+			"verbatimModuleSyntax": false
 		}
 	}
 }

Aleksbgbg added a commit to Aleksbgbg/streamfox that referenced this issue Jul 15, 2023
@seanblonien
Copy link

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

@KrisSimon
Copy link

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.

@randre70
Copy link

If I have package.json containing "type": "module", node is complaining if .js is missing. Therefore tsconfig.jest.json has to have "verbatimModuleSyntax": true.
I have no cue how to fix this. Why is this issue closed?

@randre70
Copy link

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

Can you point at an example repository where this is working?

@airtonix
Copy link

airtonix commented Mar 18, 2024

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. 😅

rash805115 added a commit to quadnix/octo that referenced this issue Jun 27, 2024
- Because of error "ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled." when running tests.
- The GitHub issue also suggested to just use the eslint version: kulshekhar/ts-jest#4081
@davidandreoletti
Copy link

jest.config.ts is not handled by ts-jest but Jest itself does.

More precisely transpiled by 'ts-node'.

@theycallmeswift
Copy link

This is still an issue in Aug 2024 FYI. Specifically ts-jest does not properly parse jest.config.ts files when "verbatimModuleSyntax": true,

@ahnpnl ahnpnl reopened this Aug 8, 2024
@ahnpnl ahnpnl added 🚀 Feature Request new suggested feature and removed Not An Issue Not ts-jest issue labels Aug 8, 2024
@ahnpnl
Copy link
Collaborator

ahnpnl commented Aug 8, 2024

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

ts-jest doesn't handle parsing of jest.config.ts. ts-jest only transpiles codes which are given by jest-runtime. jest-runtime takes care of reading jest.config.ts

@lvlte
Copy link

lvlte commented Aug 25, 2024

Why is this issue closed as "completed" ?

Suppose you have an ESM module (package.json contains "type": "module") with the following in tsconfig (no path options) :

    "module": "nodenext",
    "moduleResolution": "nodenext",
    "verbatimModuleSyntax": true,
    "esModuleInterop": true

Your jest config (defined in jest.config.js, ie. ts-node not involved), as recommended by the doc (except for the CJS syntax obviously, and without the unnecessary / redundant settings that are already [pre]set) :

export default {
  preset: 'ts-jest/presets/default-esm'
};

You run your tests and get the error : "ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled" 😮.

Adding isolatedModules: true - thanks @dustin-ruetz - makes the error go away :

export default {
  preset: 'ts-jest/presets/default-esm',
  transform: {
    '.ts': [
      'ts-jest',
      {
        isolatedModules: true
      }
    ]
  }
};

😮

Would it not be a bug ?

We shouldn't have to set isolatedModules: true or verbatimModuleSyntax: false to get rid of an error that says our ESM module is a CJS module.

This is not a feature request.

@ahnpnl
Copy link
Collaborator

ahnpnl commented Aug 25, 2024

The original report is about jest config in typescript doesn’t work with this option. We closed this issue because ts-jest doesn’t handle that.

However, your issue is a different one which is related to #4198

@lvlte
Copy link

lvlte commented Aug 25, 2024

We closed this issue because ts-jest doesn’t handle that.

Ok, great.

So why the error doesn't reflect that with a clear message : ts-jest doesn’t handle "verbatimModuleSyntax" ?
Rather than ESM syntax is not allowed in a CommonJS module when "verbatimModuleSyntax" is enabled ?

However, your issue is a different one which is related to #4198

How is it related ?

  • verbatimModuleSyntax is not mentioned at all in the issue description nor in the comments.
  • people say they only encounter the issue with isolatedModules: true, the exact opposite of what people say here.

@ahnpnl
Copy link
Collaborator

ahnpnl commented Aug 25, 2024

I think there are 2 things in this issue: one is about Jest config in typescript doesn't work with verbatimModuleSyntax and one is about transforming issue. At some point, I thought the original issue was about working with jest.config.ts so I closed this issue.

If you have issues with your jest.config.ts, ts-jest can't solve it unfortunately.

If you have transforming issue, for example your other ts files, would you pls provide an example in any of the projects here https://github.com/kulshekhar/ts-jest/tree/main/examples. Based on your input, we can repopen this issue and fix it properly.

@lvlte
Copy link

lvlte commented Aug 25, 2024

All you need to reproduce the issue is in my first comment. The content of my .ts files is not relevant.

Just take an esm package with the config I mentioned and an index.ts file that exports something, then try to import it in a test file and see the results.

Note I use jest.config.js (not .ts).

@edukisto
Copy link

edukisto commented Dec 13, 2024

I guess I found a solution.

  1. Install ts-node.

  2. Create a separate TypeScript configuration file for Jest. Let’s name it tsconfig.jest.json.

    {
      "compilerOptions": {
        "esModuleInterop": true,
        "moduleResolution": "node10",
        "verbatimModuleSyntax": false
      }
    }

    (Alternatively, you can set moduleResolution to bundler. Strategies other than bundler or node10 won’t work.)

  3. Assign the path to the file to the TS_NODE_PROJECT environment variable just before running Jest.

    Bash:

    TS_NODE_PROJECT='./tsconfig.jest.json' npx jest

    CMD:

    set "TS_NODE_PROJECT=./tsconfig.jest.json" npx jest

    Alternatively, for a cross-platform implementation, add

    "scripts": {
      "test": "cross-env TS_NODE_PROJECT=\"./tsconfig.jest.json\" jest"
    }

    to package.json, install cross-env and run npm test.

The above solution will enable ESM syntax in jest.config.ts only. You should also install ts-jest and follow this guidance to enable ESM syntax in test modules. Here is my jest.config.ts:

import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';

const preset = createDefaultEsmPreset({
  // A separate TypeScript configuration file for Jest.
  tsconfig: './tsconfig.jest.json',
});

const jestConfig: JestConfigWithTsJest = {
  ...preset,

  // Other options.
};

export default jestConfig;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🚀 Feature Request new suggested feature
Projects
None yet
Development

No branches or pull requests