Test Plan and Coverage - bounswe/bounswe2026group9 GitHub Wiki

Test Plan & Coverage

Testing Strategy

Our project has three main components: a Python/FastAPI backend, a Next.js (TypeScript) web frontend, and a Kotlin Android mobile app. Each has its own testing strategy tailored to its role.

Backend Testing Strategy

Our backend testing strategy is integration-first: all tests run against a real Supabase (PostgreSQL) database — no mocks for data access, no SQLite stubs. This ensures tests validate actual behavior including constraints, cascades, and query semantics. We mock only external side-effects (email sending, cloud storage uploads, Google OAuth callbacks) to keep tests deterministic and fast.

Test types used:

Type Purpose Example
Unit tests Isolated logic (hashing, JWT encode/decode, datetime validation) TestPassword, TestJWT in test_auth_unit.py; TestValidateEventDatetime in test_event_unit.py; TestGetAffectedUserIds, TestEmitEventNotification in test_notification_emitter_unit.py
API integration tests Full HTTP request → router → service → repository → DB round-trip All endpoint tests (test_events.py, test_discovery.py, test_categories.py, test_images.py, test_comments.py, test_invites.py, test_notifications.py, test_attendances.py, test_bookmarks.py, test_users.py)
Multi-step flow tests End-to-end user journeys spanning multiple endpoints TestFullAuthFlow, TestRefreshTokenRotation, TestEmailVerificationFlow in test_auth_integration.py; test_accept_invite_grants_event_access, test_approve_grants_event_access in test_invites.py

