К основному содержанию
правило

jest — правило для Cursor: как писать тесты на Jest

Правило задаёт команде единый стиль тестов на Jest: конфиг, изоляция, моки и асинхронные проверки. Пригодится, если тесты в проекте пишут несколько человек.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/jest.mdc
Открыть на GitHub

Что делает jest

Файл .cursor/rules/jest.mdc подключается к Cursor и подсказывает агенту, как писать тесты в проектах на JavaScript и TypeScript. Область действия задана через globs: **/*.{js,ts,jsx,tsx}.

Внутри — набор договорённостей. Конфигурацию советуют держать в jest.config.ts с пресетом ts-jest, включёнными clearMocks и resetMocks, сбором покрытия из src/**/*.{js,jsx,ts,tsx} и исключением деклараций и точек входа. Тесты предлагают класть рядом с кодом — в __tests__/ или файлом *.test.ts, а не в отдельной папке tests/. Проверять поведение через публичный API, а не приватные поля. Для асинхронного кода — async/await, а не цепочки .then(). Изоляцию обеспечивают beforeEach и afterEach, зависимости подменяют через jest.mock и jest.spyOn, время — через jest.useFakeTimers.

Правило рассчитано на команду, которая уже договорилась о таком стиле. Если у вас другой пресет или тесты лежат в отдельной папке, часть советов придётся переписать под себя.

Какие задачи решает

  • договориться о едином конфиге Jest в команде
  • разложить тесты рядом с кодом, а не в отдельной папке
  • проверять поведение через публичный API, а не приватные поля
  • подменять внешние зависимости через jest.mock и jest.spyOn
  • изолировать тесты с помощью beforeEach и afterEach

Примеры запросов агенту

  • напиши тесты для src/utils/formatDate.ts по правилу jest
  • перепиши этот тест так, чтобы он не трогал приватные поля класса
  • добавь мок для модуля ./api в тесте сервиса

Как установить jest

Вручную: положить файлы

.cursor/rules/jest.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о jest

Как установить правило jest в Cursor?

Создайте файл .cursor/rules/jest.mdc в корне проекта и вставьте в него содержимое правила. Cursor подхватит его автоматически для файлов, подходящих под globs.

Что делает правило jest?

Задаёт набор договорённостей для тестов на Jest: конфигурацию в jest.config.ts, расположение тестов рядом с кодом, изоляцию через beforeEach и afterEach, работу с моками и асинхронным кодом.

Нужен ли ts-jest для этого правила?

В примере конфигурации используется пресет ts-jest для файлов TypeScript. Если в проекте другой пресет, конфиг придётся адаптировать под него.

Исходный текст

jest.mdc · CC0-1.0
---
description: Definitive guidelines for writing robust, maintainable, and performant Jest tests in JavaScript and TypeScript projects.
globs: **/*.{js,ts,jsx,tsx}
---
# jest Best Practices

This guide outlines our team's definitive Jest best practices. Adhere to these rules for consistent, reliable, and efficient testing.

## 1. Configuration (`jest.config.ts`)

Always use a `jest.config.ts` file for type safety and explicit configuration.

```typescript
// jest.config.ts
import type { Config } from 'jest';
import { defaults } from 'jest-config';

const config: Config = {
  // Use ts-jest for TypeScript files
  preset: 'ts-jest',
  // Automatically clear mock calls and instances between tests
  clearMocks: true,
  // Reset mocks between tests to prevent state leakage
  resetMocks: true,
  // Detailed test output
  verbose: true,
  // Collect coverage from specific files, exclude common boilerplate
  collectCoverageFrom: [
    'src/**/*.{js,jsx,ts,tsx}',
    '!src/**/*.d.ts',
    '!src/index.tsx', // Exclude entry points
    '!src/reportWebVitals.ts',
  ],
  // Ignore coverage for specific paths
  coveragePathIgnorePatterns: [
    '/node_modules/',
    'src/setupTests.ts',
  ],
  // Setup file for global test environment configurations (e.g., @testing-library/jest-dom)
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
  // Map module paths for aliases or specific packages
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1', // Example: for absolute imports
  },
  // Test environment for browser-like DOM APIs
  testEnvironment: 'jsdom',
  // Match test files ending with .test.ts(x) or .spec.ts(x)
  testMatch: [...defaults.testMatch, '**/?(*.)+(spec|test).[tj]s?(x)'],
};

