home / skills / shaul1991 / shaul-agents-plugin / frontend-tdd

frontend-tdd skill

/skills/frontend-tdd

This skill guides frontend TDD by writing tests first and implementing the minimal code to pass, following red-green-refactor cycles.

npx playbooks add skill shaul1991/shaul-agents-plugin --skill frontend-tdd

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.4 KB
---
name: frontend-tdd
description: Frontend TDD Agent. React/Next.js 기반 TDD 테스트 작성 및 구현을 담당합니다. 테스트 먼저 작성 후 구현하는 Red-Green-Refactor 사이클을 따릅니다.
allowed-tools: Bash(npm:*, npx:*), Read, Write, Edit, Grep, Glob
---

# Frontend TDD Agent

## 역할

TDD(Test-Driven Development) 방식으로 Frontend 코드를 개발합니다.
테스트를 먼저 작성하고, 테스트를 통과하는 최소한의 코드를 구현합니다.

## TDD 사이클

```
┌─────────────────────────────────────────────────────────────────┐
│                    1. RED (실패하는 테스트)                       │
│  - 테스트 케이스 작성                                            │
│  - 테스트 실행 → 실패 확인                                       │
└─────────────────────────────┬───────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    2. GREEN (테스트 통과)                         │
│  - 최소한의 코드 작성                                            │
│  - 테스트 실행 → 통과 확인                                       │
└─────────────────────────────┬───────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    3. REFACTOR (리팩토링)                         │
│  - 코드 개선                                                     │
│  - 테스트 실행 → 여전히 통과 확인                                 │
└─────────────────────────────────────────────────────────────────┘
```

## 테스트 스택

- **Test Runner**: Jest / Vitest
- **Component Testing**: React Testing Library
- **E2E Testing**: Playwright
- **Mocking**: MSW (Mock Service Worker)
- **Coverage**: Istanbul / c8

## 테스트 유형

### 1. 컴포넌트 테스트

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

describe('UserProfile', () => {
  // 렌더링 테스트
  it('should render user name', () => {
    render(<UserProfile user={{ name: 'John', email: '[email protected]' }} />);

    expect(screen.getByText('John')).toBeInTheDocument();
  });

  // 인터랙션 테스트
  it('should call onEdit when edit button clicked', () => {
    const onEdit = jest.fn();
    render(<UserProfile user={{ name: 'John' }} onEdit={onEdit} />);

    fireEvent.click(screen.getByRole('button', { name: /edit/i }));

    expect(onEdit).toHaveBeenCalledTimes(1);
  });

  // 상태 테스트
  it('should show loading state', () => {
    render(<UserProfile isLoading />);

    expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
  });

  // 에러 상태 테스트
  it('should show error message when error occurs', () => {
    render(<UserProfile error="Failed to load" />);

    expect(screen.getByRole('alert')).toHaveTextContent('Failed to load');
  });
});
```

### 2. Hook 테스트

```typescript
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';

describe('useCounter', () => {
  it('should initialize with default value', () => {
    const { result } = renderHook(() => useCounter(0));

    expect(result.current.count).toBe(0);
  });

  it('should increment count', () => {
    const { result } = renderHook(() => useCounter(0));

    act(() => {
      result.current.increment();
    });

    expect(result.current.count).toBe(1);
  });

  it('should decrement count', () => {
    const { result } = renderHook(() => useCounter(10));

    act(() => {
      result.current.decrement();
    });

    expect(result.current.count).toBe(9);
  });
});
```

### 3. API 통합 테스트 (MSW)

```typescript
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { render, screen, waitFor } from '@testing-library/react';
import { UserList } from './UserList';

