Claude-skill-registry generate-test
Generate Jest test suite with mocks and common test cases. Use when creating tests for components, repositories, or API routes.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/generate-test" ~/.claude/skills/majiayu000-claude-skill-registry-generate-test-b3d317 && rm -rf "$T"
manifest:
skills/data/generate-test/SKILL.mdsource content
Generate Test
Generate a Jest test suite following Health Tracker 9000 testing patterns.
Usage
When user requests to create tests, ask for:
- Test target (component, repository, API route, or utility)
- Target name (e.g., "MealLogForm", "WaterLogRepository")
- Main functionality to test
- Edge cases or error scenarios
Implementation Pattern
Based on
src/__tests__/components/forms/MealLogForm.test.tsx pattern.
Component Test Structure
Create file:
src/__tests__/{target-type}/{location}/{TargetName}.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { FormName } from '@/components/forms/FormName'; import { useHealthStore } from '@/lib/store/healthStore'; // Mock the store jest.mock('@/lib/store/healthStore'); jest.mock('sonner', () => ({ toast: { success: jest.fn(), error: jest.fn(), info: jest.fn(), }, })); const mockAddItem = jest.fn(); describe('FormName', () => { beforeEach(() => { jest.clearAllMocks(); (useHealthStore as jest.Mock).mockReturnValue({ addItem: mockAddItem, isLoading: false, }); }); it('renders the form correctly', () => { render(<FormName />); expect(screen.getByLabelText('Field 1 Label')).toBeInTheDocument(); expect(screen.getByLabelText('Field 2 Label')).toBeInTheDocument(); expect(screen.getByRole('button', { name: /submit/i })).toBeInTheDocument(); }); it('validates required fields', async () => { render(<FormName />); const submitButton = screen.getByRole('button', { name: /submit/i }); fireEvent.click(submitButton); await waitFor(() => { expect(screen.getByText('Field 1 is required')).toBeInTheDocument(); }); }); it('submits form with valid data', async () => { render(<FormName />); const field1Input = screen.getByLabelText('Field 1 Label') as HTMLInputElement; const field2Input = screen.getByLabelText('Field 2 Label') as HTMLInputElement; const submitButton = screen.getByRole('button', { name: /submit/i }); fireEvent.change(field1Input, { target: { value: 'test value' } }); fireEvent.change(field2Input, { target: { value: '100' } }); fireEvent.click(submitButton); await waitFor(() => { expect(mockAddItem).toHaveBeenCalledWith( expect.objectContaining({ field1: 'test value', field2: '100', }) ); }); }); it('clears form after successful submission', async () => { render(<FormName />); const field1Input = screen.getByLabelText('Field 1 Label') as HTMLInputElement; const submitButton = screen.getByRole('button', { name: /submit/i }); fireEvent.change(field1Input, { target: { value: 'test' } }); fireEvent.click(submitButton); await waitFor(() => { expect(field1Input.value).toBe(''); }); }); it('disables form while loading', () => { (useHealthStore as jest.Mock).mockReturnValue({ addItem: mockAddItem, isLoading: true, }); render(<FormName />); const submitButton = screen.getByRole('button', { name: /submit/i }); expect(submitButton).toBeDisabled(); }); });
Repository Test Structure
Create file:
src/__tests__/lib/database/repositories/{EntityName}.test.ts
import { EntityRepository } from '@/lib/database/repositories/entityRepository'; import { getDatabase } from '@/lib/database/connection'; jest.mock('@/lib/database/connection'); describe('EntityRepository', () => { let repo: EntityRepository; let mockDb: any; beforeEach(() => { jest.clearAllMocks(); mockDb = { prepare: jest.fn(), }; (getDatabase as jest.Mock).mockReturnValue(mockDb); repo = new EntityRepository(); }); it('adds entity correctly', () => { const mockStmt = { run: jest.fn() }; mockDb.prepare.mockReturnValue(mockStmt); const result = repo.addEntity({ field1: 'value1', field2: 'value2' }); expect(result).toHaveProperty('id'); expect(result).toHaveProperty('createdAt'); expect(result.field1).toBe('value1'); expect(mockStmt.run).toHaveBeenCalled(); }); it('gets entity by id', () => { const mockStmt = { get: jest.fn() }; mockDb.prepare.mockReturnValue(mockStmt); mockStmt.get.mockReturnValue({ id: '123', field_1: 'value1', field_2: '{"nested": "data"}', }); const result = repo.getEntityById('123'); expect(result).toEqual( expect.objectContaining({ id: '123', field1: 'value1', }) ); }); it('returns null for non-existent entity', () => { const mockStmt = { get: jest.fn() }; mockDb.prepare.mockReturnValue(mockStmt); mockStmt.get.mockReturnValue(undefined); const result = repo.getEntityById('nonexistent'); expect(result).toBeNull(); }); it('throws error when updating non-existent entity', () => { const mockStmt = { get: jest.fn() }; mockDb.prepare.mockReturnValue(mockStmt); mockStmt.get.mockReturnValue(undefined); expect(() => { repo.updateEntity('nonexistent', {}); }).toThrow('Entity not found'); }); it('deletes entity correctly', () => { const mockStmt = { run: jest.fn() }; mockDb.prepare.mockReturnValue(mockStmt); repo.deleteEntity('123'); expect(mockStmt.run).toHaveBeenCalledWith('123'); }); });
API Route Test Structure
Create file:
src/__tests__/app/api/{resource}/route.test.ts
import { POST, DELETE } from '@/app/api/resource/route'; import { ResourceRepository } from '@/lib/database/repositories/resourceRepository'; jest.mock('@/lib/database/repositories/resourceRepository'); jest.mock('@/lib/database/repositories/dailySummaryRepository'); describe('Resource API Route', () => { beforeEach(() => { jest.clearAllMocks(); }); it('POST creates new resource', async () => { const mockRepo = { addResource: jest.fn().mockReturnValue({ id: '123', field: 'value' }), }; (ResourceRepository as jest.Mock).mockImplementation(() => mockRepo); const request = new Request('http://localhost:3000/api/resource', { method: 'POST', body: JSON.stringify({ field: 'value', date: '2024-01-15' }), }); const response = await POST(request); const data = await response.json(); expect(response.status).toBe(200); expect(data).toEqual({ id: '123', field: 'value' }); }); it('DELETE removes resource', async () => { const mockRepo = { deleteResource: jest.fn() }; (ResourceRepository as jest.Mock).mockImplementation(() => mockRepo); const request = new Request('http://localhost:3000/api/resource?id=123', { method: 'DELETE', }); const response = await DELETE(request); expect(response.status).toBe(200); expect(mockRepo.deleteResource).toHaveBeenCalledWith('123'); }); it('DELETE returns 400 when id missing', async () => { const request = new Request('http://localhost:3000/api/resource', { method: 'DELETE', }); const response = await DELETE(request); expect(response.status).toBe(400); }); });
Key Conventions
- Test file location mirrors source structure in
src/__tests__/ - File naming:
{SourceName}.test.ts(x) - Mock external dependencies (stores, API calls, database)
- beforeEach to clear mocks between tests
- Use React Testing Library patterns for components
- Test user interactions, not implementation
- Test error cases and edge cases
- Use descriptive test names (should be readable as documentation)
- Mock data should be realistic
Test Coverage Targets
For components:
- Renders correctly
- Handles user input
- Validates data
- Shows error states
- Manages loading states
- Calls store actions
For repositories:
- CRUD operations work
- Row mapping correct
- Error handling
- Null checks
For API routes:
- POST creates records
- GET retrieves records
- DELETE removes records
- Error handling (400, 500)
- Proper HTTP status codes
Steps
- Ask user for test target, name, and functionality
- Create file:
src/__tests__/{path}/{Name}.test.ts(x) - Mock dependencies (stores, database, APIs)
- Write beforeEach to clear mocks
- Write test cases for main functionality
- Write test cases for error scenarios
- Format with Prettier
Implementation Checklist
- Test file in correct location
- Dependencies properly mocked
- beforeEach clears mocks
- Tests use descriptive names
- Main functionality tested
- Error cases tested
- Edge cases tested
- Uses appropriate testing library
- No implementation details tested
- Proper assertions used