45

Is it possible to test ES6 Modules with Jest without esm or babel? Since node v13 supports es6 natively have tried:

//package.json
{
  …
  "type": "module"
  …
}



//__tests__/a.js
import Foo from '../src/Foo.js';


$ npx jest

Jest encountered an unexpected token
…
Details:

/home/node/xxx/__tests__/a.js:1
import Foo from '../src/Foo.js';
^^^^^^

SyntaxError: Cannot use import statement outside a module

When babel is added a transpiler, it works, but can es6 modules be used natively as well?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
philipp
  • 15,947
  • 15
  • 61
  • 106

6 Answers6

49

Yes, it is possible from jest@25.4.0. From this version, there is a native support of esm, so you will not have to transpile your code with babel anymore.

It is not documented yet, but according to this issue you have to do 3 easy steps to achieve that (At the time of writing this answer):

  • Make sure you don't transform away import statements by setting transform: {} in your jest config file
  • Run node@^12.16.0 || >=13.2.0 with --experimental-vm-modules flag
  • Run your test with jest-environment-node or jest-environment-jsdom-sixteen.

So your jest config file should contain at least this:

export default {
    testEnvironment: 'jest-environment-node',
    transform: {}
    ...
};

And to set --experimental-vm-modules flag, you will have to run Jest from package.json as follows (I hope this will change in the future):

"scripts": {
    "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
}

I hope, this answer was helpful to you.

doppelgreener
  • 4,809
  • 10
  • 46
  • 63
Radovan Kuka
  • 1,962
  • 1
  • 17
  • 19
  • 2
    I tried this but it doesn't really work very well. The `jest` name isn't available within the test module. I'm sure there are other problems too as per the linked issue. Sadly it looks like Babel is the way to go for now. – sdt Oct 03 '20 at 09:29
  • 10
    Didn't work for me using node 14 and jest 26. If I remove `transform` I get the following error `SyntaxError: Cannot use import statement outside a module` – Dmytro Oct 12 '20 at 14:27
  • 5
    I was struggling with the issue described by @sdt, but I finally discovered that the `jest` object "can also be imported explicitly via `import {jest} from '@jest/globals'`" https://jestjs.io/docs/en/jest-object – grvsmth Oct 20 '20 at 17:14
  • 7
    Do not forget to set "type": "module" in package.json – Saeid Nov 21 '20 at 11:31
  • 23
    The changes to the jest config weren't necessary for me. Just specifying `"type": "module"` in the package.json and running node with `--experimental-vm-modules` was enough (Jest 26.6.3 and node v14.15.4). Also a little cleaner way to specify the test command: `"test": "NODE_OPTIONS=--experimental-vm-modules jest"` – Simon Lenz Jan 31 '21 at 12:35
  • 1
    FYI, using ESM in `testEnvironment` was only added in 27.0.0: https://github.com/facebook/jest/pull/11232 – Joshua Pinter May 24 '21 at 19:40
  • Weather not the config change is needed will depend on your setup. import() is understood by both commonJS and ESM and will load either of these. This is needed for mixed settings. In pure esm settings transform: {} insures jest doesn't use babel and mess with things. – wheredidthatnamecomefrom Nov 17 '21 at 20:00
  • I had to add `{ test: /\.m?js/, resolve: {fullySpecified: false}},` in webpack.config.cjs module -> rules to avoid changing all my imports – Remy Mellet Feb 28 '22 at 20:08
  • I got it to work with scripts: {"test": "node --experimental-vm-modules $(yarn bin jest)"} in package.json – Zied Hamdi Sep 07 '22 at 08:26
  • 1
    An update in the answer as of early 2023? – kaushalpranav Jan 20 '23 at 10:07
6

Note that this is is still experimental, but we have documented how to test this, so there's hopefully less confusion.

https://jestjs.io/docs/en/ecmascript-modules

The steps in https://stackoverflow.com/a/61653104/1850276 are correct

SimenB
  • 6,410
  • 2
  • 23
  • 27
4

I followed the tips provided in the accepted answer, but I added the property "type": "module" in my package.json in order to jest works properly. This is what I done:

In package.json:

"devDependencies": {
    "jest": "^26.1.0",
    "jest-environment-jsdom-sixteen": "^1.0.3",
    "jest-environment-node": "^26.1.0"
  },
  "scripts": {
    "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
  },
  "type": "module",
  "jest": {
    "transform": {},
    "testEnvironment": "jest-environment-jsdom-sixteen"
  }
  • 1
    The changes to the jest configuration weren't necessary for me as described [here](https://stackoverflow.com/questions/60372790/node-v13-jest-es6-native-support-for-modules-without-babel-or-esm#comment116654281_61653104) – Simon Lenz Jan 31 '21 at 12:36
3

To run jest from "jest" extension in VSCode with "--experimental-vm-modules" flags, put this config in your global or workspaces settings.json:

"jest.nodeEnv": {

    "NODE_OPTIONS": "--experimental-vm-modules"
}
Gonzalo
  • 468
  • 1
  • 7
  • 17
2

In addition to @Radovan Kuka's answer, here's how to run Jest with ES modules, using npx:

"test:monitoring": "npx --node-arg=--experimental-vm-modules jest -f monitoring.test.js --detectOpenHandles",

The benefit is that one doesn't need to provide the absolute node_modules path.

akauppi
  • 17,018
  • 15
  • 95
  • 120
  • With 27.0.0-next.8, I took the `npx` out of the commands and everything's working fine. – akauppi Apr 16 '21 at 08:50
  • 1
    on npx 8.3.1 it write "npx: the --node-arg argument has been removed." and test continue to fail – pery mimon Feb 21 '22 at 16:11
  • 1
    @perymimon That clearly puts my comments to rest. But so does the soon release of Jest 28 which has native ESM support. – akauppi Feb 21 '22 at 20:06
1

Without Babel, here's a complete, minimal example that works on recent Jest versions. Run with npm test.

$ tree -I node_modules
.
├── package.json
├── src
│   └── foo.js
└── __tests__
    └── foo.spec.js

package.json:

{
  "type": "module",
  "scripts": {
    "test": "NODE_OPTIONS=--experimental-vm-modules jest"
  },
  "devDependencies": {
    "jest": "^29.3.1"
  }
}

src/foo.js:

export const bar = () => 42;

__tests__/foo.spec.js:

import {bar} from "../src/foo";

describe("foo.bar()", () => {
  it("should return 42", () => {
    expect(bar()).toBe(42);
  });
});

The secret sauce is in the package.json: "type": "module" and NODE_OPTIONS=--experimental-vm-modules jest.

If you want to add a mock, it's a bit complicated. See this answer.

ggorlen
  • 44,755
  • 7
  • 76
  • 106