Jest: [babel-jest] mjs files

Created on 9 Oct 2017  ·  23Comments  ·  Source: facebook/jest

Do you want to request a feature or report a bug?
bug

What is the current behavior?
babel-jest is not able to transpile es6 module statements if in *.mjs files

If the current behavior is a bug, please provide the steps to reproduce and either a repl.it demo through https://repl.it/languages/jest or a minimal repository on GitHub that we can yarn install and yarn test.

https://repl.it/MU09/0

What is the expected behavior?
Babel should transpile module import/export statements also with mjs files

Please provide your exact Jest configuration and mention your Jest, node, yarn/npm version and operating system.

jest.config.js

module.exports = {
  verbose: true,
  moduleDirectories: ['node_modules', 'imports'],
  testMatch: ['/tests/**/*.js', '**/?(*.)test.js'],
  transform: {
    '^.+\\.m?js$': 'babel-jest',
  },
}

.babelrc

{
  "env": {
    "test": {
      "presets": [
        ["es2015", { "modules": false }]
      ],
      "plugins": [
        ["transform-es2015-modules-commonjs", {
          "spec": true
        }]
      ]
    }
  }
}

Note: I've tried disabling the transform-es2015-modules-commonjs plugin, but then the syntax error is back in the test js file

Node: v8.6
babel-core: 6.26.0
babel-jest: 21.2.0
babel-plugin-transform-es2015-modules-commonjs: 6.24.1
babel-preset-es2015: 6.24.1
jest: 21.2.0

Example output error:

yarn run v1.1.0
$ jest
 FAIL  tests/integration/controller/data-provider/Credentials/CredentialsList.action.test.js
  ● Test suite failed to run

    /app/tests/integration/controller/data-provider/Credentials/CredentialsList.action.test.js:2
    import { Credentials, AdWordsCredentials } from '../../../../../imports/models/data-provider/Credentials.mjs';
    ^^^^^^

    SyntaxError: Unexpected token import

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:305:17)
          at Generator.next (<anonymous>)
          at Promise (<anonymous>)

P.S.
If I call my test files ending with .test.mjs and I edit the testMatch accordingly, jest won't recognize them

Most helpful comment

Any updates now that ES modules are no longer behind an experimental flag?

All 23 comments

Another way expect from transpiring with babel would be to use experimental ES6 module support, see https://nodejs.org/dist/latest-v8.x/docs/api/esm.html

I am currently trying to extend the testMatchers like this:

  "jest": {
    "verbose": true,
    "testMatch": ["**/__tests__/**/*.?(m)js?(x)", "**/?(*.)(spec|test).?(m)js?(x)"]
  }

but still my test named [test].test.mjs is still not found.

@mknet ,
I'm ashamed to say that I don't fully understand the Jest matching pattern. It does not make sense to me at all: at js?(x) ? should be applied to s meaning either jx or jsx would be a match which seems strange.

So not fully understating it, I used a plain stupid approach with:

"testMatch": [ "**/__tests__/**/*.js?(x)", "**/?(*.)(spec|test).js?(x)", "**/__tests__/**/*.mjs", "**/?(*.)(spec|test).mjs" ]

and that (probably not even surprisingly to me) worked.

We also need to specify --experimental-modules node flag to make node recognize ESM modules.

