| name | frontend-testing |
| version | 1.0.0 |
| description | Frontend testing guide — unit, integration, visual regression, accessibility, E2E for UI |
| requires | [] |
| task_types | ["testing","frontend-testing","qa","e2e"] |
| applies_to_tags | ["testing","frontend","qa","playwright","vitest","cypress"] |
Frontend Testing Skill
Thứ tự ưu tiên test
- E2E critical paths — happy path của user journey quan trọng nhất
- Integration tests — component với real API/state
- Unit tests — utilities, hooks, pure functions
- Visual regression — screenshot comparison cho UI quan trọng
- Accessibility audit — automated a11y check
Unit Test (Vitest / Jest)
Cái gì nên unit test
- Pure utility functions (date format, validation, transform)
- Custom hooks (dùng
renderHook)
- Complex business logic trong component
- Error boundary behavior
Pattern
const input = { ... }
const result = fn(input)
expect(result).toEqual(expected)
- Test behavior, không test implementation
- Mock tối thiểu — chỉ mock external services, không mock internal modules
- Tên test mô tả behavior:
"returns empty array when no results match"
Component / Integration Test (Testing Library)
render(<TaskCard task={mockTask} />)
expect(screen.getByRole('heading', { name: 'Fix bug' })).toBeVisible()
await userEvent.click(screen.getByRole('button', { name: 'Claim' }))
expect(mockClaim).toHaveBeenCalledWith(taskId)
Query priority (ưu tiên từ cao xuống thấp)
getByRole — accessible name
getByLabelText — form fields
getByText — visible text
getByTestId — last resort
E2E Test (Playwright)
Checklist viết test
test('user can claim a task', async ({ page }) => {
await page.goto('/board')
await page.getByRole('button', { name: 'Claim' }).first().click()
await expect(page.getByText('In Progress')).toBeVisible()
})
Tránh flaky tests
- Không hardcode timeout — dùng
waitForSelector / waitForResponse
- Không test timing animations
- Isolate test data — mỗi test tự tạo data riêng hoặc reset state
Visual Regression
- Screenshot các breakpoint: 375, 768, 1280, 1920
- Test cả light và dark mode nếu project có
- Chạy sau mỗi UI change đáng kể
- Review diff trước khi approve snapshot update
Accessibility Testing
import { axe } from 'jest-axe'
const { container } = render(<Component />)
const results = await axe(container)
expect(results).toHaveNoViolations()
- Keyboard navigation: Tab qua tất cả interactive elements
- Screen reader test với VoiceOver (Mac) hoặc NVDA (Windows)
- Focus trap trong modal/dialog
Coverage targets
| Loại | Minimum |
|---|
| Utility functions | 95% |
| Hooks | 85% |
| Components (branch) | 80% |
| Critical user paths (E2E) | 100% |
Khi test fail
- Reproduce locally trước khi sửa
- Đọc error message đầy đủ
- Kiểm tra xem test sai hay implementation sai
- Không disable test — fix root cause
- Nếu flaky: xác định race condition và fix bằng proper wait