Testing Expert
The Testing Expert agent specializes in software testing strategies, test implementation, and quality assurance.
Expertise Areas#
- Unit Testing - Jest, Vitest, Mocha
- Integration Testing - API testing, database testing
- E2E Testing - Playwright, Cypress, Puppeteer
- Component Testing - React Testing Library, Vue Test Utils
- Test Strategy - TDD, BDD, coverage goals
- Mocking - Spies, stubs, mocks, fixtures
- CI Integration - Test automation, reporting
Usage Examples#
Test Strategy#
Use the testing-expert agent to create a test strategy for a new e-commerce feature.
Response includes:
- Test pyramid breakdown
- Coverage goals
- Critical paths
- Test data strategy
Unit Tests#
Use the testing-expert agent to write unit tests for this utility function.
Response includes:
- Test cases
- Edge cases
- Mock setup
- Assertions
E2E Tests#
Use the testing-expert agent to write Playwright tests for the checkout flow.
Response includes:
- Page objects
- Test scenarios
- Assertions
- Error handling
Testing Patterns#
Test Structure (AAA Pattern)#
1describe('UserService', () => {
2 describe('createUser', () => {
3 it('should create a user with valid data', async () => {
4 // Arrange
5 const userData = { email: 'test@example.com', name: 'Test' };
6 const mockRepo = { create: vi.fn().mockResolvedValue({ id: '1', ...userData }) };
7 const service = new UserService(mockRepo);
8
9 // Act
10 const result = await service.createUser(userData);
11
12 // Assert
13 expect(result).toEqual({ id: '1', ...userData });
14 expect(mockRepo.create).toHaveBeenCalledWith(userData);
15 });
16
17 it('should throw on invalid email', async () => {
18 // Arrange
19 const userData = { email: 'invalid', name: 'Test' };
20 const service = new UserService(mockRepo);
21
22 // Act & Assert
23 await expect(service.createUser(userData))
24 .rejects.toThrow('Invalid email');
25 });
26 });
27});Component Testing#
1import { render, screen, fireEvent } from '@testing-library/react';
2import { LoginForm } from './LoginForm';
3
4describe('LoginForm', () => {
5 it('should submit with valid credentials', async () => {
6 const onSubmit = vi.fn();
7 render(<LoginForm onSubmit={onSubmit} />);
8
9 // Fill form
10 await userEvent.type(screen.getByLabelText('Email'), 'test@example.com');
11 await userEvent.type(screen.getByLabelText('Password'), 'password123');
12
13 // Submit
14 await userEvent.click(screen.getByRole('button', { name: 'Sign In' }));
15
16 // Assert
17 expect(onSubmit).toHaveBeenCalledWith({
18 email: 'test@example.com',
19 password: 'password123',
20 });
21 });
22
23 it('should show validation errors', async () => {
24 render(<LoginForm onSubmit={vi.fn()} />);
25
26 // Submit empty form
27 await userEvent.click(screen.getByRole('button', { name: 'Sign In' }));
28
29 // Assert errors shown
30 expect(screen.getByText('Email is required')).toBeInTheDocument();
31 expect(screen.getByText('Password is required')).toBeInTheDocument();
32 });
33});E2E Testing with Playwright#
1import { test, expect } from '@playwright/test';
2
3test.describe('Checkout Flow', () => {
4 test.beforeEach(async ({ page }) => {
5 // Login and add item to cart
6 await page.goto('/login');
7 await page.fill('[name="email"]', 'test@example.com');
8 await page.fill('[name="password"]', 'password');
9 await page.click('button[type="submit"]');
10 await page.waitForURL('/dashboard');
11 });
12
13 test('should complete checkout', async ({ page }) => {
14 // Navigate to cart
15 await page.click('[data-testid="cart-icon"]');
16 await expect(page.getByText('Your Cart')).toBeVisible();
17
18 // Proceed to checkout
19 await page.click('text=Checkout');
20 await expect(page).toHaveURL('/checkout');
21
22 // Fill shipping info
23 await page.fill('[name="address"]', '123 Main St');
24 await page.fill('[name="city"]', 'New York');
25 await page.selectOption('[name="state"]', 'NY');
26 await page.fill('[name="zip"]', '10001');
27
28 // Complete order
29 await page.click('text=Place Order');
30 await expect(page.getByText('Order Confirmed')).toBeVisible();
31 });
32});API Testing#
1import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2import request from 'supertest';
3import { app } from '../app';
4import { prisma } from '../lib/prisma';
5
6describe('POST /api/users', () => {
7 beforeAll(async () => {
8 await prisma.$connect();
9 });
10
11 afterAll(async () => {
12 await prisma.user.deleteMany();
13 await prisma.$disconnect();
14 });
15
16 it('should create a user', async () => {
17 const response = await request(app)
18 .post('/api/users')
19 .send({ email: 'test@example.com', name: 'Test User' })
20 .expect(201);
21
22 expect(response.body).toMatchObject({
23 data: {
24 email: 'test@example.com',
25 name: 'Test User',
26 },
27 });
28 });
29
30 it('should return 400 for invalid data', async () => {
31 const response = await request(app)
32 .post('/api/users')
33 .send({ email: 'invalid' })
34 .expect(400);
35
36 expect(response.body.error.code).toBe('VALIDATION_ERROR');
37 });
38});Mocking Strategies#
Function Mocks#
1// Simple mock
2const mockFn = vi.fn();
3mockFn.mockReturnValue('result');
4mockFn.mockResolvedValue('async result');
5
6// Spy on existing function
7const spy = vi.spyOn(object, 'method');
8spy.mockImplementation(() => 'mocked');Module Mocks#
1// Mock entire module
2vi.mock('./api', () => ({
3 fetchUser: vi.fn().mockResolvedValue({ id: '1', name: 'Test' }),
4}));
5
6// Partial mock
7vi.mock('./utils', async () => {
8 const actual = await vi.importActual('./utils');
9 return {
10 ...actual,
11 formatDate: vi.fn().mockReturnValue('2024-01-01'),
12 };
13});API Mocks with MSW#
1import { rest } from 'msw';
2import { setupServer } from 'msw/node';
3
4const handlers = [
5 rest.get('/api/users/:id', (req, res, ctx) => {
6 return res(ctx.json({ id: req.params.id, name: 'Test User' }));
7 }),
8 rest.post('/api/users', (req, res, ctx) => {
9 return res(ctx.status(201), ctx.json({ id: '1', ...req.body }));
10 }),
11];
12
13const server = setupServer(...handlers);
14
15beforeAll(() => server.listen());
16afterEach(() => server.resetHandlers());
17afterAll(() => server.close());Test Coverage Strategy#
| Test Type | Coverage Target | Focus Areas |
|---|---|---|
| Unit | 80%+ | Business logic, utilities |
| Integration | 70%+ | API endpoints, database |
| E2E | Critical paths | User journeys, checkout |
| Component | 75%+ | Interactive elements |
Sample Prompts#
| Task | Prompt |
|---|---|
| Unit tests | "Write unit tests for this reducer function" |
| Integration | "Create integration tests for the payment API" |
| E2E tests | "Write Playwright tests for user registration" |
| Mocking | "Set up mocks for this external API dependency" |
| Coverage | "Identify untested code paths in this module" |
Configuration#
1// bootspring.config.js
2module.exports = {
3 agents: {
4 customInstructions: {
5 'testing-expert': `
6 - Use Vitest for unit/integration tests
7 - Use Playwright for E2E tests
8 - Follow AAA pattern
9 - Include edge cases
10 - Mock external dependencies
11 `,
12 },
13 },
14 quality: {
15 thresholds: {
16 coverage: 80,
17 },
18 },
19};Related Agents#
- Frontend Expert - Component testing
- Backend Expert - API testing
- Performance Expert - Performance testing