export default config;
```

## 2. Test Organization

Colocate test files with the code they test. This improves discoverability and maintainability.

❌ BAD: Separate `tests/` directory
```
src/
  components/
    Button.tsx
tests/
  components/
    Button.test.tsx
```

✅ GOOD: Colocated `__tests__/` or `.test.ts`
```
src/
  components/
    Button/
      index.tsx
      __tests__/
        Button.test.tsx
  utils/
    formatDate.ts
    formatDate.test.ts
```

## 3. Core Principles

### Test Behavior, Not Implementation

Focus on the public API and expected outcomes. Refactoring internal logic should not break tests.

❌ BAD: Testing internal state or private methods
```typescript
class UserService {
  private _users: User[] = []; // Internal state

  constructor() { /* ... */ }
  async fetchUsers() { /* ... */ }
}

test('UserService should have empty _users array initially', () => {
  const service = new UserService();
  expect(service._users).toHaveLength(0); // Accessing private property
});
```

✅ GOOD: Testing public behavior
```typescript
class UserService {
  private _users: User[] = [];

  constructor() { /* ... */ }
  async fetchUsers() { /* ... */ return this._users; }
}

test('UserService should return an empty array of users initially', async () => {
  const service = new UserService();
  const users = await service.fetchUsers();
  expect(users).toHaveLength(0); // Testing public method output
});
```

### Descriptive Test Names

Use clear, concise names that explain *what* is being tested and *what* the expected outcome is.

❌ BAD: Vague names
```typescript
test('adds', () => { /* ... */ });
it('should work', () => { /* ... */ });
```

✅ GOOD: Specific and expressive names
```typescript
describe('sum function', () => {
  test('should correctly add two positive numbers', () => { /* ... */ });
  test('should return zero when adding zero to a number', () => { /* ... */ });
});
```

### Keep Tests Isolated

Each test should run independently without relying on the state or side effects of other tests. Use `beforeEach` and `afterEach` for setup/teardown.

```typescript
let mockData: any[];

beforeEach(() => {
  mockData = [{ id: 1, name: 'Alice' }];
});

afterEach(() => {
  // Clean up any global mocks or side effects if not handled by config.resetMocks
  jest.clearAllMocks();
});

test('should add a new item to mockData', () => {
  mockData.push({ id: 2, name: 'Bob' });
  expect(mockData).toHaveLength(2);
});

test('should retrieve the initial mockData', () => {
  expect(mockData).toHaveLength(1); // mockData is reset by beforeEach
});
```

## 4. Asynchronous Testing

Always use `async/await` for asynchronous code.

❌ BAD: Using `.then()` or forgetting `await`
```typescript
test('should fetch user data', () => {
  fetchUser(1).then(user => {
    expect(user.id).toBe(1);
  });
});

test('should not fetch user data (missing await)', () => {
  const user = fetchUser(1); // Test finishes before promise resolves
  expect(user).toBeDefined(); // This will pass, but user is a Promise
});
```

✅ GOOD: Using `async/await`
```typescript
test('should fetch user data correctly', async () => {
  const user = await fetchUser(1);
  expect(user.id).toBe(1);
});

test('should handle fetch error', async () => {
  await expect(fetchUser(999)).rejects.toThrow('User not found');
});
```

## 5. Mocking Strategies

Mock external dependencies to isolate the unit under test and ensure deterministic, fast tests.

### Automatic Mocks (`jest.mock`)

Use `jest.mock` for entire modules.

```typescript
// api.ts
export const fetchData = async () => { /* ... */ };

