Jest Testing for JavaScript/TypeScript

VerifiedCaution

Run and write Jest tests for JS/TS projects: CLI commands, options, mocks, spies, fake timers, and async tests.

Sby Skills Guide Bot
TestingIntermediate
22010/22/2026
Claude Code
#jest#javascript#typescript#unit-testing#mocking

Recommended for

Automated summary

Runs and writes Jest tests for JavaScript/TypeScript projects, with examples for mocking, async tests, and React component testing.

Strengths

  • Provides concrete commands to run all tests, target a file or test name, enable watch mode, or collect coverage.
  • Shows reusable patterns for module mocks, spies, fake timers, and async assertions.
  • Also covers React component tests with Testing Library and userEvent.
  • The path triggers focus on Jest config files and test files, which limits off-topic activation.

Limitations

  • Only covers Jest: there is no migration guide or initial setup for projects not already using this runner.
  • The React component test example is truncated at the end of the document.
  • E2E support is mentioned but no specific examples or guidance are provided.
When to use it

Use it when a JavaScript/TypeScript project already uses Jest and you need to run, write, or debug tests.

When not to use it

Avoid it when the project uses another runner (pytest, RSpec, ExUnit, xUnit) or when the runner has not been identified yet; run test-detector first.

Security analysis

Caution
Quality score82/100

The skill is a straightforward Jest test-runner reference: it runs standard npm/npx test commands and shows idiomatic test, mocking, and configuration patterns. There are no destructive shell commands, no network exfiltration, no obfuscated payloads, and no attempts to alter agent behavior. The only risk surface is the inherent one of executing project test code via Bash and the snapshot-update flag that mutates files, so it lands at caution rather than safe.

Findings
  • •Uses Bash to run `npm test` / `npx jest`, which executes arbitrary project test code and any npm lifecycle scripts — expected for a test runner but still arbitrary code execution from the repo.
  • •Includes `npx jest --updateSnapshot`, which rewrites snapshot files on disk; agents should be cautious about auto-accepting snapshot changes.
  • •`npx jest --watch` is an interactive/watching command that will hang a non-interactive agent session.
How this analysis is made

Examples

Write unit tests
Add Jest tests for src/services/user.ts covering the success and not-found cases. Mock the repository with jest.fn(), then run the new test file.
Run matching tests
Run only the Jest tests whose name matches "should create user" with verbose output and show me the failures.
Coverage and snapshots
Update the Jest snapshots and run the suite with coverage, then summarize which files have uncovered lines.

name: jest description: Run and write Jest tests for JavaScript/TypeScript projects — the JS/TS test runner. when_to_use: Reach for this when the project tests JavaScript or TypeScript with Jest (jest.config.js, jest in package.json). Per-language test runner — use pytest for Python, rspec for Ruby, exunit for Elixir, xunit for C#/.NET. If you don't yet know which runner the project uses, run test-detector first. allowed-tools: Read, Write, Edit, Bash, Grep, Glob paths:

  • "jest.config.*"
  • "**/*.test.{ts,js,tsx,jsx}"
  • "**/*.spec.{ts,js,tsx,jsx}"
  • "package.json"

Jest Testing Skill

Execute and generate Jest tests for JavaScript/TypeScript projects with support for unit, integration, and E2E testing.

Test Execution

Run All Tests

npm test
# or
npx jest

Run Specific Tests

# Run tests matching a pattern
npx jest --testNamePattern="should create user"

# Run tests in a specific file
npx jest src/services/user.test.ts

# Run tests in watch mode
npx jest --watch

# Run with coverage
npx jest --coverage

Common Options

# Verbose output
npx jest --verbose

# Run only changed files
npx jest --onlyChanged

# Update snapshots
npx jest --updateSnapshot

# Run in CI mode
npx jest --ci --coverage --reporters=default --reporters=jest-junit

Test Patterns

Basic Test Structure

describe('UserService', () => {
  let service: UserService;
  let mockRepo: jest.Mocked<UserRepository>;

  beforeEach(() => {
    mockRepo = {
      findById: jest.fn(),
      create: jest.fn(),
      update: jest.fn(),
      delete: jest.fn(),
    };
    service = new UserService(mockRepo);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  describe('getUser', () => {
    it('should return user when found', async () => {
      const user = { id: '1', name: 'John' };
      mockRepo.findById.mockResolvedValue(user);

      const result = await service.getUser('1');

      expect(result).toEqual(user);
      expect(mockRepo.findById).toHaveBeenCalledWith('1');
    });

    it('should throw when user not found', async () => {
      mockRepo.findById.mockResolvedValue(null);

      await expect(service.getUser('999')).rejects.toThrow('User not found');
    });
  });
});

Mocking

// Mock a module
jest.mock('./api', () => ({
  fetchUser: jest.fn(),
}));

// Mock implementation
import { fetchUser } from './api';
const mockFetchUser = fetchUser as jest.MockedFunction<typeof fetchUser>;

beforeEach(() => {
  mockFetchUser.mockResolvedValue({ id: '1', name: 'Test' });
});

// Spy on methods
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();

// Mock timers
jest.useFakeTimers();
jest.advanceTimersByTime(1000);
jest.useRealTimers();

Async Testing

// Using async/await
it('fetches data asynchronously', async () => {
  const data = await fetchData();
  expect(data).toEqual({ id: 1 });
});

// Testing rejected promises
it('handles errors', async () => {
  await expect(fetchData()).rejects.toThrow('Network error');
});

// Waiting for side effects
it('updates state after fetch', async () => {
  render(<Component />);

  await waitFor(() => {
    expect(screen.getByText('Loaded')).toBeInTheDocument();
  });
});

React Component Testing

import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('LoginForm', () => {
  it('submits with valid credentials', async () => {
    const onSubmit = jest.fn();
    render(<LoginForm onSubmit={onSubmit} />);

    await userEvent.type(screen.getByLabelText('Email'), 'test@example.com');
    await userEvent.type(screen.getByLabelText('Password'), 'password123');
    await userEvent.click(screen.getByRole('button', { name: /submit/i }));

    expect(onSubmit).toHaveBeenCalledWith({
      email: 'test@example.com',
      password: 'password123',
    });
  });

  it('shows validation errors', async () => {
    render(<LoginForm onSubmit={jest.fn()} />);

    await userEvent.click(screen.getByRole('button', { name: /submit/i }));

    expect(screen.getByText('Email is required')).toBeInTheDocument();
  });
});

Configuration

jest.config.js

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/src'],
  testMatch: ['**/*.test.ts', '**/*.spec.ts'],
  collectCoverageFrom: [
    'src/**/*.ts',
    '!src/**/*.d.ts',
    '!src/**/*.test.ts',
  ],
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80,
    },
  },
  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
};

jest.setup.ts

import '@testing-library/jest-dom';

// Global mocks
global.fetch = jest.fn();

// Extend expect
expect.extend({
  toBeWithinRange(received: number, floor: number, ceiling: number) {
    const pass = received >= floor && received <= ceiling;
    return {
      message: () =>
        `expected ${received} ${pass ? 'not ' : ''}to be within range ${floor} - ${ceiling}`,
      pass,
    };
  },
});

Troubleshooting

Common Issues

  1. Tests hanging: Check for unresolved promises or missing done() callbacks
  2. Mock not working: Ensure mock is defined before importing the module
  3. Timeout errors: Increase timeout with jest.setTimeout(30000)
  4. Memory issues: Run with --maxWorkers=2 or --runInBand
Related skills