🔧 Error Fixes
· 2 min read
Last updated on

Jest: Cannot Find Module — How to Fix It


You run your tests and Jest throws:

Cannot find module '@/components/Button' from 'src/App.test.tsx'

Your app runs fine in the browser, but Jest can’t resolve the same imports.

What causes this

Jest uses its own module resolution system, completely separate from your bundler (Webpack, Vite, esbuild, etc.). Path aliases like @/, ~/, or #/ are configured in your bundler or tsconfig.json, but Jest doesn’t read those configs by default.

So when your code imports @/components/Button, Vite knows that @ maps to src/. Jest doesn’t — it tries to find a literal npm package called @/components/Button and fails.

You’ll also see this error when:

  • Importing CSS, SCSS, images, or other non-JS files that Jest can’t parse
  • A dependency isn’t installed or is missing from node_modules
  • You’re using TypeScript path mappings without telling Jest about them

Fix 1: Add moduleNameMapper for path aliases

Tell Jest how to resolve your aliases in jest.config.js:

// jest.config.js
module.exports = {
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
};

If you have multiple aliases:

moduleNameMapper: {
  '^@/(.*)$': '<rootDir>/src/$1',
  '^@components/(.*)$': '<rootDir>/src/components/$1',
  '^@utils/(.*)$': '<rootDir>/src/utils/$1',
},

The keys are regex patterns, and $1 captures the rest of the path. <rootDir> is the directory containing your Jest config.

Fix 2: Handle CSS and asset imports

Jest can’t parse CSS or image files. You need to mock them:

// jest.config.js
moduleNameMapper: {
  '^@/(.*)$': '<rootDir>/src/$1',
  '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
  '\\.(jpg|jpeg|png|gif|svg|webp)$': '<rootDir>/__mocks__/fileMock.js',
},

Install the CSS mock:

npm install --save-dev identity-obj-proxy

Create the file mock:

// __mocks__/fileMock.js
module.exports = 'test-file-stub';

identity-obj-proxy returns the class name as-is, so styles.button returns "button" in tests. The file mock returns a string placeholder for images.

Fix 3: Sync with tsconfig paths automatically

If you’re using TypeScript, you can use ts-jest with pathsToModuleNameMapper to auto-generate the mappings from your tsconfig.json:

// jest.config.js
const { pathsToModuleNameMapper } = require('ts-jest');
const { compilerOptions } = require('./tsconfig.json');

module.exports = {
  preset: 'ts-jest',
  moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
    prefix: '<rootDir>/',
  }),
};

This reads the paths from your tsconfig.json and converts them to Jest’s moduleNameMapper format. One source of truth — no manual syncing.

Fix 4: Check that the module actually exists

Sometimes the error is simpler than you think — the file doesn’t exist or the path is wrong:

# Verify the file exists
ls src/components/Button.tsx

# Check for case sensitivity issues (common on Linux CI)
find src/components -iname "button*"

macOS and Windows filesystems are case-insensitive by default, so Button and button resolve to the same file. Linux is case-sensitive — your tests might pass locally but fail in CI.

How to prevent it

  • Set up moduleNameMapper when you first add Jest to a project — don’t wait until it breaks
  • If using TypeScript, use pathsToModuleNameMapper so aliases stay in sync automatically
  • Add CSS/asset mocks from the start — you’ll need them eventually
  • Run tests in CI on Linux to catch case-sensitivity issues early
  • Keep your Jest config close to your bundler config and update both when adding new aliases