Test Cases: Cover Image, Aggregates & Public Campaign Page (#661 / #662)
Module: Fundraising & Campaigns — Cover Image, Aggregates, Public Page
Endpoints: POST /api/billing/admin/campaigns/:id/cover-image · GET /api/billing/admin/campaigns / GET .../campaigns/:id (aggregates) · GET /api/public/:tenantSlug/campaigns/:slug (public, no auth).
Frontend: admin campaign create/edit forms (cover image field), admin campaign detail (progress bar), public campaign page /:tenantSlug/campaigns/:slug.
Prerequisites
Login as admin@rcme.membervu.com / Admin123! for admin cases. An ACTIVE campaign with at least one APPROVED donation for aggregate/public-page checks.
Test Cases
TC-FUND-COVER-01: Cover Image Upload — Size & Type Guards (#661)
Step
Action
Expected Result
1
Upload a cover image > 5MB.
POST /api/billing/admin/campaigns/:id/cover-image → 400 "Image too large. Please upload under 5 MB."
2
Upload a non-image type (e.g. a PDF or GIF disguised as data URI).
400 "Invalid image type. Use JPG, PNG, or WEBP."
3
Upload a valid PNG/JPG/JPEG/WEBP under 5MB.
200. FundraisingCampaign.coverImage persists; response is the fully-serialized campaign with the new cover image.
TC-FUND-COVER-02: Edit-Flow Isolation on Upload Failure
Step
Action
Expected Result
1
Edit a campaign's text fields (title/description) AND attach an oversized cover image in the same edit action.
The cover-image upload fails (400, per TC-FUND-COVER-01).
2
Reload the campaign.
The text-field edits SURVIVED and persisted even though the image upload failed — the two are isolated, not an all-or-nothing transaction.
TC-FUND-AGG-01: List/Detail Aggregates (#662)
Step
Action
Expected Result
1
Call GET /api/billing/admin/campaigns (list) and GET .../campaigns/:id (detail).
Both responses include raisedAmount = SUM(APPROVED donation amounts) and pendingProofCount = COUNT(PENDING donations).
2
Call create/update/status/archive endpoints.
These may OMIT the aggregate fields — treat as optional on non-list/detail responses.
3
Open the admin campaign detail page.
A progress bar renders showing raised vs goal, driven by raisedAmount.
Known caveat: refunding an APPROVED donation elsewhere does NOT reduce raisedAmount — there is no un-approve transition. Document, do not assert a decrease.
TC-FUND-PUBLIC-01: Public Donor List — No PII Leak
Step
Action
Expected Result
1
Call GET /api/public/:tenantSlug/campaigns/:slug logged out.
Only APPROVED donations feed raisedAmount/donationCount/donor list. Donor list items are shaped {donorName, amount, createdAt} — neverdonorEmail or donorMemberId.
TC-FUND-PUBLIC-02: Anonymous Donations Null Out donorName
Step
Action
Expected Result
1
Via direct API call, donate with isAnonymous: true and a real donorName in the body, then admin-approve it.
Donation approved as usual.
2
Fetch the public campaign page.
The donor list entry for this donation has donorName: null — REGARDLESS of the name that was submitted on the row.
Known caveat:isAnonymous has no frontend checkbox today — set it via direct API call only. The public page still honours it correctly.