Jest: Only in coverage mode, latest babel: 'import' and 'export' may appear only with 'sourceType: "module"'

Created on 23 Apr 2018  ·  23Comments  ·  Source: facebook/jest

Do you want to request a _feature_ or report a _bug_?

Bug

What is the current behavior?

Since updating to Babel 7.0-beta.46, Jest fails only when using --coverage with this error:

ERROR: 'import' and 'export' may appear only with 'sourceType: "module"' (8:0)
STACK: SyntaxError: 'import' and 'export' may appear only with 'sourceType: "module"' (1:0)
    at Parser.pp$5.raise (/Users/fakepath/node_modules/babylon/lib/index.js:4454:13)
    at Parser.pp$1.parseStatement (/Users/fakepath/node_modules/babylon/lib/index.js:1881:16)
    at Parser.parseStatement (/Users/fakepath/node_modules/babylon/lib/index.js:5910:22)
    at Parser.pp$1.parseBlockBody (/Users/fakepath/node_modules/babylon/lib/index.js:2268:21)
    at Parser.pp$1.parseTopLevel (/Users/fakepath/node_modules/babylon/lib/index.js:1778:8)
    at Parser.parse (/Users/adrien/fakepath/node_modules/babylon/lib/index.js:1673:17)
    at Object.parse (/Users/fakepath/node_modules/babylon/lib/index.js:7305:37)
    at Instrumenter.instrumentSync (/Users/fakepath/node_modules/istanbul-lib-instrument/dist/instrumenter.js:123:31)
    at exports.default (/Users/fakepath/node_modules/jest-cli/build/generate_empty_coverage.js:18:18)
    at Object.worker (/Users/fakepath/node_modules/jest-cli/build/reporters/coverage_worker.js:48:84)
Failed to collect coverage from /Users/fakepath/src/utils/Utils.js

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.

Couldn't manage to reproduce it in a minimal environment (yet). Still working on it.

What is the expected behavior?

Jest should work the same with or without --coverage

Please provide your exact Jest configuration

const path = require('path');

const configBase = {
  collectCoverageFrom: ['**/utils/*.js', '!**/lib/utils/**'],
  coverageDirectory: path.join(__dirname, '../../coverage'),
  moduleNameMapper: {
    '\\.(css|scss)$': 'identity-obj-proxy',
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': path.join(
      __dirname,
      'node_modules/shared/__mocks__/fileMock.js',
    ),
  },
  moduleDirectories: ['../../node_modules', 'node_modules'],
  modulePaths: [path.join(__dirname, 'client')],
  rootDir: __dirname,
  roots: [__dirname],
  testRegex: '\\.test\\.js$',
};

const configJUnit = process.env.JEST_JUNIT_OUTPUT
  ? {
      testResultsProcessor: 'jest-junit',
    }
  : {};

module.exports = Object.assign({}, configBase, configJUnit);

Run npx envinfo --preset jest in your project directory and paste the
results here

  System:
    OS: macOS High Sierra 10.13.4
    CPU: x64 Intel(R) Core(TM) i7-7567U CPU @ 3.50GHz
  Binaries:
    Node: 8.11.1 - /usr/local/bin/node
    Yarn: 1.5.1 - /usr/local/bin/yarn
    npm: 5.6.0 - /usr/local/bin/npm
Needs More Info

Most helpful comment

Babel beta.45/beta.46 introduces a breaking change that will primarily affect monorepo users, and people compiling node_modules files. .babelrc searching now

  • Stops at the first package.json it finds relative to the file being compiled, so things in sub-packages will not find a root-level .babelrc
  • Only searches if the file being compiled is inside of the "root" package, which means it will skip searching for .babelrc files entirely for sub-packages in a repo

In most monorepos, that means that a config at the root will be ignored, and configs in sub-packages will also.

To have a config at the root of your monorepo, you should name the file babel.config.js, which is a new non-hierarchical config file that loads from the root directory.
If you want to keep per-package configs, instead you'll want to enable configs in packages/*/.babelrc to work in a monorepo by passing Babel

babelrcRoots: "packages/*"

in the programmatic options.

For people compiling node_modules this is also a change, because a .babelrc in one package will not affect that package's node_modules. You'll also want to rename your project-root .babelrc to a babel.config.js file exporting the config, to do that.

If your config _doesn't_ fall into one of those changes, then there could always still be a bug somewhere.

All 23 comments

