react create app, typescript unit test with mocha and chai what is the correct setup to support es6 modules?

Hello I am new to react and typescript. I have created an app with react-create-app and added typescript. After finishing app modules I wanted to do some unites test I have installed mocha and chai: npm install --save-dev mocha chai.

in my pakacge.json I have updated test script to "test": "mocha src/test/*". After using an import in my test file

import {assert} from 'chai'
import {File} from "../components/File"

I run into an issue

import {assert} from 'chai'
^^^^^^

SyntaxError: Cannot use import statement outside a module

I have searched a lot and tried a ton of answers like this one but still run into the same issue -_- And I am confused whether I need to install babel? Here is my package.json any explanation

{
  ...
    "dependencies": {
      "@testing-library/jest-dom": "^5.11.9",
      "@testing-library/react": "^11.2.5",
      "@testing-library/user-event": "^12.8.3",
      "@types/classnames": "^2.2.11",
      "@types/jest": "^26.0.22",
      "@types/node": "^14.14.37",
      "@types/react": "^17.0.3",
      "@types/react-dom": "^17.0.3",
      "classnames": "^2.2.6",
      "node-sass": "^5.0.0",
      "react": "^17.0.1",
      "react-dom": "^17.0.1",
      "react-scripts": "4.0.3",
      "typescript": "^4.2.3",
      "web-vitals": "^1.1.1"
    },
    "scripts": {
      "start": "react-scripts start",
      "build": "react-scripts build",
      "test": "cross-env TS_NODE_PROJECT="tsconfig.testing.json" mocha src/test/*",
      "eject": "react-scripts eject"
    },
    ...
    "devDependencies": {
      "@types/chai": "^4.2.16",
      "@types/mocha": "^8.2.2",
      "chai": "^4.3.4",
      "cross-env": "^7.0.3",
      "mocha": "^8.3.2"
    }
  }

Here is my tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

How could I set up everything correctly?

Answer

There is 02 options

  1. using ts-mocha the short way => npm install --save-dev ts-mocha

Mocha thin wrapper that allows running TypeScript tests with TypeScript runtime (ts-node) to get rid of compilation complexity. All Mocha features are available without any limitation. See documentation.

use this ts configuration for the test tsconfig.testing.json.

{
  "compilerOptions": {
      "module": "commonjs",
      "target": "es5"
  },
  "include": ["src/test/*"]
}

This a basic configuration you can update it according to your need

Add script to package.json scripts: "test-ts": "ts-mocha -p tsconfig.testing.json src/test/*"

Well you should pay attention for importing text files that may run into issues. it will lead to token errors so move them to another files and make sure your utils functoins to be pure functions since you run unit test.

Another important note: You should set "module": "commonjs" to fix conflict issues, like yours Cannot use import statement outside a module.

  1. use normal mocha with ts-node/register for TypeScript execution. Check the documentation
  • you should install ts-node and cross-env to use the new tsconfig.testing.json.
  • This is a simple configuration for the tsconfig.testing.json. Note you should add to the up configuration moduleResolution to node Check here for more details. Add the path to your declaration types if there is any to avoid errors of type error TS2304: Cannot find name "type_name".
  • Add script to package.json scripts: cross-env TS_NODE_PROJECT="tsconfig.testing.json" mocha -r ts-node/register src/test/*
{
  "ts-node": {
    "files": true
  },
  "compilerOptions": {
    "target": "es5",
    "module": "CommonJS",
    "moduleResolution": "node"
  },
  "include": [
    "src"
  ],
  "exclude": [
    "./node_modules/",
    "./dist/"
  ], 
  "files": [
    "path_to_your_types_declaration"
  ]
}