.agents/skills/frontend-testing/references/checklist.md
Use this checklist when generating or reviewing tests for Dify frontend components.
pnpm analyze-component <path> if availablepnpm analyze-component <path> for complexity scoreLoading, Input, Badge; dify-ui Button, Tooltip, Dialog, etc.)| Feature | Add Tests For |
|---|---|
useState | Initial state, transitions, cleanup |
useEffect | Execution, dependencies, cleanup |
| Event handlers | onClick, onChange, onSubmit, keyboard |
| API calls | Loading, success, error states |
| Routing | Navigation, params, query strings |
useCallback/useMemo | Referential equality |
| Context | Provider values, consumer behavior |
| Forms | Validation, submission, error display |
describe blocks to group related testsshould <behavior> when <condition> pattern@/app/components/base/* or @langgenius/dify-ui/*)vi.clearAllMocks() in beforeEach (not afterEach)beforeEachweb/vitest.setup.ts); only override locally for custom translationsnuqs URL-state tests, wrap with NuqsTestingAdapter (prefer web/test/nuqs-testing.tsx)nuqs URL-state tests, assert onUrlUpdate payload (searchParams, options.history)nuqs parser exists, add round-trip tests for encoded edge cases (%2F, %25, spaces, legacy encoded values)getByRole, getByLabelText)queryBy* for absence assertionsfindBy* for async elementsgetByTestId only as last resortasync/awaitwaitFor wraps async assertionsany types without justificationFor the current file being tested:
Run these checks after EACH test file, not just at the end:
pnpm test path/to/file.spec.tsx - MUST PASS before next filepnpm test path/to/directory/pnpm test:coveragepnpm lint:fix on all test filespnpm type-check// ❌ Mock doesn't match actual behavior
vi.mock('./Component', () => () => <div>Mocked</div>)
// ✅ Mock matches actual conditional logic
vi.mock('./Component', () => ({ isOpen }: any) =>
isOpen ? <div>Content</div> : null
)
// ❌ Shared state not reset
let mockState = false
vi.mock('./useHook', () => () => mockState)
// ✅ Reset in beforeEach
beforeEach(() => {
mockState = false
})
// ❌ Not awaited
it('loads data', () => {
render(<Component />)
expect(screen.getByText('Data')).toBeInTheDocument()
})
// ✅ Properly awaited
it('loads data', async () => {
render(<Component />)
await waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument()
})
})
Always test these scenarios:
null / undefined inputs# Run specific test
pnpm test path/to/file.spec.tsx
# Run with coverage
pnpm test:coverage path/to/file.spec.tsx
# Watch mode
pnpm test:watch path/to/file.spec.tsx
# Update snapshots (use sparingly)
pnpm test -u path/to/file.spec.tsx
# Analyze component
pnpm analyze-component path/to/component.tsx
# Review existing test
pnpm analyze-component path/to/component.tsx --review