Skill: Frontend Testing Patterns
When to load
When writing tests for components, hooks, or integration flows.
Philosophy
Test behavior, not implementation. A user doesn't care that you called setState; they care that clicking "Submit" shows a success message.
Component Test Template
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { UserCard } from './UserCard';
const defaultUser: User = {
id: '1', name: 'Jane Smith', email: 'jane@example.com', role: 'admin',
};
describe('UserCard', () => {
it('renders user information', () => {
render(<UserCard user={defaultUser} />);
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
});
it('calls onEdit when edit button is clicked', async () => {
const
render(<UserCard user={defaultUser} />);
await userEvent.click(screen.getByRole('button', { name: /edit/i }));
expect(onEdit).toHaveBeenCalledWith(defaultUser.id);
});
});
Custom Hook Testing
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';
it('increments count', () => {
const { result } = renderHook(() => useCounter(0));
act(() => { result.current.increment(); });
expect(result.current.count).toBe(1);
});
MSW: Mock API Calls
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('/api/users', () =>
HttpResponse.json([{ id: '1', name: 'Jane' }])
),
];
Test Type Decision
| Scenario | Test Type |
|---|---|
| Component renders | Unit (RTL) |
| User interaction | Unit (RTL + userEvent) |
| Data fetching states | Unit (RTL + MSW) |
| Full user journey | E2E (Playwright) |