🧪 Что это
TDD Workflow Pro — это skill для агентов кодирования, который внедряет дисциплину Test-Driven Development (TDD) в повседневную разработку. Он гарантирует, что любой новый код (функции, исправления ошибок, рефакторинг, API, компоненты) пишется с обязательным покрытием тестами не ниже 80% на всех уровнях: unit-, integration- и E2E-тесты.
Skill полезен командам, которые хотят повысить надёжность кода, сократить регрессии и получить «страховочную сетку» для безопасного рефакторинга. Он не просто рекомендует TDD, а заставляет агента строго следовать красному-зелёному-рефакторинг циклу.
⚙️ Как работает
📝 Шаг 1: Пользовательские истории
Перед написанием кода агент формулирует задачу в формате:
Как [роль] я хочу [действие] чтобы [выгода]
Пример:
- Как пользователь, я хочу семантически искать рынки, чтобы находить их даже без точных ключевых слов.
🧪 Шаг 2: Создание тестовых сценариев
Для каждой истории генерируется полный набор тестов: счастливый путь, граничные случаи, обработка ошибок, fallback-поведение, сортировка и т.д. Тесты пишутся на Jest/Vitest (unit), Next.js route тесты (integration) и Playwright (E2E).
Пример описания сценария:
describe('Semantic Search', () => {
it('returns relevant markets for a query', async () => { /* ... */ });
it('handles empty query gracefully', async () => { /* ... */ });
it('falls back to substring search if Redis is unavailable', async () => { /* ... */ });
it('sorts results by similarity score', async () => { /* ... */ });
});
🔴 Шаг 3: Запуск тестов (они должны падать)
Команда npm test запускает тесты — они должны провалиться, ведь реализации ещё нет. Это красная фаза.
🟢 Шаг 4: Реализация кода
Пишется минимальный код, достаточный для прохождения тестов. Ничего лишнего. Например:
export async function searchMarkets(query: string) {
// реализация, управляемая тестами
}
🟢 Шаг 5: Повторный запуск тестов
Снова npm test — теперь тесты должны проходить. Если нет — вернуться к шагу 4.
🔄 Шаг 6: Рефакторинг
Не меняя внешнего поведения (тесты зелёные), улучшается качество кода: удаление дублирования, улучшение имён, оптимизация, читаемость.
✅ Шаг 7: Проверка покрытия
Команда npm run test:coverage проверяет, что покрытие >= 80% (настраивается в jest.config). Если нет — добавляются недостающие тесты.
🧩 Поддерживаемые типы тестов
- Unit-тесты (
*.test.tsx рядом с компонентом): проверка логики компонентов, pure-функций, утилит.
- Integration-тесты (
route.test.ts): проверка API-эндпоинтов, взаимодействия с БД, внешних сервисов.
- E2E-тесты (
*.spec.ts в папке e2e/): полные пользовательские сценарии через Playwright (например, авторизация, создание рынка, фильтрация).
🧪 Примеры шаблонов
Unit-тест (Jest/Vitest):
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';
describe('Button Component', () => {
it('renders with correct text', () => {
render(`Button`Click);
expect(screen.getByText('Click')).toBeInTheDocument();
});
});
API Integration тест (Next.js):
import { NextRequest } from 'next/server';
import { GET } from './route';
describe('GET /api/markets', () => {
it('returns markets successfully', async () => {
const request = new NextRequest('http://localhost/api/markets');
const response = await GET(request);
expect(response.status).toBe(200);
});
});
E2E тест (Playwright):
test('user can search and filter markets', async ({ page }) => {
await page.goto('/');
await page.click('a[href="/markets"]');
await page.fill('input[placeholder="Search markets"]', 'election');
await page.waitForTimeout(600);
const results = page.locator('[data-testid="market-card"]');
await expect(results).toHaveCount(5, { timeout: 5000 });
});
🛠 Важные анти-паттерны, которые запрещает skill
| ❌ Неправильно |
✅ Правильно |
Тестировать внутренний state (component.state.count) |
Тестировать видимое пользователю поведение (screen.getByText('Count: 5')) |
Использовать хрупкие CSS-селекторы (.css-class-xyz) |
Использовать semantic-селекторы ([data-testid="submit-button"]) |
| Не изолировать тесты (один тест зависит от другого) |
Каждый тест создаёт свои данные с нуля (createTestUser()) |
🧪 Мокирование внешних сервисов
Skill предлагает готовые примеры моков для:
- Supabase:
jest.mock('@/lib/supabase', ...)
- Redis:
jest.mock('@/lib/redis', ...)
- OpenAI:
jest.mock('@/lib/openai', ...)
Это изолирует unit-тесты от реальных сервисов и ускоряет их выполнение.
📊 Когда использовать
- При добавлении новой функциональности в проект.
- При исправлении багов (сначала пишется тест, воспроизводящий баг, затем код).
- При рефакторинге существующего кода (тесты — гарантия, что ничего не сломалось).
- При создании новых API, компонентов, утилит.
- В CI/CD — тесты запускаются в pre-commit hook и в GitHub Actions.
💡 Важно знать
- Минимальное покрытие — 80% (настраивается в
jest.config): branches, functions, lines, statements.
- Тесты не опциональны — это обязательное условие для выполнения задачи агентом.
- Тесты должны быть быстрыми: unit < 50ms каждый, весь набор unit-тестов < 30 секунд.
- Не пропускать фазу «красный»: всегда сначала убедитесь, что тесты падают, иначе TDD теряет смысл.
🧹 Организация тестовых файлов
src/
├── components/
│ ├── Button/
│ │ ├── Button.tsx
│ │ ├── Button.test.tsx # Unit
│ │ └── Button.stories.tsx # Storybook
│ └── MarketCard/
│ ├── MarketCard.tsx
│ └── MarketCard.test.tsx
├── app/api/markets/
│ ├── route.ts
│ └── route.test.ts # Integration
└── e2e/
├── markets.spec.ts # E2E
├── trading.spec.ts
└── auth.spec.ts
📈 Метрики успеха
- 80%+ покрытие.
- Все тесты зелёные (ни одного skipped/disabled).
- Unit-тесты выполняются < 30 секунд.
- E2E-тесты покрывают критический пользовательский путь.
- Тесты ловят баги до деплоя.
Помните: тесты — это не опция, а страховочная сетка для уверенного рефакторинга и быстрой разработки. 🚀
Комментарии
Комментариев пока нет. Будьте первым.