// service.ts
import { fetchData } from './api';
export const getServiceData = async () => fetchData();

// service.test.ts
import { getServiceData } from './service';
import { fetchData } from './api';

jest.mock('./api'); // Mocks the entire module

test('getServiceData should call fetchData', async () => {
  (fetchData as jest.Mock).mockResolvedValue('mocked data'); // Cast to jest.Mock
  const data = await getServiceData();
  expect(data).toBe('mocked data');
  expect(fetchData).toHaveBeenCalledTimes(1);
});
```

### Spying on Functions (`jest.spyOn`)

Use `jest.spyOn` to observe calls to existing functions without replacing their original implementation (unless you explicitly mock it).

```typescript
// calculator.ts
export const add = (a: number, b: number) => a + b;
export const calculate = (a: number, b: number) => add(a, b) * 2;

// calculator.test.ts
import * as calculator from './calculator';

test('calculate should call add', () => {
  const addSpy = jest.spyOn(calculator, 'add');
  calculator.calculate(1, 2);
  expect(addSpy).toHaveBeenCalledWith(1, 2);
  addSpy.mockRestore(); // Clean up the spy
});

test('calculate should return mocked value if add is mocked', () => {
  const addSpy = jest.spyOn(calculator, 'add').mockReturnValue(100);
  const result = calculator.calculate(1, 2);
  expect(result).toBe(200); // 100 * 2
  addSpy.mockRestore();
});
```

### Fake Timers (`jest.useFakeTimers`)

Control `setTimeout`, `setInterval`, `Date` for predictable tests involving time.

```typescript
// timer.ts
export const runAfterDelay = (cb: () => void) => setTimeout(cb, 1000);

// timer.test.ts
import { runAfterDelay } from './timer';

jest.useFakeTimers();

test('runAfterDelay calls the callback after 1 second', () => {
  const callback = jest.fn();
  runAfterDelay(callback);

  expect(callback).not.toHaveBeenCalled();
  jest.advanceTimersByTime(500); // Advance by 500ms
  expect(callback).not.toHaveBeenCalled();
  jest.advanceTimersByTime(500); // Advance by another 500ms (total 1000ms)
  expect(callback).toHaveBeenCalledTimes(1);
});

jest.useRealTimers(); // Restore real timers after tests
```

### Avoid Over-Mocking

Mock only what's necessary. Over-mocking can lead to brittle tests that don't reflect real-world behavior.

## 6. UI Component Testing (with React Testing Library)

For React components, use React Testing Library with `@testing-library/jest-dom` matchers.

```typescript
// src/setupTests.ts (referenced in jest.config.ts)
import '@testing-library/jest-dom';

// src/components/Button/index.tsx
type ButtonProps = { onClick: () => void; children: React.ReactNode; };
export const Button = ({ onClick, children }: ButtonProps) => (
  <button onClick={onClick}>{children}</button>
);

// src/components/Button/__tests__/Button.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from '../';

test('Button renders children and handles click', async () => {
  const user = userEvent.setup();
  const handleClick = jest.fn();
  render(<Button onClick={handleClick}>Click Me</Button>);

  const button = screen.getByRole('button', { name: /click me/i });
  expect(button).toBeInTheDocument();

  await user.click(button);
  expect(handleClick).toHaveBeenCalledTimes(1);
});
```

### Avoid `screen.debug()` in Committed Code

`screen.debug()` is for debugging during development, not for production tests.

❌ BAD:
```typescript
test('renders component', () => {
  render(<MyComponent />);
  screen.debug(); // Should not be committed
  expect(screen.getByText('Hello')).toBeInTheDocument();
});
```

✅ GOOD:
```typescript
test('renders component', () => {
  render(<MyComponent />);
  expect(screen.getByText('Hello')).toBeInTheDocument();
});
```

## 7. Snapshot Testing

Use snapshot tests for UI components or schema stability, but review them carefully.

```typescript
// src/components/Card/__tests__/Card.test.tsx
import { render } from '@testing-library/react';
import { Card } from '../';

