Testing Methodologies
Comprehensive testing approaches and methodologies for FLYPILOT projects.
Testing Pyramid
/\
/ \
/ E2E\
/------\
/ Integ \
/----------\
/ Unit \
/--------------\
| Level | Coverage | Speed | Cost |
|---|---|---|---|
| Unit | Components, functions | Fast | Low |
| Integration | API, services | Medium | Medium |
| E2E | User journeys | Slow | High |
Unit Testing
What to Test
- Individual functions and utilities
- React components in isolation
- State management logic
- Data transformations
Tools
| Stack | Framework | Runner |
|---|---|---|
| React/Next.js | Jest + React Testing Library | Jest |
| WordPress | PHPUnit | WP CLI |
| Node.js | Jest or Vitest | Native |
Example: React Component
// Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';
describe('Button', () => {
it('renders with text', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
it('calls onClick when clicked', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
fireEvent.click(screen.getByText('Click me'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('is disabled when disabled prop is true', () => {
render(<Button disabled>Click me</Button>);
expect(screen.getByText('Click me')).toBeDisabled();
});
});
Example: Utility Function
// utils/formatPrice.test.ts
import { formatPrice } from './formatPrice';
describe('formatPrice', () => {
it('formats whole numbers', () => {
expect(formatPrice(100)).toBe('$100.00');
});
it('formats decimals', () => {
expect(formatPrice(99.99)).toBe('$99.99');
});
it('handles zero', () => {
expect(formatPrice(0)).toBe('$0.00');
});
it('handles negative numbers', () => {
expect(formatPrice(-50)).toBe('-$50.00');
});
});
Integration Testing
What to Test
- API endpoint responses
- Database operations
- Third-party service integrations
- Authentication flows
Example: API Endpoint
// api/users.test.ts
import { createMocks } from 'node-mocks-http';
import handler from '@/app/api/users/route';
describe('/api/users', () => {
it('returns users list', async () => {
const { req, res } = createMocks({
method: 'GET',
});
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(JSON.parse(res._getData())).toHaveProperty('users');
});
it('creates a new user', async () => {
const { req, res } = createMocks({
method: 'POST',
body: {
name: 'Test User',
email: 'test@example.com',
},
});
await handler(req, res);
expect(res._getStatusCode()).toBe(201);
expect(JSON.parse(res._getData())).toHaveProperty('id');
});
it('returns 400 for invalid data', async () => {
const { req, res } = createMocks({
method: 'POST',
body: {
name: '', // Invalid: empty name
},
});
await handler(req, res);
expect(res._getStatusCode()).toBe(400);
});
});
End-to-End Testing
What to Test
- Critical user journeys
- Checkout flows
- Authentication flows
- Form submissions
Tools
| Tool | Best For |
|---|---|
| Playwright | Cross-browser, modern |
| Cypress | Developer experience |
| Puppeteer | Chrome-specific |
Example: Playwright
// tests/checkout.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Checkout Flow', () => {
test('completes purchase successfully', async ({ page }) => {
// Navigate to product
await page.goto('/products/test-product');
// Add to cart
await page.click('[data-testid="add-to-cart"]');
await expect(page.locator('[data-testid="cart-count"]')).toHaveText('1');
// Go to checkout
await page.click('[data-testid="checkout-button"]');
await expect(page).toHaveURL('/checkout');
// Fill shipping info
await page.fill('[name="email"]', 'test@example.com');
await page.fill('[name="name"]', 'Test User');
await page.fill('[name="address"]', '123 Test St');
await page.fill('[name="city"]', 'Test City');
await page.fill('[name="zip"]', '12345');
// Fill payment info (test mode)
await page.fill('[name="cardNumber"]', '4242424242424242');
await page.fill('[name="expiry"]', '12/25');
await page.fill('[name="cvc"]', '123');
// Complete purchase
await page.click('[data-testid="place-order"]');
// Verify success
await expect(page).toHaveURL(/\/order-confirmation/);
await expect(page.locator('h1')).toContainText('Thank you');
});
});
Visual Regression Testing
Tools
- Percy - CI integration, snapshot comparison
- Chromatic - Storybook integration
- BackstopJS - Open source
When to Use
- Design system components
- Marketing pages with precise designs
- After major refactors
Accessibility Testing
Automated Tools
- axe DevTools - Browser extension
- jest-axe - Jest integration
- Lighthouse - Built into Chrome
Manual Testing Checklist
- Navigate entire site with keyboard only
- Test with screen reader (VoiceOver/NVDA)
- Check color contrast ratios
- Verify focus indicators are visible
- Test with zoom at 200%
Example: Jest Accessibility Test
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
import { LoginForm } from './LoginForm';
expect.extend(toHaveNoViolations);
describe('LoginForm Accessibility', () => {
it('has no accessibility violations', async () => {
const { container } = render(<LoginForm />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
Performance Testing
Metrics to Monitor
- Time to First Byte (TTFB)
- First Contentful Paint (FCP)
- Largest Contentful Paint (LCP)
- Time to Interactive (TTI)
- Total Blocking Time (TBT)
Tools
- Lighthouse CI - Automated in CI/CD
- WebPageTest - Detailed analysis
- Chrome DevTools - Performance panel
Performance Budget
{
"performance": [
{
"metric": "first-contentful-paint",
"budget": 1800
},
{
"metric": "largest-contentful-paint",
"budget": 2500
},
{
"metric": "total-blocking-time",
"budget": 300
},
{
"metric": "cumulative-layout-shift",
"budget": 0.1
}
]
}
Testing Workflow
Pre-Commit
- Run linting
- Run unit tests
- Run type checking
Pull Request
- All pre-commit checks
- Integration tests
- Visual regression (if configured)
- Accessibility checks
Pre-Deploy
- Full test suite
- E2E tests
- Performance audit
- Security scan
Post-Deploy
- Smoke tests on production
- Monitor error rates
- Check Core Web Vitals
Test Coverage
Aim for 80%+ unit test coverage on critical paths. Don't test everything - focus on business logic and complex interactions.