DEV Community

Cover image for Unit Testing with Jest – From Zero‑Config to Production Ready
Artem Turlenko
Artem Turlenko

Posted on • Edited on

2 1 1 1

Unit Testing with Jest – From Zero‑Config to Production Ready

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
Enter fullscreen mode Exit fullscreen mode

Add a script:

"scripts": {
  "test": "jest"
}
Enter fullscreen mode Exit fullscreen mode

Tip: Running npx jest --init scaffolds a starter jest.config.js.


Your First Test

Code under test sum.js

function sum(a, b) {
  return a + b;
}
module.exports = sum;
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

Run:

npm test   # → PASS  sum.test.js
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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');
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode
const action = require('./user');

test('callback called with John', () => {
  const mockCb = jest.fn();
  action(mockCb);
  expect(mockCb).toHaveBeenCalledWith('John');
});
Enter fullscreen mode Exit fullscreen mode

Need to stub axios network calls?

jest.mock('axios');
Enter fullscreen mode Exit fullscreen mode

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'],
};
Enter fullscreen mode Exit fullscreen mode

 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
Enter fullscreen mode Exit fullscreen mode

Add .babelrc and tsconfig.json as usual.

 CSS & Asset Mocks

// __mocks__/fileMock.js
module.exports = 'test-file-stub';
Enter fullscreen mode Exit fullscreen mode

CSS modules resolved to a proxy that returns class names.

 Global Setup

// jest.setup.js
import '@testing-library/jest-dom/extend-expect';
Enter fullscreen mode Exit fullscreen mode

Watch Mode & Coverage

npm test -- --watch     # rerun only affected tests
npm test -- --coverage  # generate LCOV + text summary
Enter fullscreen mode Exit fullscreen mode

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! 🚀

Tiugo image

Fast, Lean, and Fully Extensible

CKEditor 5 is built for developers who value flexibility and speed. Pick the features that matter, drop the ones that don’t and enjoy a high-performance WYSIWYG that fits into your workflow

Start now

Top comments (3)

Collapse
 
ekalkutin profile image
Evgenii Kalkutin

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

Collapse
 
artem_turlenko profile image
Artem Turlenko

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! 🚀

Collapse
 
nathan_tarbert profile image
Nathan Tarbert

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?

Tiger Data image

🐯 🚀 Timescale is now TigerData: Building the Modern PostgreSQL for the Analytical and Agentic Era

We’ve quietly evolved from a time-series database into the modern PostgreSQL for today’s and tomorrow’s computing, built for performance, scale, and the agentic future.

So we’re changing our name: from Timescale to TigerData. Not to change who we are, but to reflect who we’ve become. TigerData is bold, fast, and built to power the next era of software.

Read more

👋 Kindness is contagious

If this **helped, please leave a ❤️ or a friendly comment!

Okay