From orchestrator
Provides testing pyramid, unit patterns (AAA, isolation, parameterized, edge cases), and React Testing Library for component tests. Use when writing tests or setting up testing infrastructure.
How this skill is triggered — by the user, by Claude, or both
Slash command
/orchestrator:testing-strategiesThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Comprehensive testing strategies and patterns for ensuring code quality.
Comprehensive testing strategies and patterns for ensuring code quality.
/\
/E2E\ 5% - Critical user journeys
/------\
/ Integ \ 15% - Service boundaries
/----------\
/ Unit \ 80% - Component logic
/--------------\
describe('calculateTotal', () => {
it('should apply discount correctly', () => {
// Arrange
const items = [{ price: 100, quantity: 1 }];
const discount = 0.1;
// Act
const result = calculateTotal(items, discount);
// Assert
expect(result).toBe(90);
});
});
describe('UserService', () => {
let service: UserService;
let mockRepo: MockUserRepository;
beforeEach(() => {
// Fresh instances for each test
mockRepo = new MockUserRepository();
service = new UserService(mockRepo);
});
afterEach(() => {
vi.clearAllMocks();
});
});
describe('validateEmail', () => {
it.each([
['[email protected]', true],
['[email protected]', true],
['invalid', false],
['@nodomain.com', false],
['no@tld', false],
])('validates %s as %s', (email, expected) => {
expect(validateEmail(email)).toBe(expected);
});
});
describe('divide', () => {
it('should handle positive numbers', () => {
expect(divide(10, 2)).toBe(5);
});
it('should handle negative numbers', () => {
expect(divide(-10, 2)).toBe(-5);
});
it('should handle zero dividend', () => {
expect(divide(0, 5)).toBe(0);
});
it('should throw on division by zero', () => {
expect(() => divide(10, 0)).toThrow('Division by zero');
});
it('should handle floating point', () => {
expect(divide(1, 3)).toBeCloseTo(0.333, 2);
});
});
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
describe('LoginForm', () => {
const mockOnSubmit = vi.fn();
beforeEach(() => {
mockOnSubmit.mockClear();
});
it('submits with valid data', async () => {
const user = userEvent.setup();
render(<LoginForm onSubmit={mockOnSubmit} />);
await user.type(screen.getByLabelText(/email/i), '[email protected]');
await user.type(screen.getByLabelText(/password/i), 'password123');
await user.click(screen.getByRole('button', { name: /submit/i }));
await waitFor(() => {
expect(mockOnSubmit).toHaveBeenCalledWith({
email: '[email protected]',
password: 'password123',
});
});
});
it('shows validation errors', async () => {
const user = userEvent.setup();
render(<LoginForm onSubmit={mockOnSubmit} />);
await user.click(screen.getByRole('button', { name: /submit/i }));
expect(await screen.findByText(/email is required/i)).toBeInTheDocument();
expect(mockOnSubmit).not.toHaveBeenCalled();
});
});
import { renderHook, act, waitFor } from '@testing-library/react';
describe('useCounter', () => {
it('increments counter', () => {
const { result } = renderHook(() => useCounter(0));
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
});
describe('useAsync', () => {
it('handles async operation', async () => {
const mockFetch = vi.fn().mockResolvedValue({ data: 'test' });
const { result } = renderHook(() => useAsync(mockFetch));
expect(result.current.isLoading).toBe(true);
await waitFor(() => {
expect(result.current.isLoading).toBe(false);
});
expect(result.current.data).toEqual({ data: 'test' });
});
});
import { testClient } from 'hono/testing';
import app from '../src/index';
describe('Users API', () => {
const client = testClient(app);
beforeEach(async () => {
await db.delete(users);
});
it('creates and retrieves user', async () => {
// Create
const createRes = await client.api.v1.users.$post({
json: { name: 'Test', email: '[email protected]', password: 'pass123' },
});
expect(createRes.status).toBe(201);
const created = await createRes.json();
// Retrieve
const getRes = await client.api.v1.users[':id'].$get({
param: { id: created.data.id },
});
expect(getRes.status).toBe(200);
const retrieved = await getRes.json();
expect(retrieved.data.email).toBe('[email protected]');
});
});
describe('UserRepository', () => {
const repo = new UserRepository();
beforeEach(async () => {
await db.delete(users);
});
it('creates and finds user', async () => {
const created = await repo.create({
name: 'Test User',
email: '[email protected]',
});
const found = await repo.findById(created.id);
expect(found).toEqual(created);
});
it('returns null for non-existent user', async () => {
const found = await repo.findById('non-existent-id');
expect(found).toBeNull();
});
});
import { test, expect } from '@playwright/test';
test.describe('User Flow', () => {
test('complete registration and login flow', async ({ page }) => {
// Register
await page.goto('/register');
await page.fill('[name="email"]', '[email protected]');
await page.fill('[name="password"]', 'Password123!');
await page.click('button[type="submit"]');
// Verify redirect to login
await expect(page).toHaveURL('/login');
// Login
await page.fill('[name="email"]', '[email protected]');
await page.fill('[name="password"]', 'Password123!');
await page.click('button[type="submit"]');
// Verify dashboard access
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('h1')).toContainText('Dashboard');
});
});
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
const handlers = [
http.get('/api/users', () => {
return HttpResponse.json({
success: true,
data: [{ id: '1', name: 'Test User' }],
});
}),
http.post('/api/users', async ({ request }) => {
const body = await request.json();
return HttpResponse.json(
{ success: true, data: { id: '2', ...body } },
{ status: 201 }
);
}),
];
export const server = setupServer(...handlers);
// Setup in test file
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
// Mock module
vi.mock('./api', () => ({
fetchUsers: vi.fn().mockResolvedValue([{ id: '1', name: 'Test' }]),
}));
// Mock implementation
const mockFetch = vi.fn();
mockFetch
.mockResolvedValueOnce({ data: 'first' })
.mockResolvedValueOnce({ data: 'second' });
// Spy on method
const spy = vi.spyOn(console, 'log');
expect(spy).toHaveBeenCalledWith('message');
| Metric | Minimum | Target |
|---|---|---|
| Statements | 70% | 85% |
| Branches | 65% | 80% |
| Functions | 70% | 85% |
| Lines | 70% | 85% |
tests/
├── unit/ # Unit tests
│ ├── utils/
│ └── services/
├── integration/ # Integration tests
│ ├── api/
│ └── db/
├── e2e/ # E2E tests
│ ├── auth.spec.ts
│ └── dashboard.spec.ts
├── fixtures/ # Test data
├── mocks/ # Mock implementations
└── setup.ts # Global setup
npx claudepluginhub devsforge/orchestrator --plugin orchestratorDesigns and implements testing strategies—unit, integration, E2E—for any codebase. Provides framework recommendations (Vitest, Playwright, pytest, etc.) and test structure templates.
Provides strategies for writing maintainable unit, integration, and E2E tests using AAA pattern, mocking, test naming, and organization. Useful for TDD and test infrastructure.
Provides test pyramid guidance, coverage targets, and patterns for unit, integration, E2E, performance, and security tests in PACT Test phase. Useful for designing test suites and prioritizing coverage.