Jest is a fast, delightful JavaScript testing framework created at Meta. It can run out‑of‑the‑box, but real‑world projects (React, TypeScript, CSS modules, etc.) need extra setup. This guide covers both the quick start and the advanced configuration you’ll meet in production.
Why Jest?
Feature | Benefit |
---|---|
Zero config (plain JS projects) | Start testing instantly. |
Parallel runner | Tests run in isolated workers for speed + safety. |
Snapshots | Track changes to large objects / UI trees over time. |
Rich mocking | Mock functions, modules, timers, even fetch . |
Watch mode & coverage | TDD‑friendly feedback loops. |
Installing Jest
npm i --save-dev jest # or: yarn add -D jest
Add a script:
"scripts": {
"test": "jest"
}
Tip: Running
npx jest --init
scaffolds a starterjest.config.js
.
Your First Test
Code under test sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
Test file sum.test.js
const sum = require('./sum');
// 👉 each test lives inside test()/it()
// 👉 expect() assertions use matchers, e.g. toBe()
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
Run:
npm test # → PASS sum.test.js
Testing Asynchronous Code (with Fake Timers)
Real timers slow suites and can flake on CI. Replace them with Jest’s simulated clock.
async function (uses a timer)
// fetchData.js
function fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve('peanut butter'), 100); // heavy in real time
});
}
module.exports = fetchData;
test with fake timers
const fetchData = require('./fetchData');
jest.useFakeTimers(); // 1️⃣ switch to mocked timers
test('resolves to peanut butter', async () => {
const promise = fetchData(); // 2️⃣ schedule timer
jest.runAllTimers(); // 3️⃣ jump 100 ms instantly
await expect(promise).resolves.toBe('peanut butter');
});
Snapshot Testing
Great for React/Vue UI or large JSON configs.
import renderer from 'react-test-renderer';
import Button from './Button';
test('renders button UI', () => {
const tree = renderer.create(<Button label="Save" />).toJSON();
expect(tree).toMatchSnapshot();
});
First run saves a snapshot file; later runs fail if output changes (update with u
).
Mock Functions & Modules
// user.js
action = cb => cb('John');
module.exports = action;
const action = require('./user');
test('callback called with John', () => {
const mockCb = jest.fn();
action(mockCb);
expect(mockCb).toHaveBeenCalledWith('John');
});
Need to stub axios
network calls?
jest.mock('axios');
Advanced Jest Configuration (real‑world projects)
When you add TypeScript, JSX, CSS modules, or path aliases, Jest must learn how to understand those imports.
jest.config.js
/** @type {import('jest').Config} */
module.exports = {
testEnvironment: 'jsdom', // React front‑end; use 'node' for back‑end
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// ︎🔶 Transform files (babel or ts-jest)
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest', // transpile TypeScript
'^.+\\.(js|jsx)$': 'babel-jest', // if using custom Babel
},
// ︎🔶 Stub non‑JS imports (CSS/SVG/img)
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1', // path alias example
'\\.(css|less|sass|scss)$': 'identity-obj-proxy',
'\\.(svg|png|jpg)$': '<rootDir>/__mocks__/fileMock.js',
},
// ︎🔶 Coverage collection
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'],
};
Transformers
-
Babel:
babel-jest
handles JSX/ESNext. -
TypeScript:
ts-jest
compiles TS on the fly.
Install:
npm i -D babel-jest @babel/preset-env ts-jest typescript
Add .babelrc
and tsconfig.json
as usual.
CSS & Asset Mocks
// __mocks__/fileMock.js
module.exports = 'test-file-stub';
CSS modules resolved to a proxy that returns class names.
Global Setup
// jest.setup.js
import '@testing-library/jest-dom/extend-expect';
Watch Mode & Coverage
npm test -- --watch # rerun only affected tests
npm test -- --coverage # generate LCOV + text summary
Conclusion
Jest shines from hello‑world samples to enterprise TypeScript monorepos. Start simple, then layer in transformers and mocks as your stack grows. Don’t forget best practices: fake timers for async code, snapshot judiciously, and keep tests isolated and fast.
For more detailed information and advanced configurations, refer to the official Jest documentation: Jest Getting Started.
Happy testing! 🚀
Top comments (3)
Some feedback:
All timers should have been simulated (u have 100ms real timer). Anyway, it is not easy as you write to use jest.
For real scenarios, you have to configure jest how it should parse and transpile files (lets say css imports in react components), typescript, path aliases e.t.c
Thanks for the detailed feedback — you’re absolutely right.
Timers: In the quick example I used a real setTimeout. In production tests I normally stub timers with jest.useFakeTimers() / jest.advanceTimersByTime() so the suite stays fast and deterministic. I’ve updated the article to show that pattern.
“Zero-config” vs real projects: Agreed. The post’s first half targets a plain-JS setup, but anything with React/TS/CSS modules needs extra config (Babel or ts-jest, moduleNameMapper for assets, path aliases, etc.). I’ve added an “Advanced Jest Configuration” section that covers those transformers and mappers.
Appreciate the sanity-check — it makes the guide more realistic for people shipping non-trivial apps. Let me know if I missed any other gotchas! 🚀
nice, getting all the must-knows in one spot like this is super helpful - you think most teams spend enough time on tests upfront or is it always an afterthought?