Services Hosting & Servers Tools Blog Search Company TürkçeTR
Get a Quote

Jest is the most popular test framework in the JavaScript and TypeScript ecosystem. It starts zero-config and ships with built-in assertions, mocking and coverage. This article walks through every core Jest feature and modern testing practice.

Installation

Related guides: PostgreSQL optimization · Advanced Git commands · What is Redis · Deploying with Docker · Docker Compose guide

npm i -D jest @types/jest
npm i -D ts-jest typescript  # for TS projects

# package.json
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}

# For TypeScript
npx ts-jest config:init

Your First Test

// math.js
function add(a, b) { return a + b; }
module.exports = { add };

// math.test.js
const { add } = require('./math');

describe('add()', () => {
    it('adds two positive numbers', () => {
        expect(add(2, 3)).toBe(5);
    });

    it('adds negative numbers', () => {
        expect(add(-1, -2)).toBe(-3);
    });

    it('works with zero', () => {
        expect(add(0, 5)).toBe(5);
    });
});
npm test
# PASS  ./math.test.js
#   add()
#     ✓ adds two positive numbers (2 ms)
#     ✓ adds negative numbers
#     ✓ works with zero

Matchers

// Equality
expect(x).toBe(5);                // primitive === 
expect(obj).toEqual({ a: 1 });    // deep equal
expect(obj).toStrictEqual({ a: 1 });  // + type check

// Truthy/Falsy
expect(x).toBeTruthy();
expect(x).toBeNull();
expect(x).toBeDefined();

// Numbers
expect(x).toBeGreaterThan(3);
expect(x).toBeCloseTo(0.3);       // float

// String / Array
expect(s).toMatch(/error/i);
expect(arr).toContain('apple');
expect(arr).toHaveLength(3);

// Objects
expect(user).toHaveProperty('email');
expect(user).toMatchObject({ name: 'Alex' });  // subset

// Exceptions
expect(() => throwError()).toThrow('Bad input');

// Negation
expect(x).not.toBe(0);

Setup and Teardown

describe('User service', () => {
    let db;

    beforeAll(async () => {
        db = await connectDB();
    });

    afterAll(async () => {
        await db.close();
    });

    beforeEach(async () => {
        await db.clear();
    });

    it('creates user', async () => {
        const user = await createUser(db, { email: 'a@b.com' });
        expect(user.id).toBeDefined();
    });
});

Async Tests

// With a promise
it('fetches user', () => {
    return getUser(1).then(user => {
        expect(user.name).toBe('Alex');
    });
});

// async/await (preferred)
it('fetches user', async () => {
    const user = await getUser(1);
    expect(user.name).toBe('Alex');
});

// Expecting a rejection
it('throws on invalid id', async () => {
    await expect(getUser(-1)).rejects.toThrow('Invalid');
});

// Expecting a resolution
it('resolves with data', async () => {
    await expect(getUser(1)).resolves.toEqual(expect.objectContaining({ name: 'Alex' }));
});

Mock Functions

// Jest mock
const logger = jest.fn();
logger('hello');
logger('world');

expect(logger).toHaveBeenCalled();
expect(logger).toHaveBeenCalledTimes(2);
expect(logger).toHaveBeenCalledWith('hello');
expect(logger).toHaveBeenNthCalledWith(1, 'hello');

// Mock return values
const fetchUser = jest.fn().mockResolvedValue({ id: 1, name: 'Alex' });
const errFetch = jest.fn().mockRejectedValue(new Error('Network'));

// Implementation
const add = jest.fn((a, b) => a + b);
expect(add(2, 3)).toBe(5);

Module Mocks

// __mocks__/axios.js
module.exports = {
    get: jest.fn(),
    post: jest.fn()
};

// user.test.js
jest.mock('axios');
const axios = require('axios');

it('fetches user', async () => {
    axios.get.mockResolvedValue({ data: { name: 'Alex' } });
    const user = await getUser(1);
    expect(user).toEqual({ name: 'Alex' });
    expect(axios.get).toHaveBeenCalledWith('/users/1');
});

Spies

// Observe an existing function while still calling it
const spy = jest.spyOn(console, 'log');
myFunction();
expect(spy).toHaveBeenCalledWith('doing work');
spy.mockRestore();  // revert to the original

Snapshot Testing

it('renders correctly', () => {
    const { container } = render(<Button label="Save" />);
    expect(container).toMatchSnapshot();
});
// First run creates the snapshot
// Subsequent runs compare — a diff fails the test
// Accept with: jest -u (update)
Note
Commit snapshots to Git. They should be reviewable; snapshots of 1000+ lines are a test smell — prefer narrower assertions.

Coverage

npm test -- --coverage

# jest.config.js
module.exports = {
    coverageDirectory: 'coverage',
    collectCoverageFrom: ['src/**/*.{js,ts}', '!**/*.test.{js,ts}'],
    coverageThreshold: {
        global: { branches: 80, functions: 80, lines: 80, statements: 80 }
    }
};

Test Driven Development (TDD)

  • Red: write a failing test (the function doesn't exist yet)
  • Green: write the simplest code to make the test pass
  • Refactor: clean up the code, the test still passes
  • Repeat

Vitest as an Alternative

If you're on a Vite project, consider Vitest instead of Jest. The API is 95% Jest-compatible, it's 3-5x faster, ESM-native and first-class TS support.

Common Pitfalls

  • Forgetting await in async tests → false positives
  • Not clearing the DB between tests → flaky tests
  • Overly large snapshots → impossible to review
  • Testing implementation details → breaks on refactor
  • No test isolation → test order affects results

Modern Software Development and DevOps Practices

Professional software development rests on three pillars: version control (Git + GitHub/GitLab pull request flow, mandatory code review), CI/CD pipeline (automated test + lint + build + deploy), and observability (Sentry/Datadog/Grafana for logs, metrics, traces). The test pyramid (unit > integration > e2e) ensures code quality, microservice architecture uses Docker containers with Kubernetes orchestration, and REST or GraphQL APIs follow OpenAPI/GraphQL Schema contracts. Across the SDLC (requirements → design → implementation → test → deploy → maintenance), Agile/Scrum sprints last 1-2 weeks while DevOps teams practice continuous delivery.

Testing infrastructure setup

Reach out to KEYDAL for a Jest, Vitest or Playwright testing pyramid and CI integration. Contact us

WhatsApp