# 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 + MongoDB Memory Server - **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 - **MongoDB Memory Server**: In-memory MongoDB 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: ['/__tests__/setup.js'], testTimeout: 30000, verbose: true }; ``` #### `backend/__tests__/setup.js` Sets up MongoDB Memory Server for all tests: - Creates in-memory MongoDB instance before all tests - Clears collections 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( ); 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(); const button = screen.getByRole('button', { name: /submit/i }); fireEvent.click(button); await waitFor(() => { expect(screen.getByText(/success/i)).toBeInTheDocument(); }); }); }); ``` ## Troubleshooting ### Common Issues #### MongoDB Memory Server Timeout If tests timeout with MongoDB Memory Server: ```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( ); ``` #### 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( ); ``` #### Leaflet Map Errors Mock react-leaflet in tests: ```javascript jest.mock('react-leaflet', () => ({ MapContainer: ({ children }) =>
{children}
, 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/) - [MongoDB Memory Server](https://github.com/nodkz/mongodb-memory-server) - [Testing Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)