@claude-powers/slash-commands
Version:
π Claude Powers - Essential slash commands for Claude Code
555 lines (465 loc) β’ 17.3 kB
Markdown
Automatically generates comprehensive tests using advanced AI to maximize coverage, quality and edge cases with minimal effort.
The `/generate-tests` command revolutionizes test writing by completely automating the process:
- **Automatic generation** of unit, integration and E2E tests
- **Code analysis** to identify all necessary test cases
- **Automatic edge cases** that humans often forget
- **Intelligent mocks** for external dependencies
- **Optimized coverage** to reach desired metrics
- **Multiple frameworks** (Jest, Vitest, Cypress, Playwright, etc.)
- **Best practices patterns** in testing built-in
- **Maintainable tests** with clear naming and logical structure
```
/generate-tests [file/directory] [--type] [--framework] [--coverage] [--mocks]
```
- `file/directory`: Source code for which to generate tests
- `--type`: Types of tests (unit, integration, e2e, performance, accessibility)
- `--framework`: Testing framework (jest, vitest, cypress, playwright, mocha)
- `--coverage`: Coverage target (80%, 90%, 95%)
- `--mocks`: Mocking strategy (auto, manual, none)
- `--patterns`: Testing patterns (aaa, bdd, tdd)
- `--edge-cases`: Edge cases level (basic, comprehensive, paranoid)
- `--performance`: Include performance tests
- `--accessibility`: Include accessibility tests
### Examples
```
/generate-tests src/components/UserProfile.tsx
/generate-tests --type=unit,integration --coverage=95%
/generate-tests api/ --framework=jest --mocks=auto
/generate-tests --edge-cases=comprehensive --patterns=bdd
/generate-tests frontend/ --type=e2e --framework=playwright
/generate-tests utils/ --performance=true --coverage=100%
```
```javascript
// Auto-generado para UserProfile.tsx
describe('UserProfile Component', () => {
const mockUser = {
id: '123',
name: 'John Doe',
email: 'john@example.com',
avatar: 'https://example.com/avatar.jpg'
};
beforeEach(() => {
render(<UserProfile user={mockUser} />);
});
describe('Rendering', () => {
it('should render user name correctly', () => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
});
it('should render user email correctly', () => {
expect(screen.getByText('john@example.com')).toBeInTheDocument();
});
it('should render avatar with correct src', () => {
const avatar = screen.getByAltText('John Doe avatar');
expect(avatar).toHaveAttribute('src', 'https://example.com/avatar.jpg');
});
});
describe('Edge Cases', () => {
it('should handle missing avatar gracefully', () => {
const userWithoutAvatar = { ...mockUser, avatar: null };
render(<UserProfile user={userWithoutAvatar} />);
expect(screen.getByText('JD')).toBeInTheDocument(); // Initials fallback
});
it('should handle extremely long names', () => {
const userWithLongName = {
...mockUser,
name: 'A'.repeat(100)
};
render(<UserProfile user={userWithLongName} />);
expect(screen.getByText(/A{50}\.\.\.$/)).toBeInTheDocument(); // Truncated
});
it('should handle special characters in name', () => {
const userWithSpecialChars = {
...mockUser,
name: 'JosΓ© MarΓa Aznar-LΓ³pez'
};
render(<UserProfile user={userWithSpecialChars} />);
expect(screen.getByText('JosΓ© MarΓa Aznar-LΓ³pez')).toBeInTheDocument();
});
});
describe('Interactions', () => {
it('should call onEdit when edit button is clicked', () => {
const mockOnEdit = jest.fn();
render(<UserProfile user={mockUser} onEdit={mockOnEdit} />);
fireEvent.click(screen.getByRole('button', { name: /edit/i }));
expect(mockOnEdit).toHaveBeenCalledWith(mockUser.id);
});
it('should handle rapid multiple clicks gracefully', () => {
const mockOnEdit = jest.fn();
render(<UserProfile user={mockUser} onEdit={mockOnEdit} />);
const editButton = screen.getByRole('button', { name: /edit/i });
fireEvent.click(editButton);
fireEvent.click(editButton);
fireEvent.click(editButton);
expect(mockOnEdit).toHaveBeenCalledTimes(1); // Debounced
});
});
describe('Accessibility', () => {
it('should have proper ARIA labels', () => {
render(<UserProfile user={mockUser} />);
expect(screen.getByRole('img')).toHaveAttribute('alt', 'John Doe avatar');
expect(screen.getByRole('button', { name: /edit/i })).toBeInTheDocument();
});
it('should be keyboard navigable', () => {
render(<UserProfile user={mockUser} />);
const editButton = screen.getByRole('button', { name: /edit/i });
expect(editButton).toHaveAttribute('tabIndex', '0');
});
});
describe('Performance', () => {
it('should render within performance budget', async () => {
const start = performance.now();
render(<UserProfile user={mockUser} />);
const end = performance.now();
expect(end - start).toBeLessThan(16); // 60fps budget
});
it('should not cause memory leaks', () => {
const { unmount } = render(<UserProfile user={mockUser} />);
unmount();
// Verificar que no hay listeners activos
});
});
});
```
```javascript
// Auto-generado para UserService integration
describe('UserService Integration', () => {
let userService;
let mockApiClient;
beforeEach(() => {
mockApiClient = {
get: jest.fn(),
post: jest.fn(),
put: jest.fn(),
delete: jest.fn()
};
userService = new UserService(mockApiClient);
});
describe('User CRUD Operations', () => {
it('should fetch user by id successfully', async () => {
const mockUser = { id: '123', name: 'John Doe' };
mockApiClient.get.mockResolvedValue({ data: mockUser });
const result = await userService.getUserById('123');
expect(mockApiClient.get).toHaveBeenCalledWith('/users/123');
expect(result).toEqual(mockUser);
});
it('should handle network errors gracefully', async () => {
mockApiClient.get.mockRejectedValue(new Error('Network Error'));
await expect(userService.getUserById('123')).rejects.toThrow('Failed to fetch user');
});
it('should retry failed requests with exponential backoff', async () => {
mockApiClient.get
.mockRejectedValueOnce(new Error('500'))
.mockRejectedValueOnce(new Error('500'))
.mockResolvedValue({ data: { id: '123' } });
const result = await userService.getUserById('123');
expect(mockApiClient.get).toHaveBeenCalledTimes(3);
expect(result).toEqual({ id: '123' });
});
});
describe('Caching Behavior', () => {
it('should cache successful responses', async () => {
const mockUser = { id: '123', name: 'John Doe' };
mockApiClient.get.mockResolvedValue({ data: mockUser });
await userService.getUserById('123');
await userService.getUserById('123');
expect(mockApiClient.get).toHaveBeenCalledTimes(1);
});
it('should invalidate cache after TTL', async () => {
jest.useFakeTimers();
const mockUser = { id: '123', name: 'John Doe' };
mockApiClient.get.mockResolvedValue({ data: mockUser });
await userService.getUserById('123');
jest.advanceTimersByTime(300000); // 5 minutes
await userService.getUserById('123');
expect(mockApiClient.get).toHaveBeenCalledTimes(2);
jest.useRealTimers();
});
});
});
```
```javascript
// Auto-generado con Playwright
describe('User Management E2E', () => {
test('complete user registration flow', async ({ page }) => {
// Navigate to registration
await page.goto('/register');
// Fill registration form
await page.fill('[data-testid="email"]', 'test@example.com');
await page.fill('[data-testid="password"]', 'SecurePass123!');
await page.fill('[data-testid="confirmPassword"]', 'SecurePass123!');
// Submit form
await page.click('[data-testid="submit"]');
// Verify email verification screen
await expect(page.locator('h1')).toContainText('Check your email');
// Simulate email verification click
await page.goto('/verify-email?token=mock-token');
// Verify successful registration
await expect(page.locator('[data-testid="welcome-message"]'))
.toContainText('Welcome to the platform!');
});
test('handles registration errors gracefully', async ({ page }) => {
await page.goto('/register');
// Try to register with existing email
await page.fill('[data-testid="email"]', 'existing@example.com');
await page.fill('[data-testid="password"]', 'SecurePass123!');
await page.fill('[data-testid="confirmPassword"]', 'SecurePass123!');
await page.click('[data-testid="submit"]');
// Verify error message
await expect(page.locator('[data-testid="error-message"]'))
.toContainText('Email already exists');
});
test('form validation works correctly', async ({ page }) => {
await page.goto('/register');
// Submit empty form
await page.click('[data-testid="submit"]');
// Verify validation errors
await expect(page.locator('[data-testid="email-error"]'))
.toContainText('Email is required');
await expect(page.locator('[data-testid="password-error"]'))
.toContainText('Password is required');
});
});
```
El comando utiliza `.claude/generate-tests-config.json`:
```json
{
"defaultFramework": "jest",
"defaultCoverage": 80,
"testTypes": {
"unit": {
"enabled": true,
"patterns": ["aaa", "bdd"],
"mockStrategy": "auto",
"edgeCases": "comprehensive"
},
"integration": {
"enabled": true,
"apiMocking": true,
"databaseMocking": "in-memory",
"cacheTests": true
},
"e2e": {
"enabled": false,
"framework": "playwright",
"browsers": ["chromium", "firefox"],
"devices": ["desktop", "mobile"]
},
"performance": {
"enabled": false,
"budgets": {
"renderTime": "16ms",
"bundleSize": "500KB",
"memoryUsage": "50MB"
}
},
"accessibility": {
"enabled": true,
"standards": ["wcag2.1", "section508"],
"levels": ["AA"]
}
},
"frameworks": {
"jest": {
"setupFiles": ["@testing-library/jest-dom"],
"testEnvironment": "jsdom",
"collectCoverageFrom": ["src/**/*.{js,jsx,ts,tsx}"]
},
"vitest": {
"environment": "jsdom",
"setupFiles": ["@testing-library/jest-dom"]
},
"cypress": {
"baseUrl": "http://localhost:3000",
"viewportWidth": 1280,
"viewportHeight": 720
},
"playwright": {
"baseURL": "http://localhost:3000",
"use": {
"screenshot": "only-on-failure",
"video": "retain-on-failure"
}
}
},
"mocking": {
"apiRequests": {
"strategy": "msw",
"generateMockData": true,
"realisticData": true
},
"modules": {
"strategy": "auto",
"preserveImplementation": false
},
"dependencies": {
"external": "mock",
"internal": "spy"
}
},
"codeAnalysis": {
"detectTestableUnits": true,
"identifyEdgeCases": true,
"analyzeDependencies": true,
"extractBusinessLogic": true
}
}
```
```
π§ͺ CLAUDE POWER - TEST GENERATION ANALYSIS
==========================================
π CΓDIGO ANALIZADO:
src/components/UserProfile.tsx (127 lΓneas)
β’ 3 props analizadas (user, onEdit, className)
β’ 5 estados internos detectados
β’ 8 mΓ©all identificados
β’ 12 casos edge identificados
π PLAN DE TESTS:
βββββββββββββββββββ¬ββββββββββ¬ββββββββββββββ¬ββββββββββββββ
β Tipo Test β Cantidadβ Cobertura β Tiempo Est. β
βββββββββββββββββββΌββββββββββΌββββββββββββββΌββββββββββββββ€
β Unit Tests β 24 β 95% β 8 min β
β Integration β 6 β 85% β 4 min β
β E2E Tests β 3 β 70% β 12 min β
β A11y Tests β 8 β 90% β 3 min β
βββββββββββββββββββ΄ββββββββββ΄ββββββββββββββ΄ββββββββββββββ
π― CASOS DETECTADOS:
β
Rendering con props vΓ‘lidas
β
Manejo de props faltantes/nulas
β
Eventos de interacciΓ³n
β
Estados de loading/error
β
Casos edge (nombres largos, caracteres especiales)
β
Accessibility compliance
β
Performance budgets
β
Mobile responsiveness
```
### Tests Generados
```
π TESTS GENERADOS EXITOSAMENTE:
===============================
π files creados:
β’ src/components/__tests__/UserProfile.test.tsx (312 lΓneas)
β’ src/components/__tests__/UserProfile.integration.test.tsx (156 lΓneas)
β’ e2e/user-profile.spec.ts (89 lΓneas)
β’ src/components/__tests__/UserProfile.a11y.test.tsx (67 lΓneas)
π COBERTURA PROYECTADA:
β’ Statements: 96.8%
β’ Branches: 94.2%
β’ Functions: 100%
β’ Lines: 95.9%
π§ͺ RESUMEN DE TESTS:
β’ Total tests: 41
β’ Unit tests: 24 (β
Rendering, interactions, edge cases)
β’ Integration tests: 6 (β
API calls, state management)
β’ E2E tests: 3 (β
User flows completos)
β’ Accessibility tests: 8 (β
WCAG 2.1 compliance)
β‘ PERFORMANCE:
β’ Tiempo de ejecuciΓ³n estimado: 12.4s
β’ Memory usage: 85MB
β’ CPU usage: Medium
π― CALIDAD:
β’ Best practices: β
Implementadas
β’ Mocking strategy: β
Optimizada
β’ Test maintainability: β
Alta
β’ Edge cases coverage: β
Comprehensive
```
```yaml
name: Generated Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test-generated:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Generate missing tests
run: |
npx claude-power generate-tests \
--type=unit,integration \
--coverage=90% \
--auto-update
- name: Run generated tests
run: npm test -- --coverage --passWithNoTests
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
- name: Comment PR with coverage
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const coverage = JSON.parse(fs.readFileSync('./coverage/coverage-summary.json'));
const comment = `
| Metric | Percentage | Status |
|--------|------------|--------|
| Statements | ${coverage.total.statements.pct}% | ${coverage.total.statements.pct >= 90 ? 'β
' : 'β οΈ'} |
| Branches | ${coverage.total.branches.pct}% | ${coverage.total.branches.pct >= 90 ? 'β
' : 'β οΈ'} |
| Functions | ${coverage.total.functions.pct}% | ${coverage.total.functions.pct >= 90 ? 'β
' : 'β οΈ'} |
| Lines | ${coverage.total.lines.pct}% | ${coverage.total.lines.pct >= 90 ? 'β
' : 'β οΈ'} |
Generated by Claude Power Test Generator π€
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
```
```json
{
"commands": [
{
"command": "claude-power.generateTests",
"title": "Generate Tests",
"category": "Claude Power"
}
],
"keybindings": [
{
"command": "claude-power.generateTests",
"key": "ctrl+shift+t",
"when": "editorTextFocus"
}
],
"tasks": [
{
"label": "Generate Tests for Current File",
"type": "shell",
"command": "npx",
"args": [
"claude-power",
"generate-tests",
"${file}",
"--coverage=90%"
]
}
]
}
```
---
*Parte del ecosistema **Claude Power** - Tests perfectos sin esfuerzo* π§ͺπ