Search code examples
typescriptjestjsts-jesttsconfigtsconfig-paths

Jest cannot import modules from TypeScript ESM path mapping


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".


Solution

  • 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.