I upgraded to latest packages (I do this once a week) and my tests stopped working too, but not only in coverage mode.
Look like that something changed in babel and/or jest runtime:

  ● Test suite failed to run

    …/src/redux/middleware/logger/logger.server.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { inspect } from 'util';
                                                                                             ^^^^^^

    SyntaxError: Unexpected token import

      10 | export default function configureStore(
      11 |   initialState: State,
    > 12 |   helpers: ThunkExtra,
      13 | ): Store {
      14 |   const middleware = [thunk.withExtraArgument(helpers)];
      15 | 

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:316:17)
      at Object.<anonymous> (src/redux/configureStore.js:12:38)
      at Object.<anonymous> (src/redux/__tests__/store.test.js:3:46)

and

  ● Test suite failed to run

    SyntaxError: …/src/core/intl/getMessages/getMessages.server.js: Unexpected token, expected "," (22:38)

      20 | }
      21 | 
    > 22 | export async function getMessages(lang: LanguageCode) {
         |                                       ^
      23 |   if (messagesCache[lang]) return messagesCache[lang];
      24 | 
      25 |   console.warn('getMessages', lang);

      at Parser.raise (node_modules/@babel/core/node_modules/babylon/lib/index.js:779:15)
      at Parser.unexpected (node_modules/@babel/core/node_modules/babylon/lib/index.js:2082:16)
      at Parser.expect (node_modules/@babel/core/node_modules/babylon/lib/index.js:2070:28)
      at Parser.parseBindingList (node_modules/@babel/core/node_modules/babylon/lib/index.js:2354:14)
      at Parser.parseFunctionParams (node_modules/@babel/core/node_modules/babylon/lib/index.js:4647:24)
      at Parser.parseFunction (node_modules/@babel/core/node_modules/babylon/lib/index.js:4634:10)
      at Parser.parseStatementContent (node_modules/@babel/core/node_modules/babylon/lib/index.js:4068:25)
      at Parser.parseStatement (node_modules/@babel/core/node_modules/babylon/lib/index.js:3963:17)
      at Parser.parseExportDeclaration (node_modules/@babel/core/node_modules/babylon/lib/index.js:5029:17)
      at Parser.parseExport (node_modules/@babel/core/node_modules/babylon/lib/index.js:4994:31)

My .babelrc.js:

// Babel configuration
// https://babeljs.io/docs/usage/api/
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 'current',
        },
      },
    ],
    ['@babel/preset-stage-2', { decoratorsLegacy: true }],
    '@babel/preset-flow',
    '@babel/preset-react',
  ],
  // ignore: ['node_modules', 'build'],
  env: {
    test: {
      presets: [
        // A Babel preset that can automatically determine the Babel plugins and polyfills
        // https://github.com/babel/babel-preset-env
        [
          '@babel/preset-env',
          {
            targets: {
              node: 'current',
            },
            modules: 'commonjs',
            useBuiltIns: false,
            debug: false,
          },
        ],
        // Experimental ECMAScript proposals
        // https://babeljs.io/docs/plugins/#presets-stage-x-experimental-presets-
        ['@babel/preset-stage-2', { decoratorsLegacy: true }],
        // Flow
        // https://github.com/babel/babel/tree/master/packages/babel-preset-flow
        '@babel/preset-flow',
        // JSX
        // https://github.com/babel/babel/tree/master/packages/babel-preset-react
        '@babel/preset-react',
      ],
      plugins: [
        'transform-es2015-modules-commonjs',
        'babel-plugin-dynamic-import-node',
      ],
    },
  },
};

Does it happen with beta.40? In beta.41 they introduced this change: https://github.com/babel/babel/pull/7417

It worked with beta.44, I'm now on beta.46

cc @loganfsmyth @SimenB

Forgot to mention it worked with beta.44, but not since beta.46 too.

I discovered that breakage is between babel 7.0.0-beta.44 and 7.0.0-beta.45

This isn't a bug in Jest, babel did something. Not sure if we need to track it here?

If babel guys (@hzoo, …) think that they are doing well, jest must take an action… so it's tightly connected.
I really don't know where problem is, but babel works with webpack, so the bug is on the jest side?

Is there a repository or branch somewhere I can test with? I can figure out what's changed.

Got the same problem. Renaming .babelrc.js to babel.config.js fixed it

Babel beta.45/beta.46 introduces a breaking change that will primarily affect monorepo users, and people compiling node_modules files. .babelrc searching now

  • Stops at the first package.json it finds relative to the file being compiled, so things in sub-packages will not find a root-level .babelrc
  • Only searches if the file being compiled is inside of the "root" package, which means it will skip searching for .babelrc files entirely for sub-packages in a repo

In most monorepos, that means that a config at the root will be ignored, and configs in sub-packages will also.

