Test Plan & Coverage - bounswe/bounswe2026group4 GitHub Wiki

Test Plan & Coverage

Table of Contents


1. Overview

This document defines the testing strategy, test plan, and acceptance criteria for the Local History Story Map project. The project follows a monorepo structure with a Django REST Framework backend, a React (Vite) frontend, and a React Native mobile app.

Testing Philosophy:

  • Every feature must include unit tests (enforced via PR checklist)
  • Tests must pass locally before opening a pull request
  • CI pipeline gates merges on test results

2. Testing Strategy

2.1 Test Pyramid

We follow the standard test pyramid approach, prioritizing a large base of fast unit tests, supported by integration and API tests, with end-to-end tests covering critical user flows.

Level Scope What We Test Tools
Unit Tests Individual functions, models, serializers, validators, components Business logic correctness in isolation pytest (backend), Vitest (frontend)
Integration / API Tests API endpoints, service layer, multi-model interactions Data flow between layers, HTTP contracts, error responses pytest + DRF APIClient (backend), Vitest + mocked services (frontend)
E2E Tests Full user flows across frontend and backend Critical user journeys work end-to-end Playwright (planned)

2.2 Testing Principles

  1. Isolation: Each test is independent. State is reset between tests using setup_method (backend) and beforeEach (frontend).
  2. Real Database: Backend tests run against a real MySQL 8.0 instance (via pytest-django), not mocks. This catches migration and constraint issues early.
  3. Fast Test Execution: Test settings use MD5PasswordHasher instead of production-grade hashers to keep the suite fast, and locmem.EmailBackend for in-memory email.
  4. DOM Simulation: Frontend tests run in a jsdom environment, simulating browser behavior without a real browser.
  5. User-Centric Frontend Tests: Frontend tests interact with components the way a real user would — via labels, roles, and visible text — following Testing Library best practices.
  6. Mock External Dependencies: API service calls in the frontend are mocked at the module level so component tests remain isolated from the backend.

2.3 What Gets Tested at Each Layer

Backend Layer What to Test
Models Object creation, defaults, constraints, relationships, signals, validation, ordering
Serializers Field validation, required/optional fields, duplicate detection, write-only behavior
Services Business logic orchestration, error handling, edge cases
Views/API HTTP status codes, response payloads, authentication/authorization, error formats
Permissions Role-based access (guest, registered user, admin, owner)
Utilities Custom validators, exception handlers, shared helpers
Frontend Layer What to Test
Pages Rendering, form validation, API submission, loading/error states, navigation
Components Prop rendering, user interactions, accessibility attributes
Services API call correctness (tested indirectly through page mocks or directly)

3. Testing Frameworks & Tools

3.1 Backend

Tool Purpose
pytest + pytest-django Test runner with Django integration (DB access, settings, fixtures)
factory-boy Model factory library for consistent test data generation
coverage Code coverage measurement and reporting
unittest.mock Mocking for isolated unit tests that don't need the database

Configuration (backend/pytest.ini):

[pytest]
addopts = --ds=config.settings.test
python_files = tests/test_*.py
python_classes = Test*
python_functions = test_*

Test settings (backend/config/settings/test.py):

  • DEBUG = False — mirrors production behavior
  • Strips debug_toolbar from apps and middleware
  • Uses in-memory email backend
  • Uses fast password hasher for speed

3.2 Frontend

Tool Purpose
vitest Test runner integrated with Vite build system
@testing-library/react Component rendering and DOM querying
@testing-library/user-event Realistic user interaction simulation
@testing-library/jest-dom Custom DOM assertion matchers (e.g., toBeInTheDocument())
jsdom Browser DOM environment for Node.js

Configuration (in frontend/vite.config.js):

test: {
  globals: true,
  environment: "jsdom",
  setupFiles: "./src/test/setup.js",
  css: true,
}

3.3 Commands

