vasturiano / react-force-graph

React component for 2D, 3D, VR and AR force directed graphs
https://vasturiano.github.io/react-force-graph/example/large-graph/
MIT License
2.26k stars 284 forks source link

SyntaxError: "Cannot use import statement outside a module" for CRA, Jest and react-force-graph #445

Open danielbakas opened 1 year ago

danielbakas commented 1 year ago

Describe the bug

When trying to import ForceGraph3D from react-force-graph by vasturiano in a create-react-app project, the tests fail with a SyntaxError: "Cannot use import statement outside a module". The error points to the first line of react-force-graph.mjs file.

Did you try recovering your dependencies?

Yes, I tried recovering my dependencies but the issue still persists.

Which terms did you search for in User Guide?

I searched for terms like "Jest encountered an unexpected token", "Cannot use import statement outside a module", "react-force-graph test fails".

Environment

Environment Info:

  current version of create-react-app: 5.0.1
  running from /Users/danielbakas/.npm/_npx/c67e74de0542c87c/node_modules/create-react-app

  System:
    OS: macOS 14.0
    CPU: (8) arm64 Apple M1 Pro
  Binaries:
    Node: 20.3.1 - /opt/homebrew/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 9.6.7 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 114.0.5735.198
    Safari: 17.0
  npmPackages:
    react: ^18.2.0 => 18.2.0 
    react-dom: ^18.2.0 => 18.2.0 
    react-scripts: ^5.0.1 => 5.0.1 

Steps to reproduce

  1. Create a new app using create-react-app.
  2. Install react-force-graph package using npm install react-force-graph.
  3. In your App component, import ForceGraph3D from react-force-graph.
  4. Run the tests with npm test.

Expected behavior

Tests run successfully without any import errors.

Actual behavior

Tests fail with SyntaxError: "Cannot use import statement outside a module". The error points to the first line of react-force-graph.mjs file.

Captura de pantalla 2023-07-03 a la(s) 2 06 50 a m
vasturiano commented 1 year ago

@danielbakas the react-force-graph.mjs is an ES modules export. It would seem you're trying to consume from it in a different environment, like CommonJS perhaps. Is that the case?

danielbakas commented 1 year ago

Hi @vasturiano! Thanks for replying.

I’m not sure. I just did a create-react-app and right off the box imported ForceGraph3D.

I then tried to run the simple render test with npm test and the test failed with that error.

Would you like me to check anything specific about my environment? 🤓

Thanks!

vasturiano commented 1 year ago

Sounds like it's an issue with CRA not supporting ESM. Please see this doc: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c#im-having-problems-with-esm-and-create-react-app

danielbakas commented 1 year ago

Are you sure? It seems CRA supports ESM since 4.0.0, and I’m using ^5.0.1

I saw your issue (https://github.com/facebook/create-react-app/issues/10892) but didn’t find any fixes. I hope I’m not mistaken and the issue is in fact the resource you wanted me to look into.

What would be a possible fix for this issue? Have you managed to fix it before?

Thank you for your help @vasturiano!

vasturiano commented 1 year ago

@danielbakas I can't really be of much help on things that relate to CRA I'm afraid. It's probably more useful to ask that in a more dedicated forum to that platform.

As far as this module is concerned, it's doing what it promises which is to expose a ES module only entrypoint.

danielbakas commented 1 year ago

Ok. I'll ask over there. Thanks @vasturiano!

mrazauskas commented 1 year ago

Jest is evaluating the code as CJS, because your transformer supplies it as CJS. react-force-graph is published as ESM, but by default Jest does not transform node_modules. This is what you see in third bullet in the error message.

The easier way to deal with this is to use react-force-graph version which was still CJS. Hard to say the exact one without having the change log. I guess the last one was v1.41.20. It came out before https://github.com/vasturiano/react-force-graph/commit/9bcec4a81af2bb9bf9969ad5268796927ed238e6.

The hard way to tell Jest to transform each and every ESM package using the transformIgnorePatterns as described here : https://jestjs.io/docs/tutorial-react-native#transformignorepatterns-customization. That will be a long list, because react-force-graph is pulling a lot of ESM packages. Just follow the error messages and add packages one by one:

"transformIgnorePatterns": [
  "node_modules/(?!(react-kapsule|react-force-graph|jerrypick|3d-force-graph-vr|accessor-fn|three-forcegraph|d3-force-3d)/)"
]

And so on. This is not the full list yet. I stoped, because it feels endless (;

mrazauskas commented 1 year ago

Hm.. I was wondering how react-force-graph is tested. For instance, testing integration with React could give ideas for users how to test their apps. Might be I am scrolling to quick.. Are there any tests in this repo?

danielbakas commented 1 year ago

Hm.. I was wondering how react-force-graph is tested.

Me too! And thank you for your answer @mrazauskas!

I started adding each package to the transformPackages too but, as you say, it seemed endless.

Also, using an outdated version of the package would not be ideal, although it’s a valuable option, thank you!

Are there any tests in this repo?

I tried looking for some, but couldn’t find any either.

Maybe @vasturiano can point us in the right direction 🤓

danielbakas commented 1 year ago

@vasturiano @mrazauskas any updates on this issue? 🤓

brijesh-imemori commented 1 year ago

I was also facing the same issue, I have done each and every changes that you guys mentioned here, But I am still in the middle of figuring out this stuff, Unfortunately, I haven't found a solution yet.

@mrazauskas @danielbakas

` ● 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:

C:\Dev\ui\node_modules\react-force-graph-2d\dist\react-force-graph-2d.mjs:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import fromKapsule from 'react-kapsule';        
                                                                                  ^^^^^^

SyntaxError: Cannot use import statement outside a module

  1 | import React, { useState, useEffect } from "react";
  2 | import Popover from "@mui/material/Popover";
> 3 | import ForceGraph2D from "react-force-graph-2d";
    | ^
  4 | import MDBox from "components/MDBox";
  5 | import { useTheme } from "@mui/material/styles";
  6 | import PropTypes from "prop-types";

  at Runtime.createScriptFromCode (node_modules/react-scripts/node_modules/jest-runtime/build/index.js:1728:14)
  at Object.<anonymous> (src/layouts/dashboards/imemori/ProgressTop/popup.tsx:3:1)
  at Object.<anonymous> (src/layouts/dashboards/imemori/ProgressTop/circle.tsx:15:1)
  at Object.<anonymous> (src/layouts/dashboards/imemori/ProgressTop/progressTop.tsx:7:1)
  at Object.<anonymous> (src/tests/component/progressTop.test.tsx:2:1)

`

Can you guys please help me out to, how to test forceGraph2d.?

danielbakas commented 1 year ago

+1

annette-graham commented 8 months ago

+1

brijesh-imemori commented 7 months ago
jest.mock("react-force-graph-2d", () => ({
  ForceGraph2D: jest.fn(),
  ForceGraphMethods: jest.fn(),
  NodeObject: jest.fn(),
}));

we found the solution, just add this and you will be able to mock the react-force-graph-2d