Jest "Cannot find module" - Fix Resolution Errors in CI
Jest could not resolve an import. Either the package was never installed, the file path is wrong (often a case mismatch that only matters on Linux), or a path alias is not mapped in the Jest config.
What this error means
A test file fails at collection with Cannot find module 'X' from 'Y'. It frequently passes locally on macOS but fails on a Linux CI runner because the filesystem there is case-sensitive.
Cannot find module '@/utils/format' from 'src/components/Card.test.tsx'
Require stack:
src/components/Card.test.tsxCommon causes
Path alias not mapped in Jest
A @/... alias works in your bundler and tsconfig paths, but Jest resolves modules itself and needs the same mapping in moduleNameMapper. Without it, the import is unresolvable.
Case-sensitive import on Linux
Importing ./Card when the file is card.tsx works on case-insensitive macOS/Windows but fails on a case-sensitive Linux runner.
Dependency not installed
The package is in devDependencies but CI ran npm ci --omit=dev, or it was never added to package.json, so it is absent from node_modules.
How to fix it
Map path aliases in Jest config
Mirror your tsconfig paths into moduleNameMapper so Jest resolves aliases the same way your build does.
// jest.config.js
module.exports = {
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};Fix the import case to match the file
- Compare the import path against the real filename, including capitalization.
- Rename the import (or the file) so they match exactly.
- Add
eslint-plugin-importwithimport/no-unresolvedto catch this before CI.
Install the missing dependency
npm install <package>
# if it is needed for tests, ensure CI installs devDependencies (no --omit=dev)How to prevent it
- Keep
moduleNameMapperin sync with tsconfigpaths. - Develop or lint on a case-sensitive filesystem to catch case bugs early.
- Commit the lockfile and run
npm ciso installs are reproducible.