# Test Generation Checklist Use this checklist when generating or reviewing tests for Dify frontend components. ## Pre-Generation - [ ] Read the component source code completely - [ ] Identify component type (component, hook, utility, page) - [ ] Run `pnpm analyze-component ` if available - [ ] Note complexity score and features detected - [ ] Check for existing tests in the same directory - [ ] **Identify ALL files in the directory** that need testing (not just index) ## Testing Strategy ### ⚠️ Incremental Workflow (CRITICAL for Multi-File) - [ ] **NEVER generate all tests at once** - process one file at a time - [ ] Order files by complexity: utilities → hooks → simple → complex → integration - [ ] Create a todo list to track progress before starting - [ ] For EACH file: write → run test → verify pass → then next - [ ] **DO NOT proceed** to next file until current one passes ### Path-Level Coverage - [ ] **Test ALL files** in the assigned directory/path - [ ] List all components, hooks, utilities that need coverage - [ ] Decide: single spec file (integration) or multiple spec files (unit) ### Complexity Assessment - [ ] Run `pnpm analyze-component ` for complexity score - [ ] **Complexity > 50**: Consider refactoring before testing - [ ] **500+ lines**: Consider splitting before testing - [ ] **30-50 complexity**: Use multiple describe blocks, organized structure ### Integration vs Mocking - [ ] **DO NOT mock base components** (`Loading`, `Button`, `Tooltip`, etc.) - [ ] Import real project components instead of mocking - [ ] Only mock: API calls, complex context providers, third-party libs with side effects - [ ] Prefer integration testing when using single spec file ## Required Test Sections ### All Components MUST Have - [ ] **Rendering tests** - Component renders without crashing - [ ] **Props tests** - Required props, optional props, default values - [ ] **Edge cases** - null, undefined, empty values, boundaries ### Conditional Sections (Add When Feature Present) | 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 | ## Code Quality Checklist ### Structure - [ ] Uses `describe` blocks to group related tests - [ ] Test names follow `should when ` pattern - [ ] AAA pattern (Arrange-Act-Assert) is clear - [ ] Comments explain complex test scenarios ### Mocks - [ ] **DO NOT mock base components** (`@/app/components/base/*`) - [ ] `vi.clearAllMocks()` in `beforeEach` (not `afterEach`) - [ ] Shared mock state reset in `beforeEach` - [ ] i18n uses global mock (auto-loaded in `web/vitest.setup.ts`); only override locally for custom translations - [ ] Router mocks match actual Next.js API - [ ] Mocks reflect actual component conditional behavior - [ ] Only mock: API services, complex context providers, third-party libs ### Queries - [ ] Prefer semantic queries (`getByRole`, `getByLabelText`) - [ ] Use `queryBy*` for absence assertions - [ ] Use `findBy*` for async elements - [ ] `getByTestId` only as last resort ### Async - [ ] All async tests use `async/await` - [ ] `waitFor` wraps async assertions - [ ] Fake timers properly setup/teardown - [ ] No floating promises ### TypeScript - [ ] No `any` types without justification - [ ] Mock data uses actual types from source - [ ] Factory functions have proper return types ## Coverage Goals (Per File) For the current file being tested: - [ ] 100% function coverage - [ ] 100% statement coverage - [ ] >95% branch coverage - [ ] >95% line coverage ## Post-Generation (Per File) **Run these checks after EACH test file, not just at the end:** - [ ] Run `pnpm test path/to/file.spec.tsx` - **MUST PASS before next file** - [ ] Fix any failures immediately - [ ] Mark file as complete in todo list - [ ] Only then proceed to next file ### After All Files Complete - [ ] Run full directory test: `pnpm test path/to/directory/` - [ ] Check coverage report: `pnpm test:coverage` - [ ] Run `pnpm lint:fix` on all test files - [ ] Run `pnpm type-check:tsgo` ## Common Issues to Watch ### False Positives ```typescript // ❌ Mock doesn't match actual behavior vi.mock('./Component', () => () =>
Mocked
) // ✅ Mock matches actual conditional logic vi.mock('./Component', () => ({ isOpen }: any) => isOpen ?
Content
: null ) ``` ### State Leakage ```typescript // ❌ Shared state not reset let mockState = false vi.mock('./useHook', () => () => mockState) // ✅ Reset in beforeEach beforeEach(() => { mockState = false }) ``` ### Async Race Conditions ```typescript // ❌ Not awaited it('loads data', () => { render() expect(screen.getByText('Data')).toBeInTheDocument() }) // ✅ Properly awaited it('loads data', async () => { render() await waitFor(() => { expect(screen.getByText('Data')).toBeInTheDocument() }) }) ``` ### Missing Edge Cases Always test these scenarios: - `null` / `undefined` inputs - Empty strings / arrays / objects - Boundary values (0, -1, MAX_INT) - Error states - Loading states - Disabled states ## Quick Commands ```bash # 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 ```