Jest cannot import modules from TypeScript ESM path mapping

691 Views Asked by At

I'm trying to set a path mapping for the src folder and for some reason in my jest test file it is not being resolved.

  • This is my project structure:
app-esm/
├── __test__/
│   └── index.test.ts
├── src/
│   └── index.ts
├── jest.config.ts
├── package.json
└── tsconfig.json
  • Here my config:

tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "dist",
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "baseUrl": ".",
    "paths": {
      "@App/*": ["src/*"]
    }
  },
  "exclude": ["node_modules", "./*.ts", "__test__"]
}

jest.config.ts

import type { JestConfigWithTsJest } from "ts-jest";

const config: JestConfigWithTsJest = {
  verbose: true,
  transform: {
    "^.+\\.ts?$": [
      "ts-jest",
      {
        useESM: true,
      },
    ],
  },
  extensionsToTreatAsEsm: [".ts"],
  moduleNameMapper: {
    "@App/(.*)": "<rootDir>/src/$1",
  },
};

export default config;

index file

export const run = () => "hello, there!";

test file

import { run } from "@App/index";

test("index", () => {
  expect(run()).toBe("hello, there!");
});

What config is missing here?

You can check out this repo to reproduce the issue.

p.s importing without the path mapping works perfectly. I just need to remove the path config from tsconfig and replace the moduleNameMapper @App by "^(\\.{1,2}/.*)\\.js$": "$1".

2

There are 2 best solutions below

0
manga On BEST ANSWER

Here is what I did:

  • Splitted tsconfig into two files:

tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "dist",
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "baseUrl": ".",
    "paths": {
      "@App/*": ["src/*"]
    }
  }
}

tsconfig.build.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "rootDir": "./"
  },
  "exclude": ["./*.ts", "__test__"]
}
  • Installed path-alias dependency and adjusted the scripts:
{
  ...
  "scripts": {
    "build": "tsc --project tsconfig.build.json",
    "test": "node --experimental-vm-modules node_modules/.bin/jest",
    "dev": "tsx src/index.ts",
    "start": "node --loader @bleed-believer/path-alias ./dist/src/index.js"
  },
  "dependencies": {
    "@bleed-believer/path-alias": "^0.15.2"
  }
  ...
  • Adjusted the moduleNameMapper:
import type { JestConfigWithTsJest } from "ts-jest";

const config: JestConfigWithTsJest = {
  verbose: true,
  transform: {
    "^.+\\.(t|j)s$": [
      "ts-jest",
      {
        useESM: true,
      },
    ],
  },
  extensionsToTreatAsEsm: [".ts"],
  moduleNameMapper: {
    "^@App/(.*)\\.js$": "<rootDir>/src/$1",
  },
};

export default config;

You can check the repo as well.

2
Robin Thomas On

You can fix your issue by following the below steps.

  1. Update your jest.config.ts to what's shown below:
import type { JestConfigWithTsJest } from "ts-jest";

const config: JestConfigWithTsJest = {
  verbose: true,
  transform: {
    '^.+\\.(t|j)s$': ['ts-jest', {
      tsconfig: './tsconfig.test.json',
      useESM: true,
    }],
  },
  moduleNameMapper: {
    "@App/main/main": "<rootDir>/src/main/main",
    "@App/(.*)": "<rootDir>/src/$1",
  },
  preset: "ts-jest/presets/default-esm",
};

export default config;

There are two fixes here. One for moduleNameMapper and other for preset to use the ESM.

We shall also use a new tsconfig.test.json for jest, which shall be explained in next step.

  1. I have created a new tsconfig.test.json (because in your existing tsconfig.json, I see that you had excluded __test__.
{
  "extends": "./tsconfig.json",
  "include": ["__test__"]
}

On running npm run test, you get the below output:

> [email protected] test
> node --experimental-vm-modules node_modules/.bin/jest

(node:12578) ExperimentalWarning: VM Modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
 PASS  __test__/main/main.test.ts
  ✓ main (1 ms)

  console.log
    Hello, Mock!

      at src/index.ts:3:9

  console.log
    Hello, Mock namedExport!

      at src/index.ts:4:9

 PASS  __test__/index.test.ts
  ✓ main (11 ms)

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.169 s, estimated 1 s
Ran all test suites.