But still, with all that it fails to me with the error similar to the one @elegos reports :-(. Wish there were better support of ESM in Jest. Because ESM's are great, I believe.

So to clarify, this still doesn't work from what I can tell.

@kirlat
Your matching pattern doesn't work for me.

@elegos You need to add moduleFileExtensions: ["js", "json", "jsx", "node", "mjs"]. It will find mjs files, but they are not supported by now, as I understood. It hardcoded in babel-core 6.
https://github.com/babel/babel/blob/v6.26.0/packages/babel-core/src/util.js#L15
And it is extended to mjs in babel 7 beta

Came here because I added a transform to my package.json to transpile files with the .es6 label. It didn't work until also adding ".es6" to moduleFileExtensions

"transform": { "^.+\\.jsx?$": "/Users/.../node_modules/babel-jest/build/index.js", "^.+\\.es6$": "/Users/.../node_modules/babel-jest/build/index.js" }

The get-around as of jest 22.4.3 and babel-core 6.26.3:

  • jest must find .test.mjs files: testMatch and moduleFileExtensions required
  • jest tests must be able to handle the import keyword: transform, babel/env/test, babel-preset-es2015 required

Therefore insert the following into package.json:

"jest": {
"testMatch": [
"**/__tests__/**/*.?(m)js?(x)",
"**/?(*.)(spec|test).?(m)js?(x)"
],
"moduleFileExtensions": [
"js",
"json",
"jsx",
"node",
"mjs"
],
"transform": {
"^.+\.m?js$": "babel-jest"
}
},
"babel": {
"env": {
"test": {
"presets": [["es2015",{"modules": false}]],
"plugins": [["transform-es2015-modules-commonjs", {"spec": true}]]
}
}
},

add preset:
yarn add --dev babel-preset-es2015 babel-plugin-transform-es2015-modules-commonjs babel-jest babel-core

yarn test now works with tests named .test.mjs and source files named .mjs

thank you @haraldrudell your solution saved me a lot of hairpulling. Your solution also works with Babel7 once plugin names are adjusted.

.babelrc:

{
  "env": {
    "test": {
      "presets": [["@babel/preset-env",{"modules": false}]],
      "plugins": [["@babel/plugin-transform-modules-commonjs", {"spec": true}]]
    }
  }
}

yarn add --dev @babel/preset-env @babel/core @babel/plugin-transform-modules-commonjs babel-jest

Isn't this a dupe of #4842?

@haraldrudell: can you please format that package.json code as a code block, using three backticks? Also, I get a syntax error due to the \ in the key under transform. An alternative that still matches a period is [.]. Also, no need for [[. Just [ is enough.

@kirlat: that glob pattern is confusing because you were expecting a regular expression, but testMatch uses micromatch and those are extended globbing patterns (or shell regular expressions). In your example, ?(expression) means the expression may appear or not. In this case, x may or may not be present, so Jest matches .js and .jsx.

In my case all I needed to do to get it working was add transform and moduleFileExtensions options in package.json:

  "jest": {
    "transform": {
      ...
      "^.+\\.mjs$": "babel-jest"
    },
    ...
    "moduleFileExtensions": [
      ...
      "mjs"
    ],

(Of course if you don't already have the babel-jest package installed you will need to install it with npm install -D or yarn add -D.)

Comment above is correct 🙂

@mbrowne this solution was already mentioned in https://github.com/facebook/jest/issues/4637#issuecomment-385291263

@SimenB: the problem isn't entirely solved. I'm using the settings listed by @mbrowne, but get weird errors with imports from CommonJS modules. Here's a reproduction repo: https://github.com/dandv/jest-mjs-devx

Please re-open. .mjs files have been around since Node v8.5.0 but the developer experience using them in Jest is pretty poor. If there is a clear solution for being able to use them, including my use case above, I would love to know about it. But right now, it's a shot in the dark and devs have to rummage through GitHub comments to figure out how to use them.

Using .mjs files is something that should be cleanly documented.

PR most definitely for documenting mjs usage.

Thanks for the reproduction, I'll take a look later today!

@dandv this is a problem with graphql-tools - they have transpiled away their import/export, so it's not compatible with babel and actual ESModules at the same time.

This fixes your test, but makes npm start fail.

diff --git i/basic.test.mjs w/basic.test.mjs
index 972110c..427162c 100644
--- i/basic.test.mjs
+++ w/basic.test.mjs
@@ -1,5 +1,5 @@
 import { makeSchema } from './lib';

 test('basic test', () => {
-  expect(makeSchema).toNotBe(null);
+  expect(makeSchema).not.toBe(null);
 });
diff --git i/lib.mjs w/lib.mjs
index 5717d51..81e22e0 100644
--- i/lib.mjs
+++ w/lib.mjs
@@ -1,5 +1,6 @@
-import graphQLTools from 'graphql-tools';
-export const makeSchema = graphQLTools.makeExecutableSchema({
+import { makeExecutableSchema } from 'graphql-tools';
+
+export const makeSchema = makeExecutableSchema({
   typeDefs: 'type Foo { bar: Int! }',
   resolvers: {},
 });

The way of importing I changed to is the way it's documented here: https://github.com/apollographql/graphql-tools. The fact that doesn't work with Node's esm mode is not Jest's fault

Also note that the current implementation in node might be pulled and redone, so asking the ecosystem to change so you can use experimental flags with their current behavior might not be the best way forward: https://github.com/nodejs/modules/pull/180

Something like @std/esm on your side is probably a better solution than --experimental-modules

re: nodejs/modules#180

it isn't getting pulled, but we are removing some of the features. .mjs is currently not going anywhere. We are also in the process of getting this standardized with the ietf

Edit: to be clear I meant not going anywhere as in it is not going to disappear, we believe it will stick around for all future implementations

@SimenB: any idea how to actually get @std/esm to work with Jest?

See #7018 for latest progress on that, although that proposal will not work alongside babel-jest

not going anywhere as in it is not going to disappear, we believe it will stick around for all future implementations

Indeed, v12 released new experimental support for .mjs. Any updates in the light of that?

I have a node_module (Ramda) that is building to a .mjs file. And now I have tests failing that are relying on ramda.

https://github.com/ramda/ramda/commit/79a7d9d893dd50c995b25b8fd4e1ecd8e96a4abc

Is there a way to fix this issue with Babel?

Here's what I did in my package.json to fix this issue I was having ^^^^

"jest": {
    "moduleNameMapper": {
      "ramda": "ramda/src/index.js",
    }
}

Any updates now that ES modules are no longer behind an experimental flag?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ianp picture ianp  ·  3Comments

kentor picture kentor  ·  3Comments

mmcgahan picture mmcgahan  ·  3Comments

jardakotesovec picture jardakotesovec  ·  3Comments

ticky picture ticky  ·  3Comments