← back to Wine Finder Next

TESTING_QUICK_START.md

300 lines

# Testing Quick Start Guide

## Installation

```bash
# Install test dependencies
npm install --save-dev \
  jest \
  @testing-library/react \
  @testing-library/jest-dom \
  @testing-library/user-event \
  @playwright/test \
  supertest \
  ts-jest \
  @types/jest \
  @types/supertest \
  jest-environment-jsdom
```

## Quick Commands

```bash
# Run all unit tests
npm run test:unit

# Run in watch mode (recommended for development)
npm test

# Run specific test file
npm test inputValidation.test.ts

# Run with coverage
npm run test:coverage

# Run E2E tests
npm run test:e2e

# Run E2E with UI (great for debugging)
npm run test:e2e:ui
```

## Test Structure at a Glance

```
__tests__/
├── unit/                   # Unit tests (70+ tests)
├── integration/            # API tests (30+ tests)
├── security/               # Security tests (50+ tests)
├── performance/            # Load tests (15+ tests)
└── fixtures/               # Test data

e2e/                        # End-to-end tests (25+ tests)
```

## Writing Your First Test

### 1. Unit Test Example

```typescript
// __tests__/unit/myFunction.test.ts
describe('MyFunction', () => {
  it('should do something', () => {
    const result = myFunction('input');
    expect(result).toBe('expected');
  });
});
```

### 2. Integration Test Example

```typescript
// __tests__/integration/api-endpoint.test.ts
import { GET } from '@/app/api/endpoint/route';
import { NextRequest } from 'next/server';

describe('API Endpoint', () => {
  it('should return data', async () => {
    const request = new NextRequest('http://localhost:3000/api/endpoint');
    const response = await GET(request);
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data.success).toBe(true);
  });
});
```

### 3. E2E Test Example

```typescript
// e2e/user-flow.spec.ts
import { test, expect } from '@playwright/test';

test('user can purchase shares', async ({ page }) => {
  await page.goto('/membership');
  await page.click('[data-testid="buy-btn"]');
  await expect(page.locator('[data-testid="success"]')).toBeVisible();
});
```

## Test Coverage Goals

| Metric | Target | Priority |
|--------|--------|----------|
| Lines | 70% | High |
| Functions | 70% | High |
| Branches | 70% | Medium |
| Statements | 70% | Medium |

## Common Test Patterns

### Arrange-Act-Assert (AAA)

```typescript
it('should validate email', () => {
  // Arrange
  const email = 'test@example.com';

  // Act
  const result = validateEmail(email);

  // Assert
  expect(result).toBe(true);
});
```

### Mocking

```typescript
jest.mock('@/lib/database');

import { database } from '@/lib/database';

beforeEach(() => {
  (database.query as jest.Mock).mockResolvedValue([]);
});
```

### Async Testing

```typescript
it('should fetch data', async () => {
  const data = await fetchData();
  expect(data).toHaveLength(5);
});
```

## Debugging Tests

### VS Code Debug Configuration

```json
{
  "type": "node",
  "request": "launch",
  "name": "Jest Debug",
  "program": "${workspaceFolder}/node_modules/.bin/jest",
  "args": ["--runInBand", "--no-cache"],
  "console": "integratedTerminal"
}
```

### Playwright Debug

```bash
# Open Playwright UI
npm run test:e2e:ui

# Debug mode
PWDEBUG=1 npm run test:e2e

# Run specific test
npx playwright test membership-flows.spec.ts
```

## Test Data

Use fixtures from `__tests__/fixtures/testData.ts`:

```typescript
import { mockBottles, createMockBottle } from '../fixtures/testData';

// Use existing mock
const bottle = mockBottles[0];

// Create custom mock
const customBottle = createMockBottle({ vintage: 2015 });
```

## Security Testing Checklist

- [ ] SQL Injection prevention
- [ ] XSS prevention
- [ ] CSRF protection
- [ ] Rate limiting
- [ ] Input validation
- [ ] Authentication
- [ ] Authorization
- [ ] File upload validation
- [ ] Header injection prevention

## Performance Testing Checklist

- [ ] API response time < 500ms
- [ ] Database queries < 10ms
- [ ] Memory leak detection
- [ ] Concurrent request handling
- [ ] Load testing (100+ users)
- [ ] Stress testing (burst traffic)

## E2E Testing Checklist

- [ ] Happy path flows
- [ ] Error handling
- [ ] Mobile responsiveness
- [ ] Accessibility (ARIA, keyboard nav)
- [ ] Cross-browser compatibility
- [ ] Network error handling

## CI/CD Integration

Tests automatically run on:
- Push to `main` or `develop`
- Pull requests
- Manual workflow dispatch

View results in GitHub Actions tab.

## Common Issues & Solutions

### Issue: Tests timeout
```typescript
jest.setTimeout(10000); // Increase timeout
```

### Issue: Module not found
```typescript
// Check moduleNameMapper in jest.config.js
moduleNameMapper: {
  '^@/(.*)$': '<rootDir>/$1',
}
```

### Issue: Async test fails
```typescript
// Always await async operations
await expect(asyncFn()).resolves.toBe(true);
```

### Issue: E2E test flaky
```typescript
// Use waitFor instead of waitForTimeout
await page.waitForSelector('[data-testid="element"]');
```

## Best Practices

1. **Test Naming**: Use descriptive names
   - Good: `should validate email format correctly`
   - Bad: `test1`

2. **Test Independence**: Each test should run independently
   ```typescript
   beforeEach(() => {
     // Reset state
   });
   ```

3. **Don't Test Implementation**: Test behavior, not internals
   ```typescript
   // Good
   expect(result).toBe('success');

   // Bad
   expect(internalState.value).toBe(123);
   ```

4. **Keep Tests Simple**: One concept per test
5. **Use Test Data Factories**: Consistent, reusable test data
6. **Mock External Dependencies**: Don't hit real APIs
7. **Test Edge Cases**: Empty strings, null, undefined, extreme values

## Resources

- Full docs: `/TEST_SUITE_DOCUMENTATION.md`
- Test helpers: `/__tests__/helpers/testUtils.ts`
- Fixtures: `/__tests__/fixtures/testData.ts`
- CI/CD: `/.github/workflows/test-automation.yml`

## Getting Help

1. Check test documentation
2. Review existing tests for patterns
3. Check CI/CD logs for failures
4. Use `npm run test:e2e:ui` for E2E debugging

---

**Happy Testing!** 🧪