# Testing Documentation

Comprehensive testing infrastructure for the Adopt-a-Street application.

## Table of Contents

1. [Overview](#overview)
2. [Backend Testing](#backend-testing)
3. [Frontend Testing](#frontend-testing)
4. [Running Tests](#running-tests)
5. [Coverage Reports](#coverage-reports)
6. [Test Structure](#test-structure)
7. [Best Practices](#best-practices)
8. [Troubleshooting](#troubleshooting)

## Overview

The Adopt-a-Street application uses a comprehensive testing strategy covering both backend and frontend:

- **Backend**: Jest + Supertest + CouchDB testing utilities
- **Frontend**: React Testing Library + Jest + MSW (Mock Service Worker)
- **Current Coverage**:
  - Backend: ~55% statement coverage (109 passing tests)
  - Frontend: MSW infrastructure in place with component tests

## Backend Testing

### Test Infrastructure

The backend uses:
- **Jest**: Test runner and assertion library
- **Supertest**: HTTP assertions for API endpoint testing
- **CouchDB Testing Utilities**: In-memory CouchDB for isolated testing
- **Cross-env**: Environment variable management

### Setup Files

#### `backend/jest.config.js`

```javascript
module.exports = {
  testEnvironment: 'node',
  coverageDirectory: 'coverage',
  collectCoverageFrom: [
    'routes/**/*.js',
    'middleware/**/*.js',
    'models/**/*.js',
    '!**/node_modules/**',
    '!**/coverage/**'
  ],
  testMatch: [
    '**/__tests__/**/*.test.js',
    '**/?(*.)+(spec|test).js'
  ],
  coverageThreshold: {
    global: {
      branches: 70,
      functions: 70,
      lines: 70,
      statements: 70
    }
  },
  setupFilesAfterEnv: ['<rootDir>/__tests__/setup.js'],
  testTimeout: 30000,
  verbose: true
};
```

#### `backend/__tests__/setup.js`

Sets up CouchDB testing utilities for all tests:
- Creates in-memory CouchDB instance before all tests
- Clears documents after each test
- Closes connections after all tests
- Suppresses console logs during tests

### Test Files

#### Route Tests (`__tests__/routes/`)

- `auth.test.js` - Authentication endpoints (register, login, get user)
- `streets.test.js` - Street CRUD operations and adoption
- `tasks.test.js` - Task management operations
- `posts.test.js` - Social feed post operations
- `events.test.js` - Community event management
- `rewards.test.js` - Points and rewards system
- `reports.test.js` - Street condition reporting

#### Model Tests (`__tests__/models/`)

- `User.test.js` - User model validation and relationships
- `Street.test.js` - Street model with GeoJSON location
- `Task.test.js` - Task model validation
- `Post.test.js` - Post model with likes and comments

#### Middleware Tests (`__tests__/middleware/`)

- `auth.test.js` - JWT authentication middleware

#### Test Helpers (`__tests__/utils/`)

`testHelpers.js` provides utilities for:
- Creating test users with JWT tokens
- Creating test streets, tasks, posts, events, rewards, reports
- Database cleanup utilities

### Example Backend Test

```javascript
const request = require('supertest');
const express = require('express');
const authRoutes = require('../../routes/auth');
const { createTestUser } = require('../utils/testHelpers');

const app = express();
app.use(express.json());
app.use('/api/auth', authRoutes);

describe('Auth Routes', () => {
  it('should register a new user', async () => {
    const response = await request(app)
      .post('/api/auth/register')
      .send({
        name: 'John Doe',
        email: 'john@example.com',
        password: 'password123',
      })
      .expect(200);

    expect(response.body).toHaveProperty('token');
  });
});
```

## Frontend Testing

### Test Infrastructure

The frontend uses:
- **React Testing Library**: Component testing utilities
- **Jest**: Test runner (via react-scripts)
- **MSW (Mock Service Worker)**: API mocking
- **@testing-library/user-event**: User interaction simulation

### Setup Files

#### `frontend/src/setupTests.js`

- Configures Jest-DOM matchers
- Sets up MSW server for API mocking
- Mocks localStorage and window.matchMedia
- Suppresses expected console warnings

#### `frontend/src/mocks/handlers.js`

Defines MSW handlers for all API endpoints:
- Authentication (register, login, get user)
- Streets (list, adopt)
- Tasks (list, create, complete)
- Posts (list, create, like)
- Events (list, create, RSVP)
- Rewards (list, redeem)
- Users (get, update)

### Test Files

#### Component Tests (`src/components/__tests__/`)

- `Login.test.js` - Login form validation and submission
- `Register.test.js` - Registration form validation
- `ErrorBoundary.test.js` - Error handling component

#### Integration Tests (`src/__tests__/`)

- `auth-flow.integration.test.js` - Complete authentication flows

### Example Frontend Test

```javascript
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import Login from '../Login';
import { AuthContext } from '../../context/AuthContext';

describe('Login Component', () => {
  it('should render login form', () => {
    render(
      <BrowserRouter>
        <AuthContext.Provider value={mockContext}>
          <Login />
        </AuthContext.Provider>
      </BrowserRouter>
    );

    expect(screen.getByPlaceholderText(/email/i)).toBeInTheDocument();
    expect(screen.getByPlaceholderText(/password/i)).toBeInTheDocument();
  });
});
```

## Running Tests

### Backend Tests

```bash
cd backend

# Run all tests
bun test

# Run tests in watch mode
bun run test:watch

# Run tests with coverage
bun run test:coverage

# Run tests with verbose output
bun run test:verbose
```

### Frontend Tests

```bash
cd frontend

# Run all tests (interactive watch mode)
bun test

# Run tests with coverage
bun run test:coverage

# Run tests in watch mode
bun run test:watch
```

### Run All Tests

From the project root:

```bash
# Backend
cd backend && bun test

# Frontend
cd frontend && bun test
```

## Coverage Reports

### Backend Coverage

Current coverage (as of last run):

```
-----------------------|---------|----------|---------|---------|
File                   | % Stmts | % Branch | % Funcs | % Lines |
-----------------------|---------|----------|---------|---------|
All files              |   54.75 |    32.23 |   62.66 |   54.85 |
 middleware            |   40.24 |    21.05 |   45.45 |    39.5 |
  auth.js              |     100 |      100 |     100 |     100 |
 models                |    82.5 |    66.66 |      50 |    82.5 |
 routes                |   45.84 |    22.61 |   60.97 |   46.07 |
-----------------------|---------|----------|---------|---------|
```

**Test Results**: 109 passing, 67 failing (schema mismatches)

Key Coverage Areas:
- ✅ Auth middleware: 100% coverage
- ✅ Model validators: 82.5% coverage
- ⚠️ Routes: 45.84% coverage (room for improvement)
- ⚠️ Other middleware: 40.24% coverage

### Frontend Coverage

Coverage configuration in `package.json`:

```json
{
  "coverageThreshold": {
    "global": {
      "branches": 50,
      "functions": 60,
      "lines": 60,
      "statements": 60
    }
  }
}
```

Coverage reports are generated in:
- Backend: `backend/coverage/`
- Frontend: `frontend/coverage/`

To view HTML coverage reports:

```bash
# Backend
cd backend && bun test -- --coverage
open coverage/lcov-report/index.html

# Frontend
cd frontend && bun run test:coverage
open coverage/lcov-report/index.html
```

## Test Structure

### Backend Test Organization

```
backend/
├── __tests__/
│   ├── setup.js                 # Global test setup
│   ├── middleware/
│   │   └── auth.test.js         # Middleware tests
│   ├── models/
│   │   ├── User.test.js         # Model tests
│   │   ├── Street.test.js
│   │   ├── Task.test.js
│   │   └── Post.test.js
│   ├── routes/
│   │   ├── auth.test.js         # Route tests
│   │   ├── streets.test.js
│   │   ├── tasks.test.js
│   │   ├── posts.test.js
│   │   ├── events.test.js
│   │   ├── rewards.test.js
│   │   └── reports.test.js
│   └── utils/
│       └── testHelpers.js       # Test utilities
└── jest.config.js               # Jest configuration
```

### Frontend Test Organization

```
frontend/src/
├── setupTests.js                # Global test setup
├── mocks/
│   ├── handlers.js              # MSW API handlers
│   └── server.js                # MSW server setup
├── __tests__/
│   └── auth-flow.integration.test.js  # Integration tests
└── components/
    └── __tests__/
        ├── Login.test.js        # Component tests
        ├── Register.test.js
        └── ErrorBoundary.test.js
```

## Best Practices

### Backend Testing

1. **Use Test Helpers**: Leverage `testHelpers.js` for consistent test data creation
2. **Isolate Tests**: Each test should be independent and not rely on other tests
3. **Mock External Services**: Mock Cloudinary, Stripe, and other external APIs
4. **Test Error Cases**: Don't just test happy paths, test error handling
5. **Use Descriptive Names**: Test names should clearly describe what they test
6. **Clean Up**: The test setup automatically cleans up between tests

### Frontend Testing

1. **Test User Behavior**: Focus on how users interact with components
2. **Use MSW for API Mocking**: Don't mock axios directly, use MSW handlers
3. **Test Accessibility**: Use semantic queries (getByRole, getByLabelText)
4. **Avoid Implementation Details**: Test what users see, not component internals
5. **Use waitFor for Async**: Always use waitFor for asynchronous operations
6. **Mock External Libraries**: Mock Leaflet, Socket.IO, and other heavy libraries

### Writing New Tests

#### Backend Route Test Template

```javascript
const request = require('supertest');
const express = require('express');
const yourRoute = require('../../routes/your-route');
const { createTestUser } = require('../utils/testHelpers');

const app = express();
app.use(express.json());
app.use('/api/your-route', yourRoute);

describe('Your Route', () => {
  describe('GET /api/your-route', () => {
    it('should do something', async () => {
      const { token } = await createTestUser();

      const response = await request(app)
        .get('/api/your-route')
        .set('x-auth-token', token)
        .expect(200);

      expect(response.body).toMatchObject({ /* expected shape */ });
    });
  });
});
```

#### Frontend Component Test Template

```javascript
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import YourComponent from '../YourComponent';

describe('YourComponent', () => {
  it('should render and work', async () => {
    render(<YourComponent />);

    const button = screen.getByRole('button', { name: /submit/i });
    fireEvent.click(button);

    await waitFor(() => {
      expect(screen.getByText(/success/i)).toBeInTheDocument();
    });
  });
});
```

## Troubleshooting

### Common Issues

#### CouchDB Testing Timeout

If tests timeout with CouchDB testing utilities:

```bash
# Increase timeout in jest.config.js
testTimeout: 30000  // 30 seconds
```

#### MSW Not Intercepting Requests

Ensure MSW server is set up in `setupTests.js`:

```javascript
import { server } from './mocks/server';

beforeAll(() => server.listen({ onUnhandledRequest: 'warn' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
```

#### React Router Errors in Tests

Wrap components with BrowserRouter:

```javascript
import { BrowserRouter } from 'react-router-dom';

render(
  <BrowserRouter>
    <YourComponent />
  </BrowserRouter>
);
```

#### Auth Context Not Found

Provide AuthContext in tests:

```javascript
import { AuthContext } from '../../context/AuthContext';

const mockAuthContext = {
  auth: { isAuthenticated: false, loading: false, user: null },
  login: jest.fn(),
};

render(
  <AuthContext.Provider value={mockAuthContext}>
    <YourComponent />
  </AuthContext.Provider>
);
```

#### Leaflet Map Errors

Mock react-leaflet in tests:

```javascript
jest.mock('react-leaflet', () => ({
  MapContainer: ({ children }) => <div data-testid="map">{children}</div>,
  TileLayer: () => null,
  Marker: () => null,
  Popup: () => null,
}));
```

### Performance Tips

1. **Run specific test files**:
   ```bash
   bun test -- auth.test.js
   ```

2. **Run tests matching pattern**:
   ```bash
   bun test -- --testNamePattern="login"
   ```

3. **Skip tests during development**:
   ```javascript
   describe.skip('Skip this suite', () => { /* ... */ });
   it.skip('Skip this test', () => { /* ... */ });
   ```

4. **Run only specific tests**:
   ```javascript
   describe.only('Run only this suite', () => { /* ... */ });
   it.only('Run only this test', () => { /* ... */ });
   ```

## Future Improvements

### Backend

- [ ] Increase route coverage to 70%+
- [ ] Add tests for Socket.IO events
- [ ] Add tests for file upload (Multer)
- [ ] Add tests for AI route
- [ ] Add tests for payments route
- [ ] Add performance/load tests
- [ ] Add E2E tests with real database

### Frontend

- [ ] Add tests for all remaining components:
  - MapView
  - TaskList
  - SocialFeed
  - Events
  - Profile
  - Premium
  - Rewards
- [ ] Add integration tests for complete user flows
- [ ] Add accessibility tests (jest-axe)
- [ ] Add visual regression tests (Percy/Chromatic)
- [ ] Add E2E tests (Playwright/Cypress)
- [ ] Increase coverage to 60%+

## CI/CD Integration

To integrate tests into CI/CD pipeline:

### GitHub Actions Example

```yaml
name: Tests

on: [push, pull_request]

jobs:
  backend-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
      - run: cd backend && bun install
      - run: cd backend && bun test -- --coverage

  frontend-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
      - run: cd frontend && bun install
      - run: cd frontend && bun run test:coverage
```

## Resources

- [Jest Documentation](https://jestjs.io/)
- [React Testing Library](https://testing-library.com/react)
- [Supertest](https://github.com/visionmedia/supertest)
- [MSW Documentation](https://mswjs.io/)
- [CouchDB Testing Utilities](https://github.com/apache/couchdb/tree/main/test)
- [Testing Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