Action Command
Run backend tests cd backend && pytest -v
Run frontend tests (watch mode) cd frontend && npm test
Run frontend tests (single run, CI) cd frontend && npm run test:run
Run frontend lint cd frontend && npm run lint

4. Test Architecture

4.1 Backend Test Organization

Each Django app follows a consistent test structure:

backend/
├── conftest.py                    # Shared fixtures (user, story, etc.)
├── <app>/
│   └── tests/
│       ├── test_models.py         # Model layer tests
│       ├── test_serializers.py    # Serializer validation tests
│       ├── test_services.py       # Business logic / service layer tests
│       ├── test_views.py          # API endpoint / view tests
│       └── test_permissions.py    # Permission class tests
└── common/
    └── tests/
        ├── test_exceptions.py     # Custom exception handler tests
        ├── test_validators.py     # Shared validator tests
        └── test_permissions.py    # Shared permission class tests

Apps with test coverage: users, stories, interactions, gamification, media, notifications, reports, tags, common

4.2 Frontend Test Organization

Frontend tests are co-located with the code they test using a __tests__/ directory convention:

frontend/src/
├── test/
│   └── setup.js                   # Global test setup (jest-dom matchers)
├── pages/
│   └── __tests__/
│       └── <PageName>.test.jsx    # Page-level tests
├── components/
│   └── __tests__/
│       └── <Component>.test.jsx   # Component-level tests
└── services/
    └── __tests__/
        └── <service>.test.js      # Service-level tests

4.3 Shared Fixtures & Helpers

Backend: A global conftest.py provides reusable pytest fixtures for common entities (users, stories). Each app may define local helper functions for creating test data specific to its domain.

Frontend: Each test file defines render helpers that wrap components with required providers (e.g., BrowserRouter) and form-fill helpers to reduce boilerplate. API services and router hooks are mocked using vi.mock().


5. Backend Test Plan

5.1 Model Layer

Every Django app must have model tests covering:

Category What's Verified
Creation Objects can be created with required fields
Defaults Default values are applied correctly (status, counters, flags)
Constraints Unique constraints, required fields, validation rules
Relationships ForeignKey behavior (CASCADE, SET_NULL), OneToOne links
Signals Side effects triggered on save/delete (e.g., counter updates)
Validation clean() methods, regex validators, custom validators
Ordering Default queryset ordering

5.2 Serializer Layer

Serializer tests validate the contract between API input/output and internal models:

  • Required vs. optional field enforcement
  • Input validation rules (email format, password strength, uniqueness)
  • Write-only fields are excluded from responses
  • Nested serializer behavior

5.3 Service Layer

Service tests verify business logic orchestration:

  • Correct model creation and mutation
  • Password hashing and token generation
  • Error handling for invalid inputs and edge cases
  • Anti-enumeration patterns (e.g., login does not reveal whether an email exists)

5.4 API / View Layer

View tests validate the HTTP contract of each endpoint:

What to Test Example
Success responses Correct status code (200, 201, 204) and payload structure
Client errors 400 for validation failures, 409 for conflicts
Auth errors 401 for unauthenticated, 403 for forbidden
Data persistence Created objects exist in the database after POST
Security Sensitive fields (passwords) excluded from responses

5.5 Permission & Utility Tests

  • Every custom permission class is tested with all role combinations (guest, authenticated, owner, admin)
  • Custom exception handlers are tested to ensure consistent error response format
  • Shared validators (e.g., password strength) are tested with valid, invalid, and edge-case inputs

6. Frontend Test Plan

6.1 Page Tests

Each page component is tested for:

Category What's Verified
Rendering All expected form fields, buttons, and text render correctly
Validation Client-side validation messages appear for invalid inputs
Submission Successful form submission calls the correct API with correct data
Loading State UI is disabled / shows loading indicator during API calls
Error Handling API error messages are displayed to the user
Navigation Page redirects correctly on success; links navigate to expected routes
Accessibility Error messages use role="alert", elements are queryable by label/role

6.2 Component Tests

Shared UI components are tested for:

  • Correct rendering based on props
  • User interaction behavior (click, toggle, hover)
  • Accessibility attributes (ARIA labels, roles)

6.3 Frontend Testing Patterns

  • Mocking Strategy: API service calls are mocked at the module level (vi.mock); router hooks are mocked to test navigation without real routing
  • User Event Simulation: All interactions use @testing-library/user-event for realistic event sequences (type, click, clear)
  • Accessibility-First Queries: Tests query elements by role, labelText, and text rather than CSS selectors or test IDs

7. CI/CD Integration

7.1 Pipeline Overview (.github/workflows/ci.yml)

The CI pipeline runs automatically on pushes to main and pull requests targeting main. It consists of two parallel jobs:

┌─────────────────────────────────┐  ┌─────────────────────────────────┐
│  backend-tests                  │  │  frontend-checks                │
│  ─────────────                  │  │  ────────────────                │
│  • Ubuntu latest, Python 3.12   │  │  • Ubuntu latest, Node.js 20    │
│  • MySQL 8.0 service container  │  │  • npm ci                       │
│  • pip install requirements     │  │  • npm run lint                  │
│  • pytest -v                    │  │  • npm run test:run              │
│                                 │  │  • npm run build                 │
└─────────────────────────────────┘  └─────────────────────────────────┘

7.2 CI Rules

  • All backend tests must pass before a PR can be merged
  • All frontend lint checks, tests, and builds must pass before a PR can be merged
  • New features must include corresponding tests — PRs without tests will be flagged during review

8. Core Use Case Scenarios

This section defines the end-to-end user journeys the application must successfully handle. Each scenario represents a critical user flow that must be validated through a combination of unit, integration, and (where applicable) E2E tests.

8.1 Scenario 1: Guest Browses Stories on the Map

Actor: Unregistered visitor Goal: Discover local history stories by exploring a map

Step Action Test Approach
1 Guest opens the application Frontend: page renders without auth
2 Map view loads with story pins Backend: story list API returns published stories; Frontend: map component renders pins
3 Guest clicks a pin to see preview popup Frontend: popup displays title, place, time
4 Guest opens the full story page Backend: story detail API; Frontend: full page renders narrative + metadata
5 Guest views comments (read-only) Backend: comment list API; Frontend: comments section visible, submit hidden
6 Guest switches to Feed view Frontend: feed renders story cards sorted by most recent
7 Guest searches by title or location Backend: search API; Frontend: results update dynamically
8 Guest filters by time period Backend: filter API; Frontend: filter controls apply correctly

8.2 Scenario 2: User Registers, Logs In, and Creates a Story

Actor: New user Goal: Create an account, log in, and submit a local history story

Step Action Test Approach
1 User opens registration page Frontend: form renders all fields
2 User submits valid registration data Backend: user created (201), password hashed; Frontend: navigates to login
3 Registration rejected for duplicate email/username Backend: 409 response; Frontend: error displayed
4 Registration rejected for weak password Backend: 400 response; Frontend: validation messages shown
5 User logs in with credentials Backend: JWT tokens returned (200); Frontend: navigates to home
6 Login rejected for wrong credentials Backend: 401 (anti-enumeration); Frontend: generic error shown
7 User fills in story submission form Frontend: title, narrative, map pin, time info fields work
8 User uploads an image Backend: media stored; Frontend: preview shown
9 Story created and visible on map/feed Backend: story persisted with correct data; Frontend: appears in listings

8.3 Scenario 3: User Interacts with Stories (Like, Comment)

Actor: Registered, logged-in user Goal: Engage with stories through likes and comments

Step Action Test Approach
1 User opens a story page Frontend: interaction buttons visible for authenticated user
2 User likes a story Backend: like created, like_count incremented; Frontend: UI reflects liked state
3 User unlikes the story Backend: like removed, like_count decremented; Frontend: UI reverts
4 User submits a comment Backend: comment created; Frontend: comment appears in list
5 User deletes own comment Backend: comment removed; Frontend: comment disappears

8.4 Scenario 4: User Views and Manages Profile

Actor: Registered user Goal: View profile with username, contribution count, and submitted stories

Step Action Test Approach
1 User navigates to profile page Frontend: profile renders user info
2 Profile displays username and contribution count Backend: profile API returns correct data
3 Profile shows submitted stories list Backend: user stories API; Frontend: stories render as cards
4 Privacy settings are respected Backend: permission checks; Frontend: private fields hidden

8.5 Scenario 5: User Logs Out

Actor: Logged-in user Goal: Securely end session

Step Action Test Approach
1 User clicks logout Backend: refresh token blacklisted (205); Frontend: redirected to login
2 Protected routes inaccessible after logout Backend: 401 for blacklisted token; Frontend: auth guard redirects

8.6 Scenario 6: Search and Filter Stories

Actor: Any user (guest or registered) Goal: Find specific stories by title, location, or time period

Step Action Test Approach
1 User enters a search term Backend: search API filters by title/location; Frontend: results update
2 User applies time period filter Backend: filter by year/decade; Frontend: filter controls work
3 User applies location filter Backend: location-based filtering; Frontend: map updates
4 Combined filters return correct results Backend: multiple filters combine correctly; Frontend: UI consistent

9. User Acceptance Criteria

9.1 Per-PR Acceptance Criteria

Every pull request must satisfy these criteria (enforced via PR template):

  • Project builds successfully
  • Code follows the style guidelines of this project
  • Hard-to-understand parts are commented
  • Self-review has been performed
  • Tests have been added or updated for the change
  • New and existing unit tests pass locally

9.2 Per-Feature Acceptance Criteria

Authentication & User Management

Criteria
User can register with valid email, username, and password
Registration rejects duplicate email/username
Registration enforces password strength (8+ chars, uppercase, lowercase, digit)
Registration rejects mismatched passwords
User can log in with valid credentials and receives JWT tokens
Login does not leak user existence (anti-enumeration)
User can log out and token is invalidated
Protected routes are inaccessible without valid authentication

Stories

Criteria
Story can be created with title, narrative, location, and time information
Story supports all time types (exact year, year range, decade, approximate)
Story supports image upload (.jpg, .png, max 2MB)
Published stories are visible on the map and feed views
Story detail page displays full narrative, metadata, and media
Deleting a user does not delete their stories (author set to NULL)

Interactions (Comments, Likes, Saves)

Criteria
Registered user can like and unlike a story
Like/unlike correctly updates the story's like count
Registered user can comment on a story
User can delete their own comment
Duplicate likes/saves per user are prevented
Registered user can save/bookmark a story

Profile

Criteria
User profile displays username, contribution count, and submitted stories
Profile privacy settings control field visibility
Only profile owner or admin can edit profile

Search & Filtering

Criteria
Users can search stories by title and location name
Users can filter stories by time period (year/decade)
Search and filters work across map, feed, and timeline views

Tags

Criteria
Tags follow format validation (lowercase, hyphens, no spaces/special chars)
Stories can have up to 3 tags
Users can browse and filter stories by tag

Gamification

Criteria
Points are awarded for publishing stories, receiving likes, comments, and saves
Badges are awarded based on defined criteria (registration, milestones)
Each user can earn a given badge only once
Total points are displayed on the user profile

Notifications

Criteria
Users receive notifications for likes, comments, moderation actions, and badges
Notification preferences can be configured per user
Unread notification count is displayed

Reporting & Moderation

Criteria
Users can report stories and comments with a reason
A user cannot submit duplicate reports on the same content
Admins can review reports and take action (remove content, ban users)

Media

Criteria
Image, audio, and video uploads are supported
Media files are associated with stories and cascade-deleted with them
Media playback works on story detail pages

⚠️ **GitHub.com Fallback** ⚠️