YulianKh
YulianKh

Reputation: 443

TypeScript Jest imports with .js extension cause error: Cannot find module

I've reached a dead end trying to fix this issue. I am using the following TypeScript configuration:

{
    "compilerOptions": {
        "module": "es2022",
        "moduleResolution": "nodenext",
        "target": "es2017",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "skipLibCheck": true,
        "noImplicitAny": true,
        "outDir": "./dist",
        "rootDir": "./src",
        "typeRoots": [
            "./src/types", "./node_modules/@types"],
        "allowJs": true,
        "strictFunctionTypes": true,
        "noImplicitReturns": true
    },
    "include": ["./src/**/*"],
    "exclude": ["node_modules"],
    "ts-node": {
        "esm": true,
        "experimentalSpecifierResolution": true
    }
}

As you see the moduleResolution is set to nodenext, and because of that I have to explicitly add a file extension when importing, like this: import ServerError from '../models/Errors/ServerError.js';. Otherwise, I get an error that the module was not found.

Everything is working fine, but when I launch my tests I get an error: Cannot find module '../models/Errors/ServerError.js' from '../src/services/usersService.ts'. So basically jest is trying to find the file ServerError.js, but it does not exist, because all files have a .ts extension, so it should be ServerError.ts. If I try to change .js to .ts in my files I also will get an error.

I can't finish my task because of this problem, so I would appreciate any help.

Upvotes: 9

Views: 9852

Answers (6)

ipikuka
ipikuka

Reputation: 814

I added only moduleNameMapper key in my case, this solved the issue for me. I've been using ts-jest/presets/default-esm preset.

/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  preset: "ts-jest/presets/default-esm",
  moduleNameMapper: {
    "(.+)\\.js": "$1",
  },
};

Upvotes: 4

Carlos
Carlos

Reputation: 194

What worked for me was a mix of the accepted answer and the settings from TS-Jest documentation.

const { defaultsESM: tsjPreset } = require('ts-jest/presets');

/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  ...tsjPreset,
moduleNameMapper: { '^(\\.|\\.\\.)\\/(.+)\\.js': '$1/$2' },

  // ....

Upvotes: 1

Már Örlygsson
Már Örlygsson

Reputation: 14606

For me this did the trick:

  "moduleNameMapper": {
    "^(\\.\\.?\\/.+)\\.js$": "$1",
  },

(Adapted from https://github.com/kulshekhar/ts-jest/issues/1057#issuecomment-1441733977)

Upvotes: 18

Peter Moses
Peter Moses

Reputation: 2137

This can be fixed by using jest-ts-webcompat-resolver npm package.

npm i jest-ts-webcompat-resolver -D

In your jest.config.ts add:

"resolver": "jest-ts-webcompat-resolver"

Upvotes: 1

oneWalker
oneWalker

Reputation: 56

I solve the problem with add a config moduleFileExtensions setting in jest.config.json;

{
    ....
    "moduleFileExtensions": ["ts", "js"],
    ....
}

Upvotes: 1

YulianKh
YulianKh

Reputation: 443

Finally, I've managed to solve this problem after doing some research and updating my jest config file.

/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
import type { Config } from 'jest';

const config: Config = {
    transform: {
        '\\.[jt]sx?$': 'ts-jest'
    },
    globals: {
        'ts-jest': {
            useESM: true
        }
    },
    moduleNameMapper: {
        '(.+)\\.js': '$1'
    },
    extensionsToTreatAsEsm: ['.ts']
};

With this configuration, everything is working fine. I hope that it will help somebody.

Upvotes: 23

Related Questions