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

[babel-jest] mjs files #4637

Closed
elegos opened this issue Oct 9, 2017 · 27 comments
Closed

[babel-jest] mjs files #4637

elegos opened this issue Oct 9, 2017 · 27 comments

Comments

@elegos
Copy link

elegos commented Oct 9, 2017

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

@mknet
Copy link

mknet commented Oct 25, 2017

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.

@kirlat
Copy link

kirlat commented Nov 4, 2017

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

@blakedietz
Copy link

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

@awidjaja
Copy link

awidjaja commented Dec 9, 2017

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

@drownbes
Copy link
Contributor

drownbes commented Dec 18, 2017

@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

@AngryPidgeon
Copy link

AngryPidgeon commented Mar 8, 2018

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

@haraldrudell
Copy link

haraldrudell commented Apr 29, 2018

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

@dpickett
Copy link

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

@dandv
Copy link
Contributor

dandv commented Jul 15, 2018

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.

@mbrowne
Copy link

mbrowne commented Sep 4, 2018

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

@SimenB
Copy link
Member

SimenB commented Sep 22, 2018

Comment above is correct 🙂

@SimenB SimenB closed this as completed Sep 22, 2018
@dandv
Copy link
Contributor

dandv commented Sep 26, 2018

@mbrowne this solution was already mentioned in #4637 (comment)

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

@SimenB
Copy link
Member

SimenB commented Sep 26, 2018

PR most definitely for documenting mjs usage.

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

@SimenB
Copy link
Member

SimenB commented Sep 27, 2018

@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

@SimenB
Copy link
Member

SimenB commented Sep 28, 2018

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: nodejs/modules#180

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

@MylesBorins
Copy link

MylesBorins commented Oct 2, 2018

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

@dandv
Copy link
Contributor

dandv commented Oct 6, 2018

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

@SimenB
Copy link
Member

SimenB commented Oct 6, 2018

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

@dandv
Copy link
Contributor

dandv commented Apr 28, 2019

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?

@jeysal
Copy link
Contributor

jeysal commented Apr 28, 2019

nodejs/node#27387 may be of interest

@martinmckenna
Copy link

martinmckenna commented Aug 13, 2019

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

ramda/ramda@79a7d9d

Is there a way to fix this issue with Babel?

@martinmckenna
Copy link

martinmckenna commented Aug 15, 2019

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

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

@dandv
Copy link
Contributor

dandv commented Dec 5, 2019

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

@OZZlE
Copy link

OZZlE commented Jan 15, 2021

None of this works..

_reactDom.default.render(<_Index.default />, document.getElementById('main'));
                         ^

SyntaxError: Unexpected token <

> 1 | import App from './app';

app.test.mjs

import App from 'app'; // (app.jsx)

app.jsx

    import React from 'react';
    import ReactDOM from 'react-dom';
    import Index from './Pages/Index';

    ReactDOM.render(<Index />, document.getElementById('main'));

jest.config.js

module.exports = {
  testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|js?|tsx?|ts|mjs?)$',
  transform: {
    '^.+\\.jsx?$': 'babel-jest',
    '^.+\\.mjs$': 'babel-jest',
    '^.+\\.ts$': 'babel-jest',
    '^.+\\.tsx$': 'babel-jest',
  },
  testPathIgnorePatterns: ['<rootDir>/build/', '<rootDir>/node_modules/'],
  moduleFileExtensions: ['js', 'jsx', 'mjs', 'ts', 'tsx'],
};

babel.config.js

const presets = [
  [
    '@babel/preset-env',
    {
      targets: {
        esmodules: true,
      },
      corejs: {
        version: '3',
        proposals: true,
      },
      useBuiltIns: 'entry',
    },
    '@babel/preset-react',
  ],
];
const plugins = [
  '@babel/plugin-proposal-class-properties',
  '@babel/plugin-proposal-function-bind',
  '@babel/plugin-transform-runtime',
  '@babel/plugin-syntax-jsx',
];

module.exports = { presets, plugins };

package.json

"testJest": "node --experimental-modules node_modules/jest/bin/jest.js --config=jest.config.js"

no luck still above error

@SimenB
Copy link
Member

SimenB commented Jan 15, 2021

@OZZlE
Copy link

OZZlE commented Jan 16, 2021

@OZZlE see https://jestjs.io/docs/en/ecmascript-modules

Thanks I see now that I missed the transform part, I changed it to {} like it says and I've tried to run it with

node --experimental-vm-modules node_modules/jest/bin/jest.js --config=jest.config.js

or (more correctly?):

node --experimental-modules node_modules/jest/bin/jest.js --config=jest.config.js

I still get:

(node:49261) ExperimentalWarning: The ESM module loader is experimental.
 FAIL  app/app.test.mjs
  ● Test suite failed to run

    /Volumes/Projects/node-express/contenful-category/app/app.test.mjs:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import App from './app';
                                                                                                    ^^^

    SyntaxError: Unexpected identifier

or

> node --experimental-vm-modules node_modules/jest/bin/jest.js --config=jest.config.js

 FAIL  app/app.test.mjs
  ● Test suite failed to run

    /Volumes/Projects/node-express/contenful-category/app/app.test.mjs:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import App from './app';
                                                                                                    ^^^

    SyntaxError: Unexpected identifier

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests