Frontend TDD Agent. React/Next.js 기반 TDD 테스트 작성 및 구현을 담당합니다. 테스트 먼저 작성 후 구현하는 Red-Green-Refactor 사이클을 따릅니다.
Install with Tessl CLI
npx tessl i github:shaul1991/shaul-agents-plugin --skill frontend-tddOverall
score
61%
Does it follow best practices?
If you maintain this skill, you can automatically optimize it using the tessl CLI to improve its score:
npx tessl skill review --optimize ./path/to/skillValidation for skill structure
TDD(Test-Driven Development) 방식으로 Frontend 코드를 개발합니다. 테스트를 먼저 작성하고, 테스트를 통과하는 최소한의 코드를 구현합니다.
┌─────────────────────────────────────────────────────────────────┐
│ 1. RED (실패하는 테스트) │
│ - 테스트 케이스 작성 │
│ - 테스트 실행 → 실패 확인 │
└─────────────────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 2. GREEN (테스트 통과) │
│ - 최소한의 코드 작성 │
│ - 테스트 실행 → 통과 확인 │
└─────────────────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 3. REFACTOR (리팩토링) │
│ - 코드 개선 │
│ - 테스트 실행 → 여전히 통과 확인 │
└─────────────────────────────────────────────────────────────────┘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: 'john@test.com' }} />);
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');
});
});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);
});
});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();
});
});
});# 전체 테스트 실행
npm run test
# Watch 모드
npm run test:watch
# 특정 파일 테스트
npm run test -- UserProfile
# 커버리지 리포트
npm run test:coverage
# E2E 테스트 (Playwright)
npm run test:e2eit('should do something', () => {
// Arrange - 준비
const user = { name: 'John' };
// Act - 실행
render(<Component user={user} />);
// Assert - 검증
expect(screen.getByText('John')).toBeInTheDocument();
});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% |
src/**/*.test.tsx, src/**/*.spec.tsxsrc/test/utils.tsxsrc/mocks/handlers.tsIf you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.