const server = setupServer(
  rest.get('/api/users', (req, res, ctx) => {
    return res(
      ctx.json([
        { id: 1, name: 'John' },
        { id: 2, name: 'Jane' },
      ])
    );
  })
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

describe('UserList', () => {
  it('should fetch and display users', async () => {
    render(<UserList />);

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

  it('should handle API error', async () => {
    server.use(
      rest.get('/api/users', (req, res, ctx) => {
        return res(ctx.status(500));
      })
    );

    render(<UserList />);

    await waitFor(() => {
      expect(screen.getByRole('alert')).toBeInTheDocument();
    });
  });
});
```

## 테스트 명령어

```bash
# 전체 테스트 실행
npm run test

# Watch 모드
npm run test:watch

# 특정 파일 테스트
npm run test -- UserProfile

# 커버리지 리포트
npm run test:coverage

# E2E 테스트 (Playwright)
npm run test:e2e
```

## 테스트 패턴

### AAA 패턴 (Arrange-Act-Assert)

```typescript
it('should do something', () => {
  // Arrange - 준비
  const user = { name: 'John' };

  // Act - 실행
  render(<Component user={user} />);

  // Assert - 검증
  expect(screen.getByText('John')).toBeInTheDocument();
});
```

### Given-When-Then 패턴

```typescript
describe('Login Form', () => {
  describe('given valid credentials', () => {
    describe('when user submits form', () => {
      it('then should redirect to dashboard', async () => {
        // test code
      });
    });
  });
});
```

## 테스트 커버리지 목표

| 유형 | 목표 |
|------|------|
| 전체 | > 80% |
| 컴포넌트 | > 90% |
| Hooks | > 95% |
| Utils | > 95% |

## TDD 체크리스트

### 테스트 작성 전
- [ ] 요구사항이 명확한가?
- [ ] 테스트할 동작을 정의했는가?
- [ ] 엣지 케이스를 식별했는가?

### 테스트 작성 시
- [ ] 테스트명이 동작을 설명하는가?
- [ ] 하나의 테스트는 하나만 검증하는가?
- [ ] 테스트가 실패하는가? (RED)

### 구현 시
- [ ] 최소한의 코드로 구현했는가?
- [ ] 테스트가 통과하는가? (GREEN)

### 리팩토링 시
- [ ] 중복 코드를 제거했는가?
- [ ] 테스트가 여전히 통과하는가?
- [ ] 코드가 읽기 쉬운가?

## 산출물 위치

- 테스트 코드: `src/**/*.test.tsx`, `src/**/*.spec.tsx`
- 테스트 유틸: `src/test/utils.tsx`
- MSW 핸들러: `src/mocks/handlers.ts`

Overview

This skill is a Frontend TDD Agent that writes and implements React/Next.js code using a strict Test-Driven Development workflow. I follow the Red-Green-Refactor cycle: write a failing test, implement the minimal code to pass, then safely refactor while keeping tests green. The agent produces component, hook, and API integration tests and enforces coverage targets.

How this skill works

I generate focused tests first (component, hook, API) using Jest or Vitest and React Testing Library, then implement minimal code to satisfy each test. For network interactions I stub endpoints with MSW; for end-to-end flows I use Playwright. I run tests, update implementations, and repeat the Red-Green-Refactor loop until the desired coverage and quality goals are met.

When to use it

  • Developing new React/Next.js features with guaranteed test coverage
  • Refactoring existing frontend code while preserving behavior
  • Adding or validating hooks and utility functions with high confidence
  • Building API-integrated UI components without relying on live backends
  • Setting up TDD workflows and CI test scripts for frontend repos

Best practices

  • Write a single clear assertion per test and follow AAA or Given-When-Then patterns
  • Start with failing tests that describe expected behavior and edge cases
  • Use MSW to simulate API responses and error conditions rather than calling real services
  • Aim for the stated coverage targets but prioritize meaningful tests over synthetic coverage
  • Keep tests fast and deterministic: prefer unit/component tests, use E2E sparingly for critical flows

Example use cases

  • Create UserProfile component: write rendering and interaction tests, implement minimal UI and handlers
  • Test a custom hook like useCounter: renderHook, exercise actions, assert state changes
  • Build UserList with API integration: mock /api/users using MSW, verify loading, success, and error states
  • Add Playwright E2E for login flow to validate critical user journeys end-to-end
  • Enforce CI: run npm run test and coverage checks on pull requests to prevent regressions

FAQ

Which test runners do you use?

I use Jest or Vitest for unit and component tests, and Playwright for E2E scenarios.

How do you handle network dependencies in tests?

I mock network calls with MSW in integration and component tests to control responses and simulate errors.

What coverage targets do you aim for?

Default goals are >80% overall, >90% for components, and >95% for hooks and utilities.