Tools & infrastructure:

  • pytest as test runner (configured in pyproject.toml)
  • FastAPI TestClient (backed by httpx) for HTTP-level testing
  • ruff for static analysis / linting (runs before tests in CI)
  • GitHub Actions CI (backend-ci.yml) — triggered on every PR touching backend/**: checkout → Python 3.12 → install deps → ruff check .pytest tests/ -v
  • Autouse fixtures for cleanup: cleanup_test_users deletes all rows matching test prefixes (testuser_, eventtest_, imgtest_, cattest_, disctest_, attndtest_, bmtest_, cmttest_, invtest_, notiftest_, proftest_) after each test — no stale data between runs
  • Mocking: unittest.mock.patch for email sending, Supabase storage upload/delete, and Google OAuth token exchange

Frontend Testing Strategy (Next.js — MVP: Manual; Automated: Final Milestone)

For the MVP milestone, the web frontend was validated through manual testing and visual inspection after each feature implementation. Every user-facing flow was exercised on the deployed application, including edge cases such as private event access, underage gate behavior, invite token acceptance, and error page rendering. No automated test framework was introduced for the MVP.

Automated tests (Jest + React Testing Library + MSW + frontend-ci.yml GitHub Actions workflow) are planned for the Final Milestone.

MVP validation approach:

Area How validated for MVP
Auth screens Manually tested registration, login, logout, duplicate email error, Google OAuth flow on live deployment
Event discovery Manually verified map/list toggle, search, category and temporal filters, pagination, guest vs. authenticated card differences
Event detail Manually tested full detail view, limited preview for guests, private event restricted view, age gate (underage block + DOB prompt), image carousel, comments, bookmark/going buttons
Event creation Manually stepped through all 7 form steps, draft save, image upload, publish flow, pre-publish validation
Private event flows Manually tested Request Access button, pending state persistence, host invite generation and copy, access request approve/reject
Profile & ratings Manually tested host profile page, hosted events list, rating submission
Notifications Manually verified in-app notification list, unread badge, mark-as-read, event update/cancellation triggers
Error pages Manually navigated to non-existent URLs (404), private events (access denied), and 18+ events as underage user

Planned automated test coverage for Final Milestone:

Type Purpose Tool
Component tests Individual UI components render with correct props and conditional logic Jest + React Testing Library
User interaction tests Simulate user actions (click, type, submit) and verify resulting UI changes React Testing Library (fireEvent / userEvent)
Navigation tests Screen transitions work correctly (e.g., login → discovery, event card → detail) Next.js routing test utilities
API integration tests API calls are made with correct parameters, responses are handled, errors are displayed Jest with MSW (Mock Service Worker)
Snapshot tests Catch unintended UI regressions across updates Jest snapshots

Planned CI: A frontend-ci.yml workflow will be added — triggered on PRs touching frontend/**: checkout → Node.js setup → npm installeslintjest --coverage.

Mobile Testing Strategy (Kotlin Android — MVP: Manual; Automated: Final Milestone)

For the MVP milestone, the Android app was validated through manual testing on emulator and physical device after each feature implementation. All screens and flows were exercised by hand, including edge cases such as the 18+ block, private event access request, invite deep link acceptance, and error page routing.

Automated tests (JUnit + MockK + Jetpack Compose Testing + android-ci.yml GitHub Actions workflow) are planned for the Final Milestone.

MVP validation approach:

Area How validated for MVP
Auth screens Manually tested registration, login, logout, token persistence (session survives app restart)
Event discovery Manually verified map/list view, search, category and temporal filters, FAB (create event, auth-only)
Event detail Manually tested full detail, limited preview for guests, private event restricted view, age gate (underage + DOB required screens), image carousel, bookmark/going buttons, comments
Event creation Manually stepped through all 7 form steps, date/time picker, image upload, draft save, publish, edit mode pre-fill, cancel and delete confirmation dialogs
Private event flows Manually tested Request Access button with pending/rejected/approved state, host invite management panel, access request approve/reject
Notifications Manually verified notification list, unread badge count in top bar, mark-as-read
Host profile Manually tested host profile page, hosted events list, rating submission
Navigation Manually tested all routes including deep link (sem://invite/{eventId}/{token}), back stack, auth guard

Planned automated test coverage for Final Milestone:

Type Purpose Tool
Unit tests ViewModel logic, repository data mapping, input validation JUnit 5 + MockK
UI tests Screen rendering, user interactions, navigation Jetpack Compose Testing + Espresso
API integration tests Retrofit/OkHttp calls constructed correctly, responses parsed, errors handled JUnit 5 + MockWebServer
Navigation tests Screen transitions, back stack behavior, deep linking Compose Navigation Testing

Planned CI: An android-ci.yml workflow will be added — triggered on PRs touching mobile/**: checkout → JDK setup → Gradle build → detekt./gradlew test./gradlew connectedAndroidTest.


Test Plan Coverage

Backend — 209 tests across 17 test files

All tests currently implemented and passing. Organized by feature area:

1. Authentication & Authorization (36 tests — test_auth.py, test_auth_integration.py, test_auth_unit.py)

Area Tests What is validated
Password hashing 3 bcrypt hash/verify, wrong password rejection, salt randomness
JWT tokens 3 Create/decode, invalid token rejection, expiry enforcement
Registration 6 Success (201), duplicate email/username (409), validation (short password, invalid email, short username — 422)
Login 5 Success (200), wrong password (401), non-existent email (401), account lockout after 5 failures (429), deactivated account (403)
Token flow 7 /me with valid/invalid/missing token, refresh via cookie, token rotation (old token revoked), logout, refresh-after-logout fails
Email verification 4 Verify valid token (200), invalid token (400), resend (200), resend-when-already-verified (400)
Integration flows 5 Full register→login→me→refresh→logout, refresh rotation, register→verify→confirm, resend→verify, expired token
Google OAuth 3 New user created, existing user linked, deactivated user rejected

2. Event CRUD & Lifecycle (49 tests — test_events.py, test_event_unit.py)

Area Tests What is validated
Create event 12 Draft creation (201), direct-publish blocked (400), venue metadata, equipment, multiple locations, invalid datetime/category (400), duplicates (409), auth required (403), missing fields (422)
Get event 6 Full detail for auth user, limited preview for guest, private event visibility (host vs. others), 404, auto-end on read
Update event 6 Title update (200), published→updated transition, non-host forbidden (403), cancelled event blocked (400), time change after start blocked (400), auth required
Status transitions 7 draft→published without image rejected (400), draft→published with image (200), published→cancelled/ended, invalid transitions (cancelled→published, draft→cancelled — 400), non-host forbidden
Delete event 5 Delete cancelled/ended (200), delete published blocked (400), non-host forbidden (403), auth required
Age restriction 3 Underage user blocked (403), missing DOB blocked, host exempt
Edge cases 5 Updated→cancelled/ended, invalid UUID (422), past start date rejected (400), clear attendee limit
Unit — datetime validation 3 Rejects past start by default, rejects end before start, allows past start when explicitly enabled
Unit — auto-end logic 2 Marks published past event as ended, leaves future event unchanged

3. Event Discovery & Search (34 tests — test_discovery.py)

Area Tests What is validated
Basic listing 9 200 without auth, response shape (items/total/page/page_size/total_pages), published appears, draft hidden, private appears with limited info, past-end-datetime excluded, cancelled excluded, auth user gets full fields, guest vs. auth field differentiation
Sort order 1 Results sorted by start_datetime ascending
Text search 5 Search by title, by description, no results, case-insensitive, excludes non-matching
Category filter 3 Matching events returned, no-match returns empty, invalid UUID rejected (422)
Temporal filter 5 upcoming, today, this_week, far-future exclusion, invalid value rejected (422)
Pagination 8 Default (page=1, size=20), custom size, max 100, min 1, second page, total_pages calculation, empty beyond-total, page=0 rejected
Combined filters 3 search + category, search + temporal, all filters together

4. Categories (9 tests — test_categories.py)

Area Tests What is validated
List 4 Returns predefined (≥15), sorted alphabetically, search by name, search no results
Create 5 Custom category (201), duplicate fails (409), no auth (403), empty name (422), custom hidden until approved

5. Image Management (10 tests — test_images.py)

Area Tests What is validated
Upload 7 JPEG (201), PNG (201), invalid format rejected (400), non-host forbidden (403), max 10 limit (400), large image resized (≤2048×2048), auth required
Delete 3 Success (200), non-host forbidden (403), nonexistent (404)

6. Comments (20 tests — test_comments.py)

Area Tests What is validated
Create comment 7 Success (201), no auth (401), empty text (422), comment on draft event blocked, comment on cancelled event blocked, nonexistent event (404), host can comment own event
List comments 7 Empty list, list with data, newest-first ordering, pagination, no auth required to read, nonexistent event (404), includes user info (username)
Delete comment 6 Owner can delete (200), host can delete others' comments, other user cannot delete (403), nonexistent comment (404), no auth (401), wrong event context

7. Invites & Access Requests (26 tests — test_invites.py)

Area Tests What is validated
Create invite 5 Success (201), invite with options (max_uses/expires_at), non-host forbidden (403), public event rejected (400), no auth (401)
Accept invite 6 Success (200), invite grants event access (full detail now visible), invalid token (400), already-granted idempotent (200), host self-accept rejected (400), max uses reached (400)
List invites 2 Host can list (200), non-host forbidden (403)
Create access request 5 Success (201), request notifies host, duplicate blocked (409), public event rejected (400), host self-request rejected (400)
List access requests 2 Host sees pending requests (200), non-host forbidden (403)
Access request decision 6 Approve grants event access, approve confirms full detail visible, deny (200), deny keeps limited access, non-host forbidden (403), already-resolved blocked (400)

8. Attendance & Capacity (1 test — test_attendances.py)

Area Tests What is validated
Attendance flow 1 Full flow: mark going, capacity enforcement (second user blocked when limit=1), remove attendance, re-mark going after capacity freed

9. Bookmarks (1 test — test_bookmarks.py)

Area Tests What is validated
Bookmark flow 1 Create bookmark (201), list bookmarks, duplicate blocked (409), delete bookmark (200), list empty after deletion

10. User Profiles & Ratings (1 test — test_users.py)

Area Tests What is validated
Profile & rating flow 1 Get host profile, rate host (201), rating reflected in profile response, self-rating blocked (400)

11. Notifications (20 tests — test_notifications.py, test_notification_emitter.py, test_notification_emitter_unit.py)

Area Tests What is validated
List notifications 6 Empty list, returns items, pagination, ordered newest-first, unauthenticated blocked (401), only own notifications returned
Mark as read 4 Mark single (200), idempotent (already read → 200), not found (404), cannot mark other user's notification
Mark all as read 3 Marks all unread (200), no unread → no-op, only affects own notifications
Emitter integration 4 Event update notifies going user, empty update does not notify, cancel notifies going user, end does not notify
Emitter unit 3 Deduplicates attendees + bookmarkers, excludes host from recipients, returns zero when no non-host recipients

12. Health Check (1 test — test_health.py)

Area Tests What is validated
System 1 GET /health returns 200 with database connectivity confirmed

Frontend (Next.js) — MVP: Manual Validation ✅ | Automated Tests: Final Milestone

For the MVP, all frontend functionality was validated manually on the deployed application after each feature was merged. Testers exercised every user flow end-to-end including edge cases (private events, underage gate, invite token, error pages). Automated test infrastructure (Jest + React Testing Library + frontend-ci.yml) will be introduced in the Final Milestone.

Estimated automated test total for Final Milestone: ~58 tests

Area Planned Tests What will be validated
Auth screens ~10 Login/registration form validation, error messages (409, 401), token storage, redirect after login, Google OAuth
Event discovery ~12 List renders from API, search filters results, category/temporal chips, pagination, empty state, guest vs. auth card differences
Event detail ~10 Full detail for auth user, limited preview for guest, private restricted view, image carousel, Going/Bookmark buttons, comments, age gate
Event creation ~8 Multi-step form navigation, required field validation, image upload preview, draft save vs. publish flow
Profile ~5 Profile info renders, hosted/past event tabs, rating display, edit form
Notifications ~4 Notification list, unread badge, mark-as-read, empty state
Navigation & routing ~5 Protected routes redirect to login, back navigation, deep links, logout clears session
Error handling ~4 404 page, access denied page, network error display, loading spinners

Mobile (Kotlin Android) — MVP: Manual Validation ✅ | Automated Tests: Final Milestone

For the MVP, all Android app functionality was validated manually on an emulator and physical device after each feature was merged to main. All screens, flows, and edge cases were exercised by hand including deep links, the 18+ gate, private event access requests, and host action dialogs. Automated test infrastructure (JUnit + MockK + Jetpack Compose Testing + android-ci.yml) will be introduced in the Final Milestone.

Estimated automated test total for Final Milestone: ~58 tests

Area Planned Tests What will be validated
Auth screens ~10 Login/registration validation, API error display, token persistence in DataStore, session restore on relaunch
Event discovery ~12 LazyColumn renders from ViewModel state, search triggers API call, filter chips update query, pagination, empty state, guest vs. auth card differences
Event detail ~10 Full detail composable, limited preview for guest, private restricted view, HorizontalPager image carousel, Going/Bookmark button calls, comment submission, age gate dialog
Event creation ~8 7-step form navigation, required field validation, date/time pickers, image picker, venue metadata, draft save vs. publish
Profile ~5 Profile screen renders, tab switching, rating bar, edit profile
Notifications ~4 Notification list, unread badge, mark-as-read, empty state
Navigation ~5 NavHost routes, auth guard, deep link (sem://invite/{eventId}/{token}), back stack
Offline / error ~4 No-network snackbar, retry, 404/403 error screens, loading shimmer

User Acceptance Criteria Mapping

Each MVP acceptance criterion is mapped to the specific tests that validate it:

MVP Acceptance Criterion Covered By Pass?
Users can register and log in TestRegister (6), TestLogin (5), TestFullAuthFlow (1)
JWT access + refresh token flow works TestTokenFlow (7), TestRefreshTokenRotation (1)
Email verification works TestEmailVerification (4), TestEmailVerificationFlow (3)
Google OAuth sign-in works TestGoogleOAuth (3)
Users can create events with all required fields TestCreateEvent (12)
Event images can be uploaded and deleted TestUploadImage (7), TestDeleteImage (3)
Events require at least one image to publish test_draft_to_published_no_image_rejected, test_draft_to_published_with_image
Event lifecycle (draft → published → updated → cancelled/ended) TestChangeEventStatus (7), TestUpdatedStatusTransitions (2)
Only host can edit/delete/change status test_update_not_host_forbidden, test_delete_not_host, test_status_change_not_host
Guest users see limited event info test_get_event_guest_limited, test_guest_sees_limited_info_auth_sees_full
Private events visible but restricted test_get_private_event_other_user_limited, test_private_event_appears_with_limited_info
Age-restricted events enforced TestAgeRestriction (3)
GET /events returns paginated published events TestListEventsBasic (9), TestListEventsPagination (8)
Text search across title and description TestListEventsSearch (5)
Category filter works TestListEventsCategoryFilter (3)
Temporal filter works (upcoming/today/this_week) TestListEventsTemporalFilter (5)
Results sorted by start_datetime test_sorted_by_start_datetime
Past-end events excluded from discovery test_past_end_datetime_not_in_listing
Category management (predefined + custom) TestListCategories (4), TestCreateCategory (5)
Auto-end events when time passes TestAutoEndEventIfPast (2)
Comments — create, list, delete TestCreateComment (7), TestListComments (7), TestDeleteComment (6)
Invite generation and acceptance TestCreateInvite (5), TestAcceptInvite (6), TestListInvites (2)
Access request flow (request → approve/reject) TestAccessRequests (5), TestAccessDecision (6)
Attendance and capacity enforcement test_attendance_and_capacity (1)
Bookmark create and delete test_create_bookmark (1)
Host profile and ratings test_user_profiles_and_ratings (1)
Notifications sent on update/cancellation TestUpdateNotification (2), TestCancelNotification (2)
Notification list, mark-as-read TestListNotifications (6), TestMarkNotificationAsRead (4), TestMarkAllAsRead (3)
CI pipeline runs lint + tests on every PR backend-ci.yml (ruff → pytest)

MVP Acceptability Criteria

The MVP is acceptable from a user perspective when these scenarios work end-to-end across both backend and frontend:

Backend (API-level validation — currently passing, 209 tests)

  1. New user onboarding: A user registers, receives a verification email, verifies their account, and logs in — receiving a JWT that authenticates all subsequent actions.

  2. Event creation flow: An authenticated user creates a draft event with title, description, category, location, date/time, and optional venue metadata. They upload at least one image, then publish. The event appears in discovery results.

  3. Event discovery: Any user (guest or registered) can browse GET /events, search by text, filter by category or time window, and paginate through results. Guests see limited fields; registered users see full details. Private events appear with restricted info. Past events are excluded.

  4. Event lifecycle management: A host can edit their published event (status becomes "updated"), cancel it (removed from discovery), or end it. Non-hosts are blocked from all management actions.

  5. Access control enforcement: Guests cannot create/edit/delete events. Private event details are hidden from non-hosts at the API level. Age-restricted events block underage users. Account lockout activates after repeated failed logins.

  6. Private event invite & access flow: A host can generate invite links for their private event. Non-host users can request access. The host can approve or reject requests; approval grants full event detail access. Invite token acceptance also grants access.

  7. Social features: Authenticated users can comment on events, bookmark them, mark themselves as going (subject to capacity), and rate the event host. All actions are auth-protected and host-restricted where applicable.

  8. Notifications: Users receive in-app notifications when events they bookmarked or are going to are updated or cancelled. The notification list supports pagination, mark-as-read, and mark-all-as-read.

Frontend (UI-level validation — manually verified for MVP)

  1. Visual completeness: All screens are implemented and match the design system. Manually verified on live deployment after each feature merge.

  2. Auth UI flow: Registration, login, logout, Google OAuth, and validation errors all work as expected in the browser.

  3. Discovery UI flow: Map/list toggle, search, filters, pagination, and guest vs. authenticated view differences all verified manually.

  4. Event detail UI flow: Full detail, limited preview, private restricted view, age gate, image carousel, comments, and attendance buttons all verified manually.

  5. Event creation UI flow: All 7 form steps, draft save, image upload, and publish flow verified manually.

  6. Private event & invite flows: Request Access button, pending state, host invite panel, access request management, and invite acceptance page all verified manually.

  7. Responsive layout: Core pages verified on mobile screen widths (NFR-08).

Mobile (UI-level validation — manually verified for MVP)

  1. Android auth flow: Registration, login, session persistence, and token restore on app relaunch verified on emulator.

  2. Android discovery flow: Map/list view, search, filters, FAB (auth-only), and pagination verified manually.

  3. Android event detail flow: Full detail, limited preview, private restricted view, 18+ gate (underage screen + DOB required screen), image carousel, Going/Bookmark, comments all verified manually.

  4. Android event creation flow: All 7 steps including date/time pickers, image upload, venue metadata, draft save, publish, edit mode (pre-fill), cancel and delete dialogs — all verified manually.

  5. Android private event flows: Request Access with pending/rejected/approved states, host invite management panel, access request approve/reject — all verified manually.

  6. Android deep linking: sem://invite/{eventId}/{token} deep link opens correct invite acceptance screen — verified manually.