jest.config.ts using ts-jest preset for TypeScript; set testEnvironment to "jsdom" for React or "node" for backend.npx jest --config jest.config.tsts-node — Jest cannot read jest.config.ts without it.ts-node installed--experimental-vm-modules flagjest-environment-jsdom is separate since Jest 28transform must match file types — .ts/.tsx need ts-jest or @swc/jest| Option | Default | Purpose |
|---|---|---|
preset | none | Base config (ts-jest) |
testEnvironment | "node" | Test runtime |
transform | {} | File transformers |
moduleNameMapper | {} | Path alias mapping |
setupFilesAfterFramework | [] | Post-init setup |
collectCoverage | false | Coverage collection |
coverageThreshold | none | Min coverage % |
testTimeout | 5000 | Default timeout (ms) |
verbose | false | Show individual results |
maxWorkers | 50% | Parallel workers |
START
├── TypeScript? → ts-jest preset
├── React/DOM? → testEnvironment: 'jsdom'
├── ESM (type: module)? → ESM preset + --experimental-vm-modules
├── Need speed? → @swc/jest (3-5x faster)
├── Path aliases? → moduleNameMapper
└── DEFAULT → ts-jest + node environment
[src4]
npm install --save-dev jest ts-jest @types/jest
# For React: npm install --save-dev jest-environment-jsdom @testing-library/react @testing-library/jest-dom
[src1]
import type { Config } from 'jest';
const config: Config = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.test.ts', '**/*.spec.ts'],
verbose: true,
};
export default config;
[src1]
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
collectCoverage: true,
coverageThreshold: {
global: { branches: 80, functions: 80, lines: 80, statements: 80 },
},
import type { Config } from 'jest';
const config: Config = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src'],
moduleNameMapper: { '^@/(.*)$': '<rootDir>/src/$1' },
collectCoverage: true,
coverageThreshold: { global: { branches: 80, functions: 80, lines: 80, statements: 80 } },
clearMocks: true,
restoreMocks: true,
};
export default config;
const config: Config = {
testEnvironment: 'node',
transform: {
'^.+\\.(t|j)sx?$': ['@swc/jest', {
jsc: { parser: { syntax: 'typescript', tsx: true } },
}],
},
};
const config: Config = {
projects: [
{ displayName: 'api', preset: 'ts-jest', testEnvironment: 'node', roots: ['<rootDir>/packages/api/src'] },
{ displayName: 'web', preset: 'ts-jest', testEnvironment: 'jsdom', roots: ['<rootDir>/packages/web/src'] },
],
};
// ❌ BAD — jsdom NOT bundled since Jest 28
{ testEnvironment: 'jsdom' } // Error: Cannot find module
# ✅ GOOD
npm install --save-dev jest-environment-jsdom
// ❌ BAD — Jest crashes on CSS imports
// No moduleNameMapper for static assets
// ✅ GOOD
moduleNameMapper: {
'\\.(css|less|scss)$': 'identity-obj-proxy',
'\\.(jpg|png|svg)$': '<rootDir>/__mocks__/fileMock.ts',
}
npm install --save-dev ts-node. [src1]@swc/jest. [src4]toHaveBeenCalledWith. Fix: use expect.any(). [src3]collectCoverageFrom: ['src/**/*.ts']. [src1]# Show resolved config
npx jest --showConfig
# Run matching tests
npx jest --testPathPattern="auth"
# Watch mode
npx jest --watch
# Coverage report
npx jest --coverage
# List tests
npx jest --listTests
| Version | Status | Breaking Changes | Migration Notes |
|---|---|---|---|
| Jest 30 | Current | Node <18 dropped, jsdom 26, stricter TS types | Check toHaveBeenCalledWith matching |
| Jest 29 | Maintenance | — | Last version supporting Node 16 |
| Jest 28 | EOL | jsdom extracted | npm i jest-environment-jsdom |
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Established codebase on Jest | New Vite project | Vitest |
| Need snapshot testing | Deno project | Deno.test |
| React Testing Library | Browser-native testing | Playwright |
@swc/jest is faster but does not type-check — run tsc --noEmit separately--experimental-vm-modules flagjest.config.ts on Node 24+ with CJS may have issues