Dify Frontend Testing Skill
This skill enables Claude to generate high-quality, comprehensive frontend tests for the Dify project following established conventions and best practices.
β οΈ Authoritative Source: This skill is derived from web/docs/test.md. Use Vitest mock/timer APIs (vi.*).
When to Apply This Skill
Apply this skill when the user:
- Asks to write tests for a component, hook, or utility
- Asks to review existing tests for completeness
- Mentions Vitest, React Testing Library, RTL, or spec files
- Requests test coverage improvement
- Uses
pnpm analyze-component output as context
- Mentions testing, unit tests, or integration tests for frontend code
- Wants to understand testing patterns in the Dify codebase
Do NOT apply when:
- User is asking about backend/API tests (Python/pytest)
- User is asking about E2E tests (Playwright/Cypress)
- User is only asking conceptual questions without code context
Quick Reference
Tech Stack
| Tool |
Version |
Purpose |
| Vitest |
4.0.16 |
Test runner |
| React Testing Library |
16.0 |
Component testing |
| jsdom |
- |
Test environment |
| nock |
14.0 |
HTTP mocking |
| TypeScript |
5.x |
Type safety |
Key Commands
pnpm test
pnpm test:watch
pnpm test path/to/file.spec.tsx
pnpm test:coverage
pnpm analyze-component <path>
pnpm analyze-component <path> --review
File Naming
- Test files:
ComponentName.spec.tsx inside a same-level __tests__/ directory
- Placement rule: Component, hook, and utility tests must live in a sibling
__tests__/ folder at the same level as the source under test. For example, foo/index.tsx maps to foo/__tests__/index.spec.tsx, and foo/bar.ts maps to foo/__tests__/bar.spec.ts.
- Integration tests:
web/__tests__/ directory
Test Structure Template
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import Component from './index'
vi.mock('@/service/api')
vi.mock('next/navigation', () => ({
useRouter: () => ({ push: vi.fn() }),
usePathname: () => '/test',
}))
let mockSharedState = false
describe('ComponentName', () => {
beforeEach(() => {
vi.clearAllMocks()
mockSharedState = false
})
describe('Rendering', () => {
it('should render without crashing', () => {
const props = { title: 'Test' }
render(<Component {...props} />)
expect(screen.getByText('Test')).toBeInTheDocument()
})
})
describe('Props', () => {
it('should apply custom className', () => {
render(<Component className="custom" />)
expect(screen.getByRole('button')).toHaveClass('custom')
})
})
describe('User Interactions', () => {
it('should handle click events', () => {
const handleClick = vi.fn()
render(<Component onClick={handleClick} />)
fireEvent.click(screen.getByRole('button'))
expect(handleClick).toHaveBeenCalledTimes(1)
})
})
describe('Edge Cases', () => {
it('should handle null data', () => {
render(<Component data={null} />)
expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
it('should handle empty array', () => {
render(<Component items={[]} />)
expect(screen.getByText(/empty/i)).toBeInTheDocument()
})
})
})
Testing Workflow (CRITICAL)
β οΈ Incremental Approach Required
NEVER generate all test files at once. For complex components or multi-file directories:
- Analyze & Plan: List all files, order by complexity (simple β complex)
- Process ONE at a time: Write test β Run test β Fix if needed β Next
- Verify before proceeding: Do NOT continue to next file until current passes
For each file:
ββββββββββββββββββββββββββββββββββββββββββ
β 1. Write test β
β 2. Run: pnpm test <file>.spec.tsx β
β 3. PASS? β Mark complete, next file β
β FAIL? β Fix first, then continue β
ββββββββββββββββββββββββββββββββββββββββββ
Complexity-Based Order
Process in this order for multi-file testing:
- π’ Utility functions (simplest)
- π’ Custom hooks
- π‘ Simple components (presentational)
- π‘ Medium components (state, effects)
- π΄ Complex components (API, routing)
- π΄ Integration tests (index files - last)
When to Refactor First
- Complexity > 50: Break into smaller pieces before testing
- 500+ lines: Consider splitting before testing
- Many dependencies: Extract logic into hooks first
π See references/workflow.md for complete workflow details and todo list format.
Testing Strategy
Path-Level Testing (Directory Testing)
When assigned to test a directory/path, test ALL content within that path:
- Test all components, hooks, utilities in the directory (not just
index file)
- Use incremental approach: one file at a time, verify each before proceeding
- Goal: 100% coverage of ALL files in the directory
Integration Testing First
Prefer integration testing when writing tests for a directory:
- β
Import real project components directly (including base components and siblings)
- β
Only mock: API services (
@/service/*), next/navigation, complex context providers
- β DO NOT mock base components (
@/app/components/base/*)
- β DO NOT mock sibling/child components in the same directory
See Test Structure Template for correct import/mock patterns.
nuqs Query State Testing (Required for URL State Hooks)
When a component or hook uses useQueryState / useQueryStates:
- β
Use
NuqsTestingAdapter (prefer shared helpers in web/test/nuqs-testing.tsx)
- β
Assert URL synchronization via
onUrlUpdate (searchParams, options.history)
- β
For custom parsers (
createParser), keep parse and serialize bijective and add roun