Skip to content

Commit ee27705

Browse files
authored
Merge branch 'langgenius:main' into main
2 parents a04bdf1 + 80c74cf commit ee27705

704 files changed

Lines changed: 34765 additions & 14299 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Test Generation Checklist
2+
3+
Use this checklist when generating or reviewing tests for Dify frontend components.
4+
5+
## Pre-Generation
6+
7+
- [ ] Read the component source code completely
8+
- [ ] Identify component type (component, hook, utility, page)
9+
- [ ] Run `pnpm analyze-component <path>` if available
10+
- [ ] Note complexity score and features detected
11+
- [ ] Check for existing tests in the same directory
12+
- [ ] **Identify ALL files in the directory** that need testing (not just index)
13+
14+
## Testing Strategy
15+
16+
### ⚠️ Incremental Workflow (CRITICAL for Multi-File)
17+
18+
- [ ] **NEVER generate all tests at once** - process one file at a time
19+
- [ ] Order files by complexity: utilities → hooks → simple → complex → integration
20+
- [ ] Create a todo list to track progress before starting
21+
- [ ] For EACH file: write → run test → verify pass → then next
22+
- [ ] **DO NOT proceed** to next file until current one passes
23+
24+
### Path-Level Coverage
25+
26+
- [ ] **Test ALL files** in the assigned directory/path
27+
- [ ] List all components, hooks, utilities that need coverage
28+
- [ ] Decide: single spec file (integration) or multiple spec files (unit)
29+
30+
### Complexity Assessment
31+
32+
- [ ] Run `pnpm analyze-component <path>` for complexity score
33+
- [ ] **Complexity > 50**: Consider refactoring before testing
34+
- [ ] **500+ lines**: Consider splitting before testing
35+
- [ ] **30-50 complexity**: Use multiple describe blocks, organized structure
36+
37+
### Integration vs Mocking
38+
39+
- [ ] **DO NOT mock base components** (`Loading`, `Button`, `Tooltip`, etc.)
40+
- [ ] Import real project components instead of mocking
41+
- [ ] Only mock: API calls, complex context providers, third-party libs with side effects
42+
- [ ] Prefer integration testing when using single spec file
43+
44+
## Required Test Sections
45+
46+
### All Components MUST Have
47+
48+
- [ ] **Rendering tests** - Component renders without crashing
49+
- [ ] **Props tests** - Required props, optional props, default values
50+
- [ ] **Edge cases** - null, undefined, empty values, boundaries
51+
52+
### Conditional Sections (Add When Feature Present)
53+
54+
| Feature | Add Tests For |
55+
|---------|---------------|
56+
| `useState` | Initial state, transitions, cleanup |
57+
| `useEffect` | Execution, dependencies, cleanup |
58+
| Event handlers | onClick, onChange, onSubmit, keyboard |
59+
| API calls | Loading, success, error states |
60+
| Routing | Navigation, params, query strings |
61+
| `useCallback`/`useMemo` | Referential equality |
62+
| Context | Provider values, consumer behavior |
63+
| Forms | Validation, submission, error display |
64+
65+
## Code Quality Checklist
66+
67+
### Structure
68+
69+
- [ ] Uses `describe` blocks to group related tests
70+
- [ ] Test names follow `should <behavior> when <condition>` pattern
71+
- [ ] AAA pattern (Arrange-Act-Assert) is clear
72+
- [ ] Comments explain complex test scenarios
73+
74+
### Mocks
75+
76+
- [ ] **DO NOT mock base components** (`@/app/components/base/*`)
77+
- [ ] `jest.clearAllMocks()` in `beforeEach` (not `afterEach`)
78+
- [ ] Shared mock state reset in `beforeEach`
79+
- [ ] i18n mock returns keys (not empty strings)
80+
- [ ] Router mocks match actual Next.js API
81+
- [ ] Mocks reflect actual component conditional behavior
82+
- [ ] Only mock: API services, complex context providers, third-party libs
83+
84+
### Queries
85+
86+
- [ ] Prefer semantic queries (`getByRole`, `getByLabelText`)
87+
- [ ] Use `queryBy*` for absence assertions
88+
- [ ] Use `findBy*` for async elements
89+
- [ ] `getByTestId` only as last resort
90+
91+
### Async
92+
93+
- [ ] All async tests use `async/await`
94+
- [ ] `waitFor` wraps async assertions
95+
- [ ] Fake timers properly setup/teardown
96+
- [ ] No floating promises
97+
98+
### TypeScript
99+
100+
- [ ] No `any` types without justification
101+
- [ ] Mock data uses actual types from source
102+
- [ ] Factory functions have proper return types
103+
104+
## Coverage Goals (Per File)
105+
106+
For the current file being tested:
107+
108+
- [ ] 100% function coverage
109+
- [ ] 100% statement coverage
110+
- [ ] >95% branch coverage
111+
- [ ] >95% line coverage
112+
113+
## Post-Generation (Per File)
114+
115+
**Run these checks after EACH test file, not just at the end:**
116+
117+
- [ ] Run `pnpm test -- path/to/file.spec.tsx` - **MUST PASS before next file**
118+
- [ ] Fix any failures immediately
119+
- [ ] Mark file as complete in todo list
120+
- [ ] Only then proceed to next file
121+
122+
### After All Files Complete
123+
124+
- [ ] Run full directory test: `pnpm test -- path/to/directory/`
125+
- [ ] Check coverage report: `pnpm test -- --coverage`
126+
- [ ] Run `pnpm lint:fix` on all test files
127+
- [ ] Run `pnpm type-check:tsgo`
128+
129+
## Common Issues to Watch
130+
131+
### False Positives
132+
133+
```typescript
134+
// ❌ Mock doesn't match actual behavior
135+
jest.mock('./Component', () => () => <div>Mocked</div>)
136+
137+
// ✅ Mock matches actual conditional logic
138+
jest.mock('./Component', () => ({ isOpen }: any) =>
139+
isOpen ? <div>Content</div> : null
140+
)
141+
```
142+
143+
### State Leakage
144+
145+
```typescript
146+
// ❌ Shared state not reset
147+
let mockState = false
148+
jest.mock('./useHook', () => () => mockState)
149+
150+
// ✅ Reset in beforeEach
151+
beforeEach(() => {
152+
mockState = false
153+
})
154+
```
155+
156+
### Async Race Conditions
157+
158+
```typescript
159+
// ❌ Not awaited
160+
it('loads data', () => {
161+
render(<Component />)
162+
expect(screen.getByText('Data')).toBeInTheDocument()
163+
})
164+
165+
// ✅ Properly awaited
166+
it('loads data', async () => {
167+
render(<Component />)
168+
await waitFor(() => {
169+
expect(screen.getByText('Data')).toBeInTheDocument()
170+
})
171+
})
172+
```
173+
174+
### Missing Edge Cases
175+
176+
Always test these scenarios:
177+
178+
- `null` / `undefined` inputs
179+
- Empty strings / arrays / objects
180+
- Boundary values (0, -1, MAX_INT)
181+
- Error states
182+
- Loading states
183+
- Disabled states
184+
185+
## Quick Commands
186+
187+
```bash
188+
# Run specific test
189+
pnpm test -- path/to/file.spec.tsx
190+
191+
# Run with coverage
192+
pnpm test -- --coverage path/to/file.spec.tsx
193+
194+
# Watch mode
195+
pnpm test -- --watch path/to/file.spec.tsx
196+
197+
# Update snapshots (use sparingly)
198+
pnpm test -- -u path/to/file.spec.tsx
199+
200+
# Analyze component
201+
pnpm analyze-component path/to/component.tsx
202+
203+
# Review existing test
204+
pnpm analyze-component path/to/component.tsx --review
205+
```

0 commit comments

Comments
 (0)