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

Jest: SyntaxError: Unexpected token 'export' on "@bundled-es-modules/js-levenshtein" #1810

Closed
4 tasks done
RobinClowers opened this issue Oct 30, 2023 · 5 comments
Closed
4 tasks done
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:browser Related to MSW running in a browser

Comments

@RobinClowers
Copy link

Prerequisites

Environment check

  • I'm using the latest msw version
  • I'm using Node.js version 14 or higher

Browsers

Chromium (Chrome, Brave, etc.)

Reproduction repository

https://github.com/RobinClowers/msw-jest-esm-error

Reproduction steps

npm i && npx jest

Current behavior

It appears that msw is importing an ESM package, which seem to fail unless my package is configured to be an ESM.

  ● Test suite failed to run

    Jest encountered an unexpected token

    Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

    Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

    By default "node_modules" folder is ignored by transformers.

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
     • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/configuration
    For information about custom transformations, see:
    https://jestjs.io/docs/code-transformation

    Details:

    /Users/robinclowers/src/msw-jest-esm-error/node_modules/@bundled-es-modules/js-levenshtein/index-esm.js:116
    export {
    ^^^^^^

    SyntaxError: Unexpected token 'export'

      1 | import { render, screen } from "@testing-library/react";
      2 | import App from "./App";
    > 3 | import { http, setupServer, HttpResponse } from "msw/node";
        | ^
      4 |
      5 | export default setupServer(
      6 |   http.get("*/api", () => {

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
      at Object.<anonymous> (src/App.test.js:3:1)

Expected behavior

The test should run successfully.

@RobinClowers RobinClowers added bug Something isn't working needs:triage Issues that have not been investigated yet. scope:browser Related to MSW running in a browser labels Oct 30, 2023
@pord911
Copy link

pord911 commented Oct 31, 2023

I got the same issue. After some troubleshooting, I found that it's more to do with the jest-runner and esm to cjs transformation than mock service worker.

The problem
msw uses a library @bundled-es-modules/js-levenshtein which is transpiled and bundled with esbuild. The end result is an index-cjs.cjs file (common js) and (index-esm.js) (EcmaScript module). You can find the bundled library here. In the libraries package.json, one can see that "main" property points to "index-esm.js".

Now, jest-runner looks for files to load and parse by using the "main" property of each of the package.json. This is all taken from the modules that are involved in a test. After jest-runner found all of the files involved in a test run, it loads their code and tries to parse it with node:vm.Script. And this is the point where it fails, once the Script class tries to parse "index-esm.js" code, it fails with a SyntaxError as soon as it hits an EcmaScript construct, in this case "export" keyword. Since, it expects a commonjs (cjs) syntax, and it received an ESM one.

Quick fix
The index-esm.js will have to be transformed before hitting the Script parsing. So, one way to have a quick fix is to update jest config "transformIgnorePatterns" to fail (not ignore) if it sees esm.js but still pass if it sees i.e. index.js. With this fix, your index-esm.js will be transformed with babelTransform.js from the "transform" config property.

Example for transformIgnorePatterns:

    "transformIgnorePatterns": [
      "[/\\\\]node_modules[/\\\\].+[^esm]\\.(js|jsx|mjs|cjs|ts|tsx)$",
      "^.+\\.module\\.(css|sass|scss)$"
    ],

Note, I haven't had time to test it properly, I quickly hacked it just to get it working, but this should be a clean quick fix if the regex pattern is done correctly.

A bit bigger problem
Anyone using create react app to manage their test and build is going to have a problem because jest config is hidden in react-scripts node module. And from what I've seen, seems that create react app is dead. The only option is to eject or move to another testing framework which might not have this problem.

Going forward
Further investigation should be done to see if @bundled-es-modules/js-levenshtein/index-cjs.cjs can me loaded automatically, because it is there, it's just not picked up by jest-runner. This would be more of a query for the jest people, but given that esbuild bundler has just started, it's highly unlikely that someone in jest will pay attention. Worth a try though. Or the msw uses a different library to do the same job. Currently, this issue is a blocker for anyone running msw with jest and create react app. But it's not a direct problem on msw.

NOTE: I'm running node 18, jest 27, react-scripts 5.0.1, and msw 2.0.0.

@kettanaito
Copy link
Member

kettanaito commented Oct 31, 2023

Thanks for reporting this. Jest is historically bad with ESM and I don't believe they support it properly yet. If you can, consider migrating to modern test frameworks, like Vitest. There are no module issues there, as long as a number of other issues you may find with Jest.

The same goes for Create React App. The project is officially dead, and the React team recommends using a production-grade framework like Next.js or Remix instead. Again, migrate at your own consideration and possibilities.

If migrating is not an option for you, follow @pord911's advice and configure the transformIgnorePatterns to completely ignore dependencies under the @bundled-es-modules scope. Let me know if that helps.

@kettanaito kettanaito changed the title ESM error with jest Jest: SyntaxError: Unexpected token 'export' on "@bundled-es-modules/js-levenshtein" Oct 31, 2023
@RobinClowers
Copy link
Author

Thank you both for the quick responses!

I don't use CRA, I just used it to create an example.

@kettanaito I understand your frustration with jest, but I don't think most teams are going to migrate test frameworks when they run into an issue upgrading a library.

@pord911 thanks for the suggestion! For anyone else coming across this issue, here is what was needed to make this work:

In my jest config, I had to change the preset so it would transform ESM to commonjs. By default ts-jest only transforms typescript, not javascript. I also had to update transformIgnorePatterns to include the bundled-es-modules packages, since by default jest does not transform node_modules.

  preset: "ts-jest/presets/js-with-babel",
  transformIgnorePatterns: ["/node_modules/(?!(@bundled-es-modules)/)"],

Useful jest docs:
https://kulshekhar.github.io/ts-jest/docs/27.1/getting-started/presets
https://jestjs.io/docs/tutorial-react-native#transformignorepatterns-customization

@kettanaito
Copy link
Member

I understand your frustration with jest, but I don't think most teams are going to migrate test frameworks when they run into an issue upgrading a library.

They will migrate sooner or later. I'd rather MSW incentivizes them to do that sooner. Jest doesn't support ESM, and by the looks of it, never will. MSW has been historically helpful in highlighting problematics application areas by relying on standards. This is yet another example of it.

Anything that makes Jest happy with proper export conditions and ESM works.

@Maryam1982
Copy link

Hi everybody
I followed your solutions but the bug does not go away.
//jest-config.json
{
"collectCoverage": true,
"testEnvironment": "./jsdom-extended.js",
"transformIgnorePatterns": ["/node_modules/(?!(@bundled-es-modules)/)"]
}

//jsdom-extended.js
/const JSDOMEnvironment = require("jest-environment-jsdom"); // or import JSDOMEnvironment from 'jest-environment-jsdom' if you are using ESM modules

class JSDOMEnvironmentExtended extends JSDOMEnvironment {
constructor(...args) {
super(...args);

this.global.ReadableStream = ReadableStream;
this.global.TextDecoder = TextDecoder;
this.global.TextEncoder = TextEncoder;

this.global.Blob = Blob;
this.global.File = File;
this.global.Headers = Headers;
this.global.FormData = FormData;
this.global.Request = Request;
this.global.Response = Response;
this.global.Request = Request;
this.global.Response = Response;
this.global.fetch = fetch;
this.global.structuredClone = structuredClone;

}
}

module.exports = JSDOMEnvironmentExtended;

//.babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}

//package.json
{
"name": "users-crud",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"jest": "^27.5.1",
"msw": "^2.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "jest --watchAll --config=jest-config.json",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

@github-actions github-actions bot locked and limited conversation to collaborators Oct 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:browser Related to MSW running in a browser
Projects
None yet
Development

No branches or pull requests

4 participants