Skip to main content
โšก Calmops

JavaScript Testing Complete Guide 2026: Vitest, Jest, Testing Library

Introduction

Modern JavaScript testing has evolved significantly. Vitest has emerged as a popular alternative to Jest, offering better performance and Vite integration.

This guide covers JavaScript testing in 2026.

Testing Tools Overview

Tool Type Performance Ecosystem
Vitest Test Runner Fast โšก Large
Jest Test Runner Medium Largest
Mocha Test Runner Medium Large
AVA Test Runner Fast Medium

Vitest

Setup

npm create vitest@latest my-app
cd my-app
npm install

Configuration

// vitest.config.js
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    environment: 'node',
    globals: true,
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
    },
  },
});

Writing Tests

import { describe, it, expect, beforeEach } from 'vitest';

describe('Math utilities', () => {
  beforeEach(() => {
    // Setup
  });

  it('adds two numbers', () => {
    expect(2 + 2).toBe(4);
  });

  it('handles arrays', () => {
    const arr = [1, 2, 3];
    expect(arr).toHaveLength(3);
    expect(arr).toContain(2);
  });

  it('async operation', async () => {
    const data = await fetchData();
    expect(data).toBeDefined();
  });
});

Mocking

import { vi, expect, it } from 'vitest';

vi.mock('./api', () => ({
  fetchUser: () => Promise.resolve({ id: 1, name: 'John' }),
}));

it('mocks API', async () => {
  const user = await fetchUser();
  expect(user.name).toBe('John');
});

Jest

Setup

npm install --save-dev jest

Configuration

// jest.config.js
module.exports = {
  testEnvironment: 'node',
  coverageDirectory: 'coverage',
  collectCoverageFrom: [
    'src/**/*.js',
    '!src/**/*.test.js',
  ],
};

Writing Tests

describe('String utilities', () => {
  test('reverses string', () => {
    expect(reverse('hello')).toBe('olleh');
  });

  test('capitalizes', () => {
    expect(capitalize('hello')).toBe('Hello');
  });
});

Testing Library

Installation

npm install --save-dev @testing-library/react @testing-library/dom

Query Methods

import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';

test('button click', () => {
  const handleClick = vi.fn();
  render(<Button onClick={handleClick}>Click me</Button>);
  
  fireEvent.click(screen.getByText('Click me'));
  
  expect(handleClick).toHaveBeenCalledTimes(1);
});

Common Queries

// Get by text
screen.getByText('Submit');

// Get by role
screen.getByRole('button', { name: /submit/i });

// Get by testid
screen.getByTestId('submit-button');

// Query vs Get (throw vs return null)
screen.getByText('Submit');     // Throws if not found
screen.queryByText('Submit');   // Returns null if not found

Best Practices

Test Structure

describe('Component', () => {
  // Setup
  beforeEach(() => { ... });
  
  // Tests
  it('should do something', () => { ... });
  
  // Teardown
  afterEach(() => { ... });
});

Naming Conventions

// Good naming
it('should return 404 when user not found');
it('should throw error for invalid input');

// Bad naming
it('test1');
it('works');

AAA Pattern

it('calculates total correctly', () => {
  // Arrange
  const cart = [{ price: 10 }, { price: 20 }];
  
  // Act
  const total = calculateTotal(cart);
  
  // Assert
  expect(total).toBe(30);
});

Conclusion

Modern JavaScript testing is powerful and fast. Use Vitest for new projects, Testing Library for component tests, and follow AAA pattern.

Resources

Comments