- Updated AGENTS.md with CouchDB references throughout - Updated TESTING.md to reflect CouchDB testing utilities - Updated TESTING_QUICK_START.md with CouchDB terminology - Updated TEST_IMPLEMENTATION_SUMMARY.md for CouchDB architecture - Updated IMPLEMENTATION_SUMMARY.md to include CouchDB migration - Created comprehensive COUCHDB_MIGRATION_GUIDE.md with: - Migration benefits and architecture changes - Step-by-step migration process - Data model conversions - Design document setup - Testing updates - Deployment configurations - Performance optimizations - Monitoring and troubleshooting All MongoDB references replaced with CouchDB equivalents while maintaining existing document structure and technical accuracy. 🤖 Generated with AI Assistant Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
14 KiB
Testing Documentation
Comprehensive testing infrastructure for the Adopt-a-Street application.
Table of Contents
- Overview
- Backend Testing
- Frontend Testing
- Running Tests
- Coverage Reports
- Test Structure
- Best Practices
- 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
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 adoptiontasks.test.js- Task management operationsposts.test.js- Social feed post operationsevents.test.js- Community event managementrewards.test.js- Points and rewards systemreports.test.js- Street condition reporting
Model Tests (__tests__/models/)
User.test.js- User model validation and relationshipsStreet.test.js- Street model with GeoJSON locationTask.test.js- Task model validationPost.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
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 submissionRegister.test.js- Registration form validationErrorBoundary.test.js- Error handling component
Integration Tests (src/__tests__/)
auth-flow.integration.test.js- Complete authentication flows
Example Frontend Test
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
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
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:
# 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:
{
"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:
# 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
- Use Test Helpers: Leverage
testHelpers.jsfor consistent test data creation - Isolate Tests: Each test should be independent and not rely on other tests
- Mock External Services: Mock Cloudinary, Stripe, and other external APIs
- Test Error Cases: Don't just test happy paths, test error handling
- Use Descriptive Names: Test names should clearly describe what they test
- Clean Up: The test setup automatically cleans up between tests
Frontend Testing
- Test User Behavior: Focus on how users interact with components
- Use MSW for API Mocking: Don't mock axios directly, use MSW handlers
- Test Accessibility: Use semantic queries (getByRole, getByLabelText)
- Avoid Implementation Details: Test what users see, not component internals
- Use waitFor for Async: Always use waitFor for asynchronous operations
- Mock External Libraries: Mock Leaflet, Socket.IO, and other heavy libraries
Writing New Tests
Backend Route Test Template
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
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:
# Increase timeout in jest.config.js
testTimeout: 30000 // 30 seconds
MSW Not Intercepting Requests
Ensure MSW server is set up in setupTests.js:
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:
import { BrowserRouter } from 'react-router-dom';
render(
<BrowserRouter>
<YourComponent />
</BrowserRouter>
);
Auth Context Not Found
Provide AuthContext in tests:
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:
jest.mock('react-leaflet', () => ({
MapContainer: ({ children }) => <div data-testid="map">{children}</div>,
TileLayer: () => null,
Marker: () => null,
Popup: () => null,
}));
Performance Tips
-
Run specific test files:
bun test -- auth.test.js -
Run tests matching pattern:
bun test -- --testNamePattern="login" -
Skip tests during development:
describe.skip('Skip this suite', () => { /* ... */ }); it.skip('Skip this test', () => { /* ... */ }); -
Run only specific tests:
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
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