Search code examples
typescriptunit-testingjestjsts-jest

Resolve TypeScript path in jest.mock


I'm adding unit tests to a TypeScript project which is using compilerOptions.paths, and I need to mock an import.

I'm running into an issue where jest can't resolve the module to mock

 FAIL  logic/index.test.ts
  ● Test suite failed to run

    Cannot find module '@lib/foo' from 'logic/index.test.ts'

I'm using ts-jest which adds support for paths in imports but looks like I need to do an extra step for the mocks

What is the correct way to resolve the path here?


SIMPLIFIED CASE

{
  "baseUrl": ".",
  "compilerOptions": {
    "paths": {
      "@lib/*": ["lib/*"]
    }
  }
}

Filesystem

* lib
  * __mocks__
    * foo.ts
  * foo.ts
* logic
  * index.ts
  * index.test.ts
* tsconfig.json
* jest.config.js
// index.ts
import foo from '@lib/foo';

const logic = () => foo();

export default logic;
// index.test.ts
import 'jest';

import logic from '.';

jest.mock('@lib/foo');
// jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
};

Solution

  • Per the ts-jest docs, when you're using compilerOptions.paths you need to update Jest's moduleNameMapper accordingly. The library supplies a utility to build the appropriate mapping for you:

    // jest.config.js
    const { pathsToModuleNameMapper } = require('ts-jest/utils');
    
    const { compilerOptions } = require('path/to/tsconfig');
    
    module.exports = {
      moduleNameMapper: pathsToModuleNameMapper(
        compilerOptions.paths,
        { prefix: '<rootDir>/' },
      ),
      preset: 'ts-jest',
      testEnvironment: 'node',
    };
    

    Alternatively you can do it manually, in your case:

    // jest.config.js
    module.exports = {
      moduleNameMapper: { '^@lib/(.*)$': '<rootDir>/lib/$1' },
      preset: 'ts-jest',
      testEnvironment: 'node',
    };