To have a config at the root of your monorepo, you should name the file babel.config.js, which is a new non-hierarchical config file that loads from the root directory.
If you want to keep per-package configs, instead you'll want to enable configs in packages/*/.babelrc to work in a monorepo by passing Babel

babelrcRoots: "packages/*"

in the programmatic options.

For people compiling node_modules this is also a change, because a .babelrc in one package will not affect that package's node_modules. You'll also want to rename your project-root .babelrc to a babel.config.js file exporting the config, to do that.

If your config _doesn't_ fall into one of those changes, then there could always still be a bug somewhere.

Thanks for the detailed explanation @loganfsmyth!

Also if it's helpful, here's the PR in Babel for this change https://github.com/babel/babel/pull/7784

@SimenB doesbabel-jest package require any changes to handle new babel.config.js?

For cache-busting purposes, we should. But I don't _think_ it's needed to work. Are you still having issues? If so, please setup a reproduction.

See https://github.com/facebook/jest/blob/eb3ba0f31fea13fdc90bec0ba35deef6ce3bdf1e/packages/babel-jest/src/index.js#L101

@loganfsmyth Does babel.config.js merge with my sub-package's local .babelrc?

If so, is there a way to use .babelrc instead of babel.config.js on a per-package basis? (Maybe https://github.com/babel/website/blob/master/docs/babelrc.md#overrides?)

Should I remove the babel.config.js from my project and rely on local .babelrcs (by setting babelrcRoots)?


Just tested, the config is indeed merged. babel.config.js > .babelrc > programmatic.

Also, I think its really bad to merge the configs. We should favor composition over inheritance. I.e. If you need the top-level config you should explicitly require it from your local .babelrc. So babel.config.js should be overridden entirely by .babelrc.


At present there seems no easy way to use a babel configuration for all packages, and then override on a per-package basis. You are forced to add a .babelrc for every package in the monorepo (there could be 100s of packages) if you want to use a custom overriding config for even just 1 package.


overrides helped me along a bit. Does an override replace all config when it matches?

Might be best to continue this discussion in Babel's Slack or something to avoid pinging everyone on this issue, but here's my thoughts, assuming I understand what you're asking.

Does babel.config.js merge with my sub-package's local .babelrc?

Yes, we perform merging, with .babelrcs overriding individual fields in babel.config.js, and plugins/presets merging based on identity of the entry, and programmatic config merging on top of config files.

If so, is there a way to use .babelrc instead of babel.config.js on a per-package basis?

The goal of the babel.config.js is to be one central config that applies consistently to one project-level instance of Babel, whereas individual .babelrc files are relative to the file being compiled. If there are subfolders where that config should not apply, using test/include/exclude in the config seems like the correct approach to me. If you're fully disabling the babel.config.js, you don't even need overrides, test/include/exclude are also allowed in the top-level configuration object.

Also, I think its really bad to merge the configs. We should favor composition over inheritance.

We merge because merging is already a necessary feature in order to support extends, env, and overrides. I don't anticipate that people would often actually rely on it, but I think entirely ignoring a previous config would also be surprising for users because it's not clear when it would and would not happen. I'd rather leave that up to users to define when and where configs should apply.

At present there seems no easy way to use a babel configuration for all packages, and then override on a per-package basis. You are forced to add a .babelrc for every package in the monorepo (there could be 100s of packages) if you want to use a custom overriding config for even just 1 package.

I don't follow what you mean here. Why would you have to add a .babelrc to every package? As mentioned already, you have overrides + test/include/exclude and babelrcRoots and combined those would allow you to enable .babelrc resolution for all subpackages.

I don't follow what you mean here. Why would you have to add a .babelrc to every package? As mentioned already, you have overrides + test/include/exclude and babelrcRoots and combined those would allow you to enable .babelrc resolution for all subpackages.

I only learned about overrides after posting my initial comment. This does seem to solve my problem.

anybody has an example of lerna using jest with babelrcRoots?

@sibelius Example using yarn workspaces (not lerna, but shouldn't be too different).

@vikr01 I'd like an example like this one https://github.com/paularmstrong/jest-multi-project-example

one jest.config.js in the root that have the packages option, and then each package has it's own jest.config.js config

I'm trying to fix this in this boilerplate/playground: https://github.com/entria/entria-fullstack, but jest is not transpiling tests inside packages, neither when using babelrcRoots

I also had this issue, try doing it this way: https://babeljs.io/docs/en/config-files#jest

So, dont put babelrcRoots in babel.config.js, use transform in root jest.config.js

is there an example repo?

Was this page helpful?
0 / 5 - 0 ratings