test('Card component matches snapshot', () => {
  const { asFragment } = render(<Card title="Test" content="Hello World" />);
  expect(asFragment()).toMatchSnapshot();
});

// For GraphQL schema stability (requires jest-serializer-graphql-schema)
import { buildSchema } from 'graphql';
import { lexicographicSortSchema } from 'graphql/utilities';

test('GraphQL schema is stable', () => {
  const schema = buildSchema(/* ... */);
  expect(lexicographicSortSchema(schema)).toMatchSnapshot();
});
```

## 8. Avoid Focused Tests in Committed Code

Never commit `.only` or `.skip` to the codebase. These are for local development only.

❌ BAD:
```typescript
describe.only('My Feature', () => { /* ... */ });
test.skip('should not run this test', () => { /* ... */ });
```

✅ GOOD:
```typescript
describe('My Feature', () => { /* ... */ });
test('should run this test', () => { /* ... */ });
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Всё по теме «Тесты и QA» →
bun-jest-migration secondsky Скилл ведёт миграцию тестов с Jest на встроенный раннер Bun: импорты, моки, таймеры, конфиг. CX Codex +1 386установок jest-react-testing manutej Скилл для тестирования React-компонентов и хуков через Jest и React Testing Library: конфигурация, моки, асинхронные сценарии. CX Codex +1 1 200установок testing-anti-patterns bobmatnyc Скилл помогает находить ошибки в тестах: проверки поведения моков, тестовые методы в продакшене и неполные заглушки. CX Codex +1 368установок experience-lwc-accessibility-jest-run forcedotcom Запускает модульные тесты доступности Sa11y Jest для компонентов LWC в среде Bazel или автономном Jest. CX Codex +1 898установок javascript-testing-patterns Seth Hobson Скилл подсказывает, как писать unit-, интеграционные и end-to-end-тесты для JavaScript и TypeScript. Пригодится при настройке тестовой инфраструктуры и работе по TDD. CX Codex 20 472установок testing-best-practices agent-skills Набор правил по юнит- и интеграционным тестам и TDD: 34 правила в 7 категориях на TypeScript с Jest и Vitest. Пригодится, когда пишете тесты или разбираете чужие. CX Codex +1 899установок

Из того же набора69

llama-index Правило Cursor с примерами кода для LlamaIndex: модульные функции, Workflow API, LlamaCloud и асинхронная обработка документов. ★ 3 579звёзд репо langgraph Правило для Cursor с практиками LangGraph: как раскладывать узлы, состояния и подграфы в Python-проекте. ★ 3 579звёзд репо kubernetes Правило для Cursor задаёт, как писать и раскладывать по файлам манифесты Kubernetes: метки, ресурсы, пробы, Pod Security Standards. ★ 3 579звёзд репо junit Правило для Cursor задаёт стиль юнит-тестов на JUnit 5 в Java-проектах: имена, структура, параметризация. Пригодится, когда тесты пишет агент и хочется единый вид. ★ 3 579звёзд репо java Правило задаёт агенту стиль кода Java: Google Java Style, именование, иммутабельность, Stream API и работа с ресурсами. ★ 3 579звёзд репо httpx Правило для Cursor задаёт, как работать с httpx в Python: переиспользовать клиент, включать HTTP/2, настраивать таймауты. Пригодится, если агент пишет сетевой код. ★ 3 579звёзд репо hardhat Правило для Cursor задаёт стандарты проекта на Hardhat 3: конфиг на TypeScript, тесты на Solidity и TypeScript, деплой через Ignition. ★ 3 579звёзд репо grafana Правило задаёт команде единый стиль работы с дашбордами, алертами и источниками данных Grafana в виде кода: структура, визуальные стандарты, оптимизация запросов. ★ 3 579звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой