mirror of
https://github.com/langgenius/dify.git
synced 2026-04-29 12:37:20 +08:00
docs: update frontend testing guidelines and add comprehensive testing documentation in TESTING.md
This commit is contained in:
parent
1bb42447cf
commit
009744b71a
226
.cursorrules
226
.cursorrules
@ -1,193 +1,69 @@
|
|||||||
# Cursor Rules for Dify Project - Test Generation
|
# Cursor Rules for Dify Project
|
||||||
|
|
||||||
## When Generating Tests
|
## Frontend Testing Guidelines
|
||||||
|
|
||||||
Follow these rules when asked to generate tests for React components:
|
> **📖 Complete Testing Documentation**: For detailed testing specifications and guidelines, see [`web/scripts/TESTING.md`](./web/scripts/TESTING.md)
|
||||||
|
|
||||||
### Tech Stack
|
When generating tests for React components:
|
||||||
- Next.js 15 + React 19 + TypeScript
|
|
||||||
- Jest 29.7 + React Testing Library 16.0
|
|
||||||
- Test environment: @happy-dom/jest-environment
|
|
||||||
- File naming: `ComponentName.spec.tsx` (same directory)
|
|
||||||
|
|
||||||
### Component Complexity Guidelines
|
### Key Requirements
|
||||||
|
|
||||||
#### 🔴 Very Complex Components (Complexity > 50)
|
1. **Tech Stack**: Next.js 15 + React 19 + TypeScript + Jest + React Testing Library
|
||||||
- **Split before testing**: Break component into smaller pieces
|
2. **File Naming**: `ComponentName.spec.tsx` (same directory as component)
|
||||||
- **Integration tests**: Test complex workflows end-to-end
|
3. **Code Style**:
|
||||||
- **Data-driven tests**: Use `test.each()` for multiple scenarios
|
- Use `fireEvent` (not `userEvent`)
|
||||||
- **Performance benchmarks**: Add performance tests for critical paths
|
- AAA pattern (Arrange → Act → Assert)
|
||||||
|
- Test names: `"should [behavior] when [condition]"`
|
||||||
|
- No `any` types
|
||||||
|
- Cleanup after each test: `afterEach(() => jest.clearAllMocks())`
|
||||||
|
|
||||||
#### ⚠️ Complex Components (Complexity 30-50)
|
### Required Tests (All Components)
|
||||||
- **Multiple describe blocks**: Group related test cases
|
|
||||||
- **Integration scenarios**: Test feature combinations
|
|
||||||
- **Organized structure**: Keep tests maintainable
|
|
||||||
|
|
||||||
#### 📏 Large Components (500+ lines)
|
- ✅ Renders without crashing
|
||||||
- **Consider refactoring**: Split into smaller components if possible
|
|
||||||
- **Section testing**: Test major sections separately
|
|
||||||
- **Helper functions**: Reduce test complexity with utilities
|
|
||||||
|
|
||||||
### Test Scenarios
|
|
||||||
|
|
||||||
Apply based on component features:
|
|
||||||
|
|
||||||
#### 1. Rendering Tests (REQUIRED for all)
|
|
||||||
```typescript
|
|
||||||
describe('Rendering', () => {
|
|
||||||
it('should render without crashing', () => {
|
|
||||||
render(<Component />)
|
|
||||||
expect(screen.getByRole('...')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. Props Testing (REQUIRED for all)
|
|
||||||
- Test each prop variation
|
|
||||||
- Test required vs optional props
|
|
||||||
- Test default values
|
|
||||||
- Test prop type validation
|
|
||||||
|
|
||||||
#### 3. State Management
|
|
||||||
|
|
||||||
**State Only (useState):**
|
|
||||||
- Test initial state values
|
|
||||||
- Test all state transitions
|
|
||||||
- Test state reset/cleanup scenarios
|
|
||||||
|
|
||||||
**Effects Only (useEffect):**
|
|
||||||
- Test effect execution conditions
|
|
||||||
- Verify dependencies array correctness
|
|
||||||
- Test cleanup on unmount
|
|
||||||
|
|
||||||
**State + Effects Combined:**
|
|
||||||
- Test state initialization and updates
|
|
||||||
- Test useEffect dependencies array
|
|
||||||
- Test cleanup functions (return from useEffect)
|
|
||||||
- Use `waitFor()` for async state changes
|
|
||||||
|
|
||||||
#### 4. Performance Optimization
|
|
||||||
|
|
||||||
**useCallback:**
|
|
||||||
- Verify callbacks maintain referential equality
|
|
||||||
- Test callback dependencies
|
|
||||||
- Ensure re-renders don't recreate functions unnecessarily
|
|
||||||
|
|
||||||
**useMemo:**
|
|
||||||
- Test memoization dependencies
|
|
||||||
- Ensure expensive computations are cached
|
|
||||||
- Verify memo recomputation conditions
|
|
||||||
|
|
||||||
#### 5. Event Handlers
|
|
||||||
- Test all onClick, onChange, onSubmit handlers
|
|
||||||
- Test keyboard events (Enter, Escape, Tab, etc.)
|
|
||||||
- Verify event.preventDefault() calls if needed
|
|
||||||
- Test event bubbling/propagation
|
|
||||||
- Use `fireEvent` (not userEvent)
|
|
||||||
|
|
||||||
#### 6. API Calls & Async Operations
|
|
||||||
- Mock all API calls using `jest.mock`
|
|
||||||
- Test retry logic if applicable
|
|
||||||
- Verify error handling and user feedback
|
|
||||||
- Use `waitFor()` for async operations
|
|
||||||
|
|
||||||
#### 7. Next.js Routing
|
|
||||||
- Mock useRouter, usePathname, useSearchParams
|
|
||||||
- Test navigation behavior and parameters
|
|
||||||
- Test query string handling
|
|
||||||
- Verify route guards/redirects if any
|
|
||||||
- Test URL parameter updates
|
|
||||||
|
|
||||||
#### 8. Edge Cases (REQUIRED for all)
|
|
||||||
- Test null/undefined/empty values
|
|
||||||
- Test boundary conditions
|
|
||||||
- Test error states
|
|
||||||
- Test loading states
|
|
||||||
- Test unexpected inputs
|
|
||||||
|
|
||||||
#### 9. Accessibility (Optional)
|
|
||||||
- Test keyboard navigation
|
|
||||||
- Verify ARIA attributes
|
|
||||||
- Test focus management
|
|
||||||
- Ensure screen reader compatibility
|
|
||||||
|
|
||||||
#### 10. Snapshots (use sparingly)
|
|
||||||
- Only for stable UI (icons, badges, static layouts)
|
|
||||||
- Snapshot small sections only
|
|
||||||
- Prefer explicit assertions over snapshots
|
|
||||||
- Update snapshots intentionally, not automatically
|
|
||||||
|
|
||||||
**Note**: Dify is a desktop app. NO responsive/mobile testing.
|
|
||||||
|
|
||||||
### Code Style
|
|
||||||
|
|
||||||
- Use `fireEvent` not `userEvent`
|
|
||||||
- AAA pattern: Arrange → Act → Assert
|
|
||||||
- Descriptive test names: "should [behavior] when [condition]"
|
|
||||||
- TypeScript: No `any` types
|
|
||||||
- Cleanup: `afterEach(() => jest.clearAllMocks())`
|
|
||||||
|
|
||||||
### Dify-Specific Components
|
|
||||||
|
|
||||||
#### General
|
|
||||||
1. **i18n**: Always return key: `t: (key) => key`
|
|
||||||
2. **Toast**: Mock `@/app/components/base/toast`
|
|
||||||
3. **Forms**: Test validation thoroughly
|
|
||||||
|
|
||||||
#### Workflow Components (`workflow/`)
|
|
||||||
- **Node configuration**: Test all node configuration options
|
|
||||||
- **Data validation**: Verify input/output validation rules
|
|
||||||
- **Variable passing**: Test data flow between nodes
|
|
||||||
- **Edge connections**: Test graph structure and connections
|
|
||||||
- **Error handling**: Verify handling of invalid configurations
|
|
||||||
- **Integration**: Test complete workflow execution paths
|
|
||||||
|
|
||||||
#### Dataset Components (`dataset/`)
|
|
||||||
- **File upload**: Test file upload and validation
|
|
||||||
- **File types**: Verify supported format handling
|
|
||||||
- **Pagination**: Test data loading and pagination
|
|
||||||
- **Search & filtering**: Test query functionality
|
|
||||||
- **Data format handling**: Test various data formats
|
|
||||||
- **Error states**: Test upload failures and invalid data
|
|
||||||
|
|
||||||
#### Configuration Components (`app/configuration`, `config/`)
|
|
||||||
- **Form validation**: Test all validation rules thoroughly
|
|
||||||
- **Save/reset functionality**: Test data persistence
|
|
||||||
- **Required vs optional fields**: Verify field validation
|
|
||||||
- **Configuration persistence**: Test state preservation
|
|
||||||
- **Error feedback**: Verify user error messages
|
|
||||||
- **Default values**: Test initial configuration state
|
|
||||||
|
|
||||||
### Test Strategy Quick Reference
|
|
||||||
|
|
||||||
**Always Test:**
|
|
||||||
- ✅ Rendering without crashing
|
|
||||||
- ✅ Props (required, optional, defaults)
|
- ✅ Props (required, optional, defaults)
|
||||||
- ✅ Edge cases (null, undefined, empty)
|
- ✅ Edge cases (null, undefined, empty values)
|
||||||
|
|
||||||
|
### Conditional Tests (When Present in Component)
|
||||||
|
|
||||||
**Test When Present:**
|
|
||||||
- 🔄 **useState** → State initialization, transitions, cleanup
|
- 🔄 **useState** → State initialization, transitions, cleanup
|
||||||
- ⚡ **useEffect** → Execution, dependencies, cleanup
|
- ⚡ **useEffect** → Execution, dependencies, cleanup
|
||||||
- 🎯 **Event handlers** → All onClick, onChange, onSubmit, keyboard events
|
- 🎯 **Event Handlers** → onClick, onChange, onSubmit, keyboard events
|
||||||
- 🌐 **API calls** → Loading, success, error states
|
- 🌐 **API Calls** → Loading, success, error states
|
||||||
- 🔀 **Routing** → Navigation, params, query strings
|
- 🔀 **Next.js Routing** → Navigation, params, query strings
|
||||||
- 🚀 **useCallback/useMemo** → Referential equality, dependencies
|
- 🚀 **useCallback/useMemo** → Referential equality, dependencies
|
||||||
- ⚙️ **Workflow** → Node config, data flow, validation
|
- ⚙️ **Workflow Components** → Node config, data flow, validation
|
||||||
- 📚 **Dataset** → Upload, pagination, search
|
- 📚 **Dataset Components** → Upload, pagination, search
|
||||||
- 🎛️ **Configuration** → Form validation, persistence
|
- 🎛️ **Configuration Components** → Form validation, persistence
|
||||||
|
|
||||||
**Complex Components (30+):**
|
### Component Complexity Strategy
|
||||||
- Group tests in multiple `describe` blocks
|
|
||||||
- Test integration scenarios
|
|
||||||
- Consider splitting component before testing
|
|
||||||
|
|
||||||
### Coverage Target
|
- **Complexity > 50**: Refactor before testing, use integration tests and `test.each()`
|
||||||
|
- **Complexity 30-50**: Use multiple `describe` blocks to group tests
|
||||||
|
- **500+ lines**: Consider splitting component
|
||||||
|
|
||||||
|
### Coverage Goals
|
||||||
|
|
||||||
Aim for 100% coverage:
|
Aim for 100% coverage:
|
||||||
- Line: >95%
|
- Line coverage: >95%
|
||||||
- Branch: >95%
|
- Branch coverage: >95%
|
||||||
- Function: 100%
|
- Function coverage: 100%
|
||||||
- Statement: 100%
|
- Statement coverage: 100%
|
||||||
|
|
||||||
Generate comprehensive tests covering ALL code paths and scenarios.
|
### Dify-Specific Mocks
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
|
||||||
|
// Toast
|
||||||
|
jest.mock('@/app/components/base/toast')
|
||||||
|
|
||||||
|
// Next.js Router
|
||||||
|
jest.mock('next/navigation', () => ({
|
||||||
|
useRouter: jest.fn(),
|
||||||
|
usePathname: jest.fn(),
|
||||||
|
useSearchParams: jest.fn(),
|
||||||
|
}))
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Important**: The above is a quick reference only. When generating tests, strictly follow the complete specifications in [`web/scripts/TESTING.md`](./web/scripts/TESTING.md), including detailed examples, best practices, and FAQs.
|
||||||
|
|||||||
@ -77,6 +77,8 @@ How we prioritize:
|
|||||||
|
|
||||||
For setting up the frontend service, please refer to our comprehensive [guide](https://github.com/langgenius/dify/blob/main/web/README.md) in the `web/README.md` file. This document provides detailed instructions to help you set up the frontend environment properly.
|
For setting up the frontend service, please refer to our comprehensive [guide](https://github.com/langgenius/dify/blob/main/web/README.md) in the `web/README.md` file. This document provides detailed instructions to help you set up the frontend environment properly.
|
||||||
|
|
||||||
|
**Testing**: All React components must have comprehensive test coverage. See [web/scripts/TESTING.md](https://github.com/langgenius/dify/blob/main/web/scripts/TESTING.md) for detailed testing guidelines.
|
||||||
|
|
||||||
#### Backend
|
#### Backend
|
||||||
|
|
||||||
For setting up the backend service, kindly refer to our detailed [instructions](https://github.com/langgenius/dify/blob/main/api/README.md) in the `api/README.md` file. This document contains step-by-step guidance to help you get the backend up and running smoothly.
|
For setting up the backend service, kindly refer to our detailed [instructions](https://github.com/langgenius/dify/blob/main/api/README.md) in the `api/README.md` file. This document contains step-by-step guidance to help you get the backend up and running smoothly.
|
||||||
|
|||||||
@ -93,20 +93,26 @@ If your IDE is VSCode, rename `web/.vscode/settings.example.json` to `web/.vscod
|
|||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
We start to use [Jest](https://jestjs.io/) and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) for Unit Testing.
|
We use [Jest](https://jestjs.io/) and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) for Unit Testing.
|
||||||
|
|
||||||
You can create a test file with a suffix of `.spec` beside the file that to be tested. For example, if you want to test a file named `util.ts`. The test file name should be `util.spec.ts`.
|
**📖 Complete Testing Guide**: See [scripts/TESTING.md](./scripts/TESTING.md) for detailed testing specifications, best practices, and examples.
|
||||||
|
|
||||||
Run test:
|
### Example Code
|
||||||
|
|
||||||
|
If you are not familiar with writing tests, refer to:
|
||||||
|
|
||||||
|
- [classnames.spec.ts](./utils/classnames.spec.ts) - Utility function test example
|
||||||
|
- [index.spec.tsx](./app/components/base/button/index.spec.tsx) - Component test example
|
||||||
|
|
||||||
|
### Analyze Component Complexity
|
||||||
|
|
||||||
|
Before writing tests, use the script to analyze component complexity:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm run test
|
pnpm analyze-component app/components/your-component/index.tsx
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are not familiar with writing tests, here is some code to refer to:
|
This will help you determine the testing strategy. See [scripts/TESTING.md](./scripts/TESTING.md) for details.
|
||||||
|
|
||||||
- [classnames.spec.ts](./utils/classnames.spec.ts)
|
|
||||||
- [index.spec.tsx](./app/components/base/button/index.spec.tsx)
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ Frontend development utility scripts.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Generate Tests (Using Cursor AI)
|
## 🚀 Generate Tests (Using AI Assistants)
|
||||||
|
|
||||||
### Quick Start
|
### Quick Start
|
||||||
|
|
||||||
@ -18,11 +18,14 @@ Frontend development utility scripts.
|
|||||||
# 1. Analyze component
|
# 1. Analyze component
|
||||||
pnpm test:gen app/components/base/button/index.tsx
|
pnpm test:gen app/components/base/button/index.tsx
|
||||||
|
|
||||||
# Output: Component analysis + Cursor prompt (auto-copied)
|
# Output: Component analysis + AI prompt (auto-copied to clipboard)
|
||||||
|
|
||||||
# 2. In Cursor: Cmd+L → Cmd+V → Enter → Apply
|
# 2. Paste in your AI assistant:
|
||||||
|
# - Cursor: Cmd+L (Chat) or Cmd+I (Composer) → Cmd+V → Enter
|
||||||
|
# - GitHub Copilot Chat: Cmd+I → Cmd+V → Enter
|
||||||
|
# - Claude/ChatGPT: Paste the prompt directly
|
||||||
|
|
||||||
# 3. Verify
|
# 3. Apply the generated test and verify
|
||||||
pnpm test app/components/base/button/index.spec.tsx
|
pnpm test app/components/base/button/index.spec.tsx
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -37,19 +40,19 @@ pnpm test app/components/base/button/index.spec.tsx
|
|||||||
Script analyzes and scores components:
|
Script analyzes and scores components:
|
||||||
|
|
||||||
- **0-10**: 🟢 Simple (5-10 min to test)
|
- **0-10**: 🟢 Simple (5-10 min to test)
|
||||||
- **11-30Menu 🟡 Medium (15-30 min to test)
|
- **11-30**: 🟡 Medium (15-30 min to test)
|
||||||
- **31-50Menu 🟠 Complex (30-60 min to test)
|
- **31-50**: 🟠 Complex (30-60 min to test)
|
||||||
- **51+**: 🔴 Very Complex (60+ min, consider refactoring)
|
- **51+**: 🔴 Very Complex (60+ min, consider refactoring)
|
||||||
|
|
||||||
### Test Scenarios (11 types)
|
### Test Scenarios
|
||||||
|
|
||||||
Defined in `.cursorrules`:
|
Defined in `TESTING.md`:
|
||||||
|
|
||||||
**Must test**: Rendering, Props, Edge Cases
|
**Must test**: Rendering, Props, Edge Cases
|
||||||
**CommonMenuInteractions, Accessibility, i18n, Async
|
**Conditional**: State, Effects, Events, API calls, Routing
|
||||||
**OptionalMenuState, Security, Performance, Snapshots
|
**Optional**: Accessibility, Performance, Snapshots
|
||||||
|
|
||||||
Cursor AI auto-selects scenarios based on component features.
|
AI assistant auto-selects scenarios based on component features.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -58,10 +61,12 @@ Cursor AI auto-selects scenarios based on component features.
|
|||||||
```bash
|
```bash
|
||||||
# New component
|
# New component
|
||||||
pnpm test:gen app/components/new-feature/index.tsx
|
pnpm test:gen app/components/new-feature/index.tsx
|
||||||
# → Cursor → Apply → Done
|
# → Paste in AI assistant → Apply → Done
|
||||||
|
|
||||||
# Or even simpler in Cursor
|
# Quick shortcuts:
|
||||||
# Cmd+I → "Generate test" → Apply
|
# Cursor users: Cmd+I → "Generate test for [file]" → Apply
|
||||||
|
# Copilot users: Cmd+I → Paste prompt → Accept
|
||||||
|
# Others: Copy prompt → Paste in your AI tool
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -80,10 +85,24 @@ pnpm type-check # Type check
|
|||||||
|
|
||||||
## 🎯 Customize
|
## 🎯 Customize
|
||||||
|
|
||||||
Edit `.cursorrules` to modify test standards for your team.
|
Edit testing standards for your team:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Complete testing guide (for all team members)
|
||||||
|
code web/scripts/TESTING.md
|
||||||
|
|
||||||
|
# Quick reference for Cursor users
|
||||||
code .cursorrules
|
code .cursorrules
|
||||||
git commit -m "docs: update test rules"
|
|
||||||
|
# Commit your changes
|
||||||
|
git commit -m "docs: update test standards"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Resources
|
||||||
|
|
||||||
|
- **Testing Guide**: [TESTING.md](./TESTING.md) - Complete testing specifications
|
||||||
|
- **Quick Reference**: [.cursorrules](../../.cursorrules) - For Cursor users
|
||||||
|
- **Examples**: [classnames.spec.ts](../utils/classnames.spec.ts), [button/index.spec.tsx](../app/components/base/button/index.spec.tsx)
|
||||||
|
|
||||||
|
|||||||
459
web/scripts/TESTING.md
Normal file
459
web/scripts/TESTING.md
Normal file
@ -0,0 +1,459 @@
|
|||||||
|
# Frontend Testing Guide
|
||||||
|
|
||||||
|
This document is the complete testing specification for the Dify frontend project.
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
- **Framework**: Next.js 15 + React 19 + TypeScript
|
||||||
|
- **Testing Tools**: Jest 29.7 + React Testing Library 16.0
|
||||||
|
- **Test Environment**: @happy-dom/jest-environment
|
||||||
|
- **File Naming**: `ComponentName.spec.tsx` (same directory as component)
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run all tests
|
||||||
|
pnpm test
|
||||||
|
|
||||||
|
# Watch mode
|
||||||
|
pnpm test -- --watch
|
||||||
|
|
||||||
|
# Generate coverage report
|
||||||
|
pnpm test -- --coverage
|
||||||
|
|
||||||
|
# Run specific file
|
||||||
|
pnpm test -- path/to/file.spec.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Component Complexity Guidelines
|
||||||
|
|
||||||
|
Use `pnpm analyze-component <path>` to analyze component complexity and adopt different testing strategies based on the results.
|
||||||
|
|
||||||
|
### 🔴 Very Complex Components (Complexity > 50)
|
||||||
|
|
||||||
|
- **Refactor first**: Break component into smaller pieces
|
||||||
|
- **Integration tests**: Test complex workflows end-to-end
|
||||||
|
- **Data-driven tests**: Use `test.each()` for multiple scenarios
|
||||||
|
- **Performance benchmarks**: Add performance tests for critical paths
|
||||||
|
|
||||||
|
### ⚠️ Complex Components (Complexity 30-50)
|
||||||
|
|
||||||
|
- **Multiple describe blocks**: Group related test cases
|
||||||
|
- **Integration scenarios**: Test feature combinations
|
||||||
|
- **Organized structure**: Keep tests maintainable
|
||||||
|
|
||||||
|
### 📏 Large Components (500+ lines)
|
||||||
|
|
||||||
|
- **Consider refactoring**: Split into smaller components if possible
|
||||||
|
- **Section testing**: Test major sections separately
|
||||||
|
- **Helper functions**: Reduce test complexity with utilities
|
||||||
|
|
||||||
|
## Test Scenarios
|
||||||
|
|
||||||
|
Apply the following test scenarios based on component features:
|
||||||
|
|
||||||
|
### 1. Rendering Tests (REQUIRED - All Components)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
describe('Rendering', () => {
|
||||||
|
it('should render without crashing', () => {
|
||||||
|
render(<Component />)
|
||||||
|
expect(screen.getByRole('...')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Points**:
|
||||||
|
- Verify component renders properly
|
||||||
|
- Check key elements exist
|
||||||
|
- Use semantic queries (getByRole, getByLabelText)
|
||||||
|
|
||||||
|
### 2. Props Testing (REQUIRED - All Components)
|
||||||
|
|
||||||
|
**Must Test**:
|
||||||
|
- ✅ Different values for each prop
|
||||||
|
- ✅ Required vs optional props
|
||||||
|
- ✅ Default values
|
||||||
|
- ✅ Props type validation
|
||||||
|
|
||||||
|
### 3. State Management
|
||||||
|
|
||||||
|
#### useState
|
||||||
|
|
||||||
|
When testing state-related components:
|
||||||
|
- ✅ Test initial state values
|
||||||
|
- ✅ Test all state transitions
|
||||||
|
- ✅ Test state reset/cleanup scenarios
|
||||||
|
|
||||||
|
#### useEffect
|
||||||
|
|
||||||
|
When testing side effects:
|
||||||
|
- ✅ Test effect execution conditions
|
||||||
|
- ✅ Verify dependencies array correctness
|
||||||
|
- ✅ Test cleanup function on unmount
|
||||||
|
|
||||||
|
#### useState + useEffect Combined
|
||||||
|
|
||||||
|
- ✅ Test state initialization and updates
|
||||||
|
- ✅ Test useEffect dependencies array
|
||||||
|
- ✅ Test cleanup functions (useEffect return value)
|
||||||
|
- ✅ Use `waitFor()` for async state changes
|
||||||
|
|
||||||
|
### 4. Performance Optimization
|
||||||
|
|
||||||
|
#### useCallback
|
||||||
|
|
||||||
|
- ✅ Verify callbacks maintain referential equality
|
||||||
|
- ✅ Test callback dependencies
|
||||||
|
- ✅ Ensure re-renders don't recreate functions unnecessarily
|
||||||
|
|
||||||
|
#### useMemo
|
||||||
|
|
||||||
|
- ✅ Test memoization dependencies
|
||||||
|
- ✅ Ensure expensive computations are cached
|
||||||
|
- ✅ Verify memo recomputation conditions
|
||||||
|
|
||||||
|
### 5. Event Handlers
|
||||||
|
|
||||||
|
**Must Test**:
|
||||||
|
- ✅ All onClick, onChange, onSubmit handlers
|
||||||
|
- ✅ Keyboard events (Enter, Escape, Tab, etc.)
|
||||||
|
- ✅ Verify event.preventDefault() calls (if needed)
|
||||||
|
- ✅ Test event bubbling/propagation
|
||||||
|
|
||||||
|
**Note**: Use `fireEvent` (not `userEvent`)
|
||||||
|
|
||||||
|
### 6. API Calls and Async Operations
|
||||||
|
|
||||||
|
**Must Test**:
|
||||||
|
- ✅ Mock all API calls using `jest.mock`
|
||||||
|
- ✅ Test retry logic (if applicable)
|
||||||
|
- ✅ Verify error handling and user feedback
|
||||||
|
- ✅ Use `waitFor()` for async operations
|
||||||
|
|
||||||
|
### 7. Next.js Routing
|
||||||
|
|
||||||
|
**Must Test**:
|
||||||
|
- ✅ Mock useRouter, usePathname, useSearchParams
|
||||||
|
- ✅ Test navigation behavior and parameters
|
||||||
|
- ✅ Test query string handling
|
||||||
|
- ✅ Verify route guards/redirects (if any)
|
||||||
|
- ✅ Test URL parameter updates
|
||||||
|
|
||||||
|
### 8. Edge Cases (REQUIRED - All Components)
|
||||||
|
|
||||||
|
**Must Test**:
|
||||||
|
- ✅ null/undefined/empty values
|
||||||
|
- ✅ Boundary conditions
|
||||||
|
- ✅ Error states
|
||||||
|
- ✅ Loading states
|
||||||
|
- ✅ Unexpected inputs
|
||||||
|
|
||||||
|
### 9. Accessibility Testing (Optional)
|
||||||
|
|
||||||
|
- Test keyboard navigation
|
||||||
|
- Verify ARIA attributes
|
||||||
|
- Test focus management
|
||||||
|
- Ensure screen reader compatibility
|
||||||
|
|
||||||
|
### 10. Snapshot Testing (Use Sparingly)
|
||||||
|
|
||||||
|
**Only Use For**:
|
||||||
|
- ✅ Stable UI (icons, badges, static layouts)
|
||||||
|
- ✅ Snapshot small sections only
|
||||||
|
- ✅ Prefer explicit assertions over snapshots
|
||||||
|
- ✅ Update snapshots intentionally, not automatically
|
||||||
|
|
||||||
|
**Note**: Dify is a desktop application. **No need for** responsive/mobile testing.
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
### Basic Guidelines
|
||||||
|
|
||||||
|
- ✅ Use `fireEvent` instead of `userEvent`
|
||||||
|
- ✅ AAA pattern: Arrange (setup) → Act (execute) → Assert (verify)
|
||||||
|
- ✅ Descriptive test names: `"should [behavior] when [condition]"`
|
||||||
|
- ✅ TypeScript: No `any` types
|
||||||
|
- ✅ Cleanup: `afterEach(() => jest.clearAllMocks())`
|
||||||
|
|
||||||
|
### Example Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
||||||
|
import Component from './index'
|
||||||
|
|
||||||
|
// Mock dependencies
|
||||||
|
jest.mock('@/service/api')
|
||||||
|
|
||||||
|
describe('ComponentName', () => {
|
||||||
|
// Cleanup after each test
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Rendering', () => {
|
||||||
|
it('should render without crashing', () => {
|
||||||
|
// Arrange
|
||||||
|
const props = { title: 'Test' }
|
||||||
|
|
||||||
|
// Act
|
||||||
|
render(<Component {...props} />)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(screen.getByText('Test')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('User Interactions', () => {
|
||||||
|
it('should handle click events', () => {
|
||||||
|
const handleClick = jest.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()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dify-Specific Components
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
1. **i18n**: Always return key
|
||||||
|
```typescript
|
||||||
|
jest.mock('react-i18next', () => ({
|
||||||
|
useTranslation: () => ({
|
||||||
|
t: (key: string) => key,
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Toast**: Mock toast component
|
||||||
|
```typescript
|
||||||
|
jest.mock('@/app/components/base/toast', () => ({
|
||||||
|
notify: jest.fn(),
|
||||||
|
}))
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Forms**: Test validation logic thoroughly
|
||||||
|
|
||||||
|
### Workflow Components (`workflow/`)
|
||||||
|
|
||||||
|
**Must Test**:
|
||||||
|
- ⚙️ **Node configuration**: Test all node configuration options
|
||||||
|
- ✔️ **Data validation**: Verify input/output validation rules
|
||||||
|
- 🔄 **Variable passing**: Test data flow between nodes
|
||||||
|
- 🔗 **Edge connections**: Test graph structure and connections
|
||||||
|
- ❌ **Error handling**: Verify invalid configuration handling
|
||||||
|
- 🧪 **Integration**: Test complete workflow execution paths
|
||||||
|
|
||||||
|
### Dataset Components (`dataset/`)
|
||||||
|
|
||||||
|
**Must Test**:
|
||||||
|
- 📤 **File upload**: Test file upload and validation
|
||||||
|
- 📄 **File types**: Verify supported format handling
|
||||||
|
- 📃 **Pagination**: Test data loading and pagination
|
||||||
|
- 🔍 **Search & filtering**: Test query functionality
|
||||||
|
- 📊 **Data format handling**: Test various data formats
|
||||||
|
- ⚠️ **Error states**: Test upload failures and invalid data
|
||||||
|
|
||||||
|
### Configuration Components (`app/configuration`, `config/`)
|
||||||
|
|
||||||
|
**Must Test**:
|
||||||
|
- ✅ **Form validation**: Test all validation rules thoroughly
|
||||||
|
- 💾 **Save/reset functionality**: Test data persistence
|
||||||
|
- 🔒 **Required vs optional fields**: Verify field validation
|
||||||
|
- 📌 **Configuration persistence**: Test state preservation
|
||||||
|
- 💬 **Error feedback**: Verify user error messages
|
||||||
|
- 🎯 **Default values**: Test initial configuration state
|
||||||
|
|
||||||
|
## Testing Strategy Quick Reference
|
||||||
|
|
||||||
|
### Required (All Components)
|
||||||
|
|
||||||
|
- ✅ Renders without crashing
|
||||||
|
- ✅ Props (required, optional, defaults)
|
||||||
|
- ✅ Edge cases (null, undefined, empty values)
|
||||||
|
|
||||||
|
### Conditional (When Present in Component)
|
||||||
|
|
||||||
|
- 🔄 **useState** → State initialization, transitions, cleanup
|
||||||
|
- ⚡ **useEffect** → Execution, dependencies, cleanup
|
||||||
|
- 🎯 **Event Handlers** → All onClick, onChange, onSubmit, keyboard events
|
||||||
|
- 🌐 **API Calls** → Loading, success, error states
|
||||||
|
- 🔀 **Routing** → Navigation, params, query strings
|
||||||
|
- 🚀 **useCallback/useMemo** → Referential equality, dependencies
|
||||||
|
- ⚙️ **Workflow** → Node config, data flow, validation
|
||||||
|
- 📚 **Dataset** → Upload, pagination, search
|
||||||
|
- 🎛️ **Configuration** → Form validation, persistence
|
||||||
|
|
||||||
|
### Complex Components (Complexity 30+)
|
||||||
|
|
||||||
|
- Group tests in multiple `describe` blocks
|
||||||
|
- Test integration scenarios
|
||||||
|
- Consider splitting component before testing
|
||||||
|
|
||||||
|
## Coverage Goals
|
||||||
|
|
||||||
|
Aim for 100% coverage:
|
||||||
|
- **Line coverage**: >95%
|
||||||
|
- **Branch coverage**: >95%
|
||||||
|
- **Function coverage**: 100%
|
||||||
|
- **Statement coverage**: 100%
|
||||||
|
|
||||||
|
Generate comprehensive tests covering **all** code paths and scenarios.
|
||||||
|
|
||||||
|
## Common Mock Patterns
|
||||||
|
|
||||||
|
### Mock Hooks
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Mock useState
|
||||||
|
const mockSetState = jest.fn()
|
||||||
|
jest.spyOn(React, 'useState').mockImplementation((init) => [init, mockSetState])
|
||||||
|
|
||||||
|
// Mock useContext
|
||||||
|
jest.spyOn(React, 'useContext').mockReturnValue({ user: mockUser })
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mock Modules
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Mock entire module
|
||||||
|
jest.mock('@/utils/api', () => ({
|
||||||
|
get: jest.fn(),
|
||||||
|
post: jest.fn(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Mock partial module
|
||||||
|
jest.mock('@/utils/helpers', () => ({
|
||||||
|
...jest.requireActual('@/utils/helpers'),
|
||||||
|
specificFunction: jest.fn(),
|
||||||
|
}))
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mock Next.js
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// useRouter
|
||||||
|
jest.mock('next/navigation', () => ({
|
||||||
|
useRouter: () => ({
|
||||||
|
push: jest.fn(),
|
||||||
|
replace: jest.fn(),
|
||||||
|
prefetch: jest.fn(),
|
||||||
|
}),
|
||||||
|
usePathname: () => '/current-path',
|
||||||
|
useSearchParams: () => new URLSearchParams(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
// next/image
|
||||||
|
jest.mock('next/image', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: (props: any) => <img {...props} />,
|
||||||
|
}))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging Tips
|
||||||
|
|
||||||
|
### View Rendered DOM
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { screen } from '@testing-library/react'
|
||||||
|
|
||||||
|
// Print entire DOM
|
||||||
|
screen.debug()
|
||||||
|
|
||||||
|
// Print specific element
|
||||||
|
screen.debug(screen.getByRole('button'))
|
||||||
|
```
|
||||||
|
|
||||||
|
### Finding Elements
|
||||||
|
|
||||||
|
Priority order (recommended top to bottom):
|
||||||
|
1. `getByRole` - Most recommended, follows accessibility standards
|
||||||
|
2. `getByLabelText` - Form fields
|
||||||
|
3. `getByPlaceholderText` - Only when no label
|
||||||
|
4. `getByText` - Non-interactive elements
|
||||||
|
5. `getByDisplayValue` - Current form value
|
||||||
|
6. `getByAltText` - Images
|
||||||
|
7. `getByTitle` - Last choice
|
||||||
|
8. `getByTestId` - Only as last resort
|
||||||
|
|
||||||
|
### Async Debugging
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Wait for element to appear
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText('Loaded')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Wait for element to disappear
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryByText('Loading')).not.toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Find async element
|
||||||
|
const element = await screen.findByText('Async Content')
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reference Examples
|
||||||
|
|
||||||
|
Test examples in the project:
|
||||||
|
- [classnames.spec.ts](../utils/classnames.spec.ts) - Utility function tests
|
||||||
|
- [index.spec.tsx](../app/components/base/button/index.spec.tsx) - Component tests
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [Jest Documentation](https://jestjs.io/docs/getting-started)
|
||||||
|
- [React Testing Library Documentation](https://testing-library.com/docs/react-testing-library/intro/)
|
||||||
|
- [Testing Library Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
|
||||||
|
- [Jest Mock Functions](https://jestjs.io/docs/mock-functions)
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### Q: When to use `getBy` vs `queryBy` vs `findBy`?
|
||||||
|
|
||||||
|
- `getBy*`: Expect element to exist, throws error if not found
|
||||||
|
- `queryBy*`: Element may not exist, returns null if not found
|
||||||
|
- `findBy*`: Async query, returns Promise
|
||||||
|
|
||||||
|
### Q: How to test conditional rendering?
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
it('should conditionally render content', () => {
|
||||||
|
const { rerender } = render(<Component show={false} />)
|
||||||
|
expect(screen.queryByText('Content')).not.toBeInTheDocument()
|
||||||
|
|
||||||
|
rerender(<Component show={true} />)
|
||||||
|
expect(screen.getByText('Content')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q: How to test custom hooks?
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { renderHook, act } from '@testing-library/react'
|
||||||
|
|
||||||
|
it('should update counter', () => {
|
||||||
|
const { result } = renderHook(() => useCounter())
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
result.current.increment()
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.current.count).toBe(1)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Remember**: Writing tests is not just about coverage, but ensuring code quality and maintainability. Good tests should be clear, concise, and meaningful.
|
||||||
@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
/**
|
/**
|
||||||
* Component Analyzer for Cursor AI
|
* Component Analyzer for Test Generation
|
||||||
*
|
*
|
||||||
* Analyzes a component and generates a structured prompt for Cursor AI.
|
* Analyzes a component and generates a structured prompt for AI assistants.
|
||||||
* Copy the output and paste into Cursor Chat (Cmd+L) or Composer (Cmd+I).
|
* Works with Cursor, GitHub Copilot, and other AI coding tools.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* node scripts/analyze-component.js <component-path>
|
* node scripts/analyze-component.js <component-path>
|
||||||
@ -11,6 +11,8 @@
|
|||||||
* Examples:
|
* Examples:
|
||||||
* node scripts/analyze-component.js app/components/base/button/index.tsx
|
* node scripts/analyze-component.js app/components/base/button/index.tsx
|
||||||
* node scripts/analyze-component.js app/components/workflow/nodes/llm/panel.tsx
|
* node scripts/analyze-component.js app/components/workflow/nodes/llm/panel.tsx
|
||||||
|
*
|
||||||
|
* For complete testing guidelines, see: web/scripts/TESTING.md
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const fs = require('node:fs')
|
const fs = require('node:fs')
|
||||||
@ -272,16 +274,16 @@ class ComponentAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Prompt Builder for Cursor
|
// Prompt Builder for AI Assistants
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
class CursorPromptBuilder {
|
class TestPromptBuilder {
|
||||||
build(analysis, _sourceCode) {
|
build(analysis, _sourceCode) {
|
||||||
const testPath = analysis.path.replace(/\.tsx?$/, '.spec.tsx')
|
const testPath = analysis.path.replace(/\.tsx?$/, '.spec.tsx')
|
||||||
|
|
||||||
return `
|
return `
|
||||||
╔════════════════════════════════════════════════════════════════════════════╗
|
╔════════════════════════════════════════════════════════════════════════════╗
|
||||||
║ 📋 GENERATE TEST FOR DIFY COMPONENT ║
|
║ 📋 GENERATE TEST FOR DIFY COMPONENT ║
|
||||||
╚════════════════════════════════════════════════════════════════════════════╝
|
╚════════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
📍 Component: ${analysis.name}
|
📍 Component: ${analysis.name}
|
||||||
@ -307,7 +309,7 @@ Features Detected:
|
|||||||
${analysis.hasAPI ? '✓' : '✗'} API calls
|
${analysis.hasAPI ? '✓' : '✗'} API calls
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
📝 TASK FOR CURSOR AI:
|
📝 TASK:
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
Please generate a comprehensive test file for this component at:
|
Please generate a comprehensive test file for this component at:
|
||||||
@ -316,16 +318,18 @@ Please generate a comprehensive test file for this component at:
|
|||||||
The component is located at:
|
The component is located at:
|
||||||
${analysis.path}
|
${analysis.path}
|
||||||
|
|
||||||
Follow the testing guidelines in .cursorrules file.
|
Follow the testing guidelines in:
|
||||||
|
- web/scripts/TESTING.md (complete testing guide)
|
||||||
|
- .cursorrules (quick reference for Cursor users)
|
||||||
|
|
||||||
${this.getSpecificGuidelines(analysis)}
|
${this.getSpecificGuidelines(analysis)}
|
||||||
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
📋 COPY THIS TO CURSOR:
|
📋 PROMPT FOR AI ASSISTANT (COPY THIS TO YOUR AI ASSISTANT):
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
Generate a comprehensive test file for @${analysis.path} following the project's testing guidelines in .cursorrules.
|
Generate a comprehensive test file for @${analysis.path} following the project's testing guidelines in web/scripts/TESTING.md.
|
||||||
|
|
||||||
Including but not limited to:
|
Including but not limited to:
|
||||||
${this.buildFocusPoints(analysis)}
|
${this.buildFocusPoints(analysis)}
|
||||||
@ -514,8 +518,13 @@ Examples:
|
|||||||
node scripts/analyze-component.js app/components/base/button/index.tsx
|
node scripts/analyze-component.js app/components/base/button/index.tsx
|
||||||
node scripts/analyze-component.js app/components/workflow/nodes/llm/panel.tsx
|
node scripts/analyze-component.js app/components/workflow/nodes/llm/panel.tsx
|
||||||
|
|
||||||
This tool analyzes your component and generates a prompt for Cursor AI.
|
This tool analyzes your component and generates a prompt for AI assistants.
|
||||||
Copy the output and use it in Cursor Chat (Cmd+L) or Composer (Cmd+I).
|
Copy the output and use it with:
|
||||||
|
- Cursor (Cmd+L for Chat, Cmd+I for Composer)
|
||||||
|
- GitHub Copilot Chat (Cmd+I)
|
||||||
|
- Claude, ChatGPT, or any other AI coding tool
|
||||||
|
|
||||||
|
For complete testing guidelines, see: web/scripts/TESTING.md
|
||||||
`)
|
`)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
@ -587,8 +596,8 @@ This component is too complex to test effectively. Please consider:
|
|||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build prompt for Cursor
|
// Build prompt for AI assistant
|
||||||
const builder = new CursorPromptBuilder()
|
const builder = new TestPromptBuilder()
|
||||||
const prompt = builder.build(analysis, sourceCode)
|
const prompt = builder.build(analysis, sourceCode)
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
@ -619,8 +628,13 @@ This component is too complex to test effectively. Please consider:
|
|||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result.status === 0)
|
if (result.status === 0) {
|
||||||
console.log('\n📋 Prompt copied to clipboard! Paste it in Cursor Chat (Cmd+L).\n')
|
console.log('\n📋 Prompt copied to clipboard!')
|
||||||
|
console.log(' Paste it in your AI assistant:')
|
||||||
|
console.log(' - Cursor: Cmd+L (Chat) or Cmd+I (Composer)')
|
||||||
|
console.log(' - GitHub Copilot Chat: Cmd+I')
|
||||||
|
console.log(' - Or any other AI coding tool\n')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
// pbcopy failed, but don't break the script
|
// pbcopy failed, but don't break the script
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user