Reputation: 3800
I'm trying to write a simple jest test for a 3rd party package were using that only exports an ES module. It's a wrapper around an http
server.
Here is a test repo I setup (just run yarn && yarn jest
to reproduce): https://github.com/jamesopti/hocuspocus-testing
No matter what config I experiment with, I still get this error when trying to run it:
Must use import to load ES Module: /Users/j/hocuspocus-testing/node_modules/@hocuspocus/server/dist/hocuspocus-server.esm.js
> 1 | import { Server, Hocuspocus } from '@hocuspocus/server'
| ^
2 | import * as request from 'supertest'
3 |
4 | describe('Server (e2e)', () => {
Things I've tried already:
The Jest instructions on ES modules: https://jestjs.io/docs/ecmascript-modules
In Jest configuration using transformIgnorePatterns
transformIgnorePatterns: ['node_modules/(?!@hocuspocus/)']
Using Babel via babel-jest
modifying transform setup in Jest configuration as '^.+\.jsx?$': 'babel-jest', '^.+\.tsx?$': 'ts-jest'
Ran into the error You appear to be using a native ECMAScript module configuration file, which is only supported when running Babel asynchronously.
Using .babel.config.js instead of .babelrc.js
Any ideas what I'm missing here? I thought this would be straightforward
[EDIT 1] - Added tsconfig.json
and a working src/index.ts
file to the example repo.
Upvotes: 49
Views: 47056
Reputation: 11771
For what it's worth, the OPs approach of using transformIgnorePatterns
works fine for me - just need to escape the forward slashes.
transformIgnorePatterns: ['node_modules\\/(?!use-local-storage-state\\/)'],
The context this is for is that the package I'm using has code compiled to ESM only, which won't work for jest, and won't be transpiled for CJS because it lives in node_modules.
ie. without the above config, I get this error:
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import useLocalStorageState from './src/useLocalStorageState.js';
^^^^^^
SyntaxError: Cannot use import statement outside a module
Upvotes: 0
Reputation: 6432
Much as I'm loathe to give a "use something else" type answer, I'm going to, even though it may not directly answer the original question.
It does, however, answer the question "How can I make it easy to test my TypeScript files which have ESM dependencies, whilst using Jest syntax?"
After messing around with various jest.config.js
options, with ideas taken from some of these answers, I eventually just did:
npm install -D vitest
... and, it all just worked. No jest.config.js
file. No messing with any other dependencies.
The only change I had to make was to import some test-related functions that you don't have to with Jest:
import { expect, describe, it } from "vitest";
Other than this, it's easy to forget I'm not simply using Jest.
Further detail here: https://vitest.dev/guide/.
EDIT: As suggested in a helpful comment, you can set an option such that importing expect
/ describe
/ it
is not necessary.
See here for details on how to use globals: true
: https://vitest.dev/config/#globals.
Upvotes: 15
Reputation: 1584
JAN 2023: ES2022, TypeScript 4.9.4, jest 29.3.1, ts-jest 29.0.3 FEB 2024: Modified transform file regex based on comment from @vick
This is what worked for me, after 2 hours of frustration.
I used this configuration in jest.config.ts
:
import type { JestConfigWithTsJest } from 'ts-jest'
const config: JestConfigWithTsJest = {
extensionsToTreatAsEsm: ['.ts'],
verbose: true,
preset: 'ts-jest/presets/default-esm',
testEnvironment: 'node',
transform: {
'^.+\\.tsx?$': ['ts-jest', { useESM: true }]
},
testPathIgnorePatterns: ['./dist']
}
export default config
Change the test
script in package.json
to:
I use
pnpm
. Change tonpx jest
with npm, oryarn exec
with yarn
...
"scripts": {
...
"test": "NODE_OPTIONS=--experimental-vm-modules pnpm exec jest",
...
}
...
tsconfig.json
:
{
"compilerOptions": {
"rootDirs": ["src"],
"outDir": "dist",
"lib": ["ES2022"],
"target": "ES2022",
"module": "ES2022",
"composite": true,
"moduleResolution": "node",
"declaration": true,
"declarationMap": true,
"incremental": true,
"esModuleInterop": true,
"types": ["jest", "node", "@types/jest"],
"sourceMap": true
},
"ts-node": {
"esm": true,
"experimentalSpecifierResolution": "node"
},
"include": ["./src/**/*", "./tests/**/*"]
}
See this (rather confusing) documentation for reference: https://kulshekhar.github.io/ts-jest/docs/guides/esm-support/
Upvotes: 19
Reputation: 205
I was having the same problem with my svelte app and testing. I ultimately traced it to having a jest.config.js
and a jest.config.json
in my root folder. It seems that jest does not have automatic config file resolution and was using a default configuration instead of either of my specified configurations.
Upvotes: 1
Reputation: 922
So for anyone still hitting this, ESM configuration explained in this section of documentation :
https://kulshekhar.github.io/ts-jest/docs/guides/esm-support
{
// [...]
"jest": {
"extensionsToTreatAsEsm": [".ts"],
"globals": {
"ts-jest": {
"useESM": true
}
}
}
}
Upvotes: 29
Reputation: 8718
You don't have a tsconfig.json
file that specifies module
. Therefore it uses the default, where it transpiles all your modules to CommonJS
syntax, which uses require
.
If you actually look at your dist/hocuspocus-server.esm.js
, you should see it using require
over the ESM import syntax.
Upvotes: 2