Campaigns
Comprehensive manual QA testing plan for the fundraising campaigns feature (~300 tests).
Context#
Comprehensive manual QA testing plan for the fundraising campaigns feature. The goal is to verify that every setting, toggle, field, and interaction works correctly — and that saved values are reflected both in the dashboard and on the public-facing campaign page/devices.
How to Use This Plan#
- Work through each section sequentially
- For every setting: change it, save, refresh the page, and confirm it persisted
- Where indicated, also check the public campaign page to confirm the setting is reflected to donors
- Mark each item pass/fail as you go
1. Campaign List Page#
Route: /dashboard/{org}/fundraising/campaigns
1.1 Data Table Display#
- Page loads and displays all campaigns in a table
- Columns visible by default: Name, Status, Fund, Raised, % of Goal, Goal, Supporters, Created
- Column data matches expected values for each campaign
- Status chips show correct colors (Published = green, Draft = yellow, Archived = grey)
- Fund chips display correctly with fund color
- Currency formatting is correct (e.g.,
$1,234.56) - Dates are formatted correctly
1.2 Optional Columns#
- Click column settings and toggle on each optional column one by one:
- ID
- Fund ID
- Campaign Slug
- End Date
- Most Recent Donation Date
- Zakat Raised
- Average Donation Amount
- Recurring Supporters
- 1 Month Recurring
- 1 Year Recurring
- Each column shows correct data
- Column preferences persist after page refresh
1.3 Sorting#
- Click each column header to sort ascending
- Click again to sort descending
- Sorting persists in URL params
- Sort order survives page refresh
1.4 Filtering#
- Created Date: Set a date range filter — table filters correctly
- Status: Toggle Published / Draft / Archived — table filters correctly
- Fund: Select a specific fund — only campaigns in that fund show
- Amount Raised: Set min/max range — filters correctly
- Fundraising Goal: Set min/max range — filters correctly
- Supporter Count: Set min/max range — filters correctly
- Combining multiple filters works correctly
- Clearing filters restores full list
- Filter state persists in URL params
1.5 Search#
- Search by campaign name — matches correctly
- Search by slug — matches correctly
- Search by ID (prefix match) — matches correctly
- Clear search restores full list
1.6 Pagination#
- Pagination controls appear when campaigns exceed page size
- Navigating pages works correctly
- Page state persists in URL
1.7 Mobile Responsive#
- Resize to mobile width — table switches to card view
- Card view shows: raised amount, progress bar (if goal exists), fund chip, status chip
- Actions are accessible on mobile
1.8 Row Actions#
- On a Draft campaign:
- "Publish" action appears and works (campaign becomes Published)
- "Edit" navigates to campaign detail page
- "Copy Link" copies URL to clipboard
- "Duplicate" opens DuplicateCampaignModal
- "Delete" appears (if raised === 0) and works
- "Archive" appears (if raised > 0) and works
- On a Published campaign:
- "View" appears and opens public campaign URL in new tab
- "Edit" navigates to detail page
- "Copy Link" works
- "Duplicate" works
- Publish action is NOT shown (already published)
- On an Archived campaign:
- "Publish" action appears (re-publish)
- "Delete" appears if raised === 0
2. Campaign Creation#
2.1 New Campaign Modal#
- Click "New Campaign" button — modal opens
- Internal Name field is required — cannot submit empty
- Title field is present
- Fund dropdown shows available funds, defaults to General Fund
- Zakat Eligible toggle is present
- Submit creates campaign with status DRAFT
- After creation, navigates to the new campaign's detail page
- New campaign appears in the campaigns list
- Cancel button closes modal without creating
2.2 Duplicate Campaign Modal#
- Open duplicate modal from row actions
- Pre-fills name as "Copy of {original name}"
- Creates a new DRAFT campaign with all settings copied
- Verify duplicated campaign has:
- Same goal settings
- Same content (title, message, media)
- Same theme color
- Same email receipt configs
- Same giving amounts/levels
- Same fee/zakat settings
- Fresh slug (not duplicated)
- No external_id (stripped)
- raised = 0 (not copied)
- Giving levels have no
product_idorclaimed(stripped)
2.3 Delete Campaign Modal#
- Only available when raised === 0
- Shows warning about breaking links/widgets
- Confirming deletes the campaign
- Campaign disappears from list
- Navigates back to campaigns list
2.4 Archive Campaign#
- Available when raised > 0 and not already archived
- Campaign status changes to ARCHIVED
- Campaign remains in list with Archived status
3. Campaign Detail — Layout & Header#
Route: /dashboard/{org}/fundraising/campaigns/{id}
3.1 Header#
- Breadcrumb shows "Campaigns" and links back to list
- Campaign internal name displays in header
- Status chip shows next to name (Published/Draft/Archived)
- Copy Link icon button copies public URL to clipboard
- Draft: "Publish" button appears and works
- Published: "View" button appears and opens public URL in new tab
- Loading spinner shows while fetching campaign data
- Error state displays if fetch fails
3.2 Footer Progress Bar#
- Shows when campaign has raised > 0 and goal is set
- Displays: "Raised ${amount} | [progress bar] | ${goal} Goal"
- Progress percentage is visually correct
- Hidden when no goal is set
3.3 Tabs#
- All 8 tabs visible: Essentials, Campaign Page, Devices, Amounts, Post Donation, Sharing, Settings, Emails
- Clicking each tab navigates to correct route
- Active tab is visually highlighted
- Default tab is Essentials
4. Essentials Tab#
4.1 Main Details Card#
- Internal Name field shows current name
- Change name → Save → Refresh → Name persisted
- Name updates in header after save
- Empty name is rejected (validation)
- Customize Theme Color toggle:
- OFF: No color picker shown, uses org default
- ON: Color picker appears with hex input
- Pick a color → Save → Refresh → Color persisted
- Toggle OFF → Save → theme_color is cleared
- Public page check: Theme color reflects on public campaign page
4.2 Goal Card#
- Display Goal toggle:
- OFF: No goal amount input shown
- ON: Goal amount input appears
- Enter goal amount (e.g., 50000) → Save → Refresh → Amount persisted
- Goal shows correct currency symbol
- Footer progress bar updates with new goal
- Edge cases:
- Amount = 0 when goal enabled → validation error
- Amount > 99,999,999 → validation error
- Negative amount → validation error
- Public page check: Goal and progress bar display on campaign page
- Public page check: Toggling goal OFF hides it from public page
4.3 Content Card#
- Media Mode segmented control:
- "Landscape" mode: Shows message + image/video below
- "Portrait" mode: Shows image only with title text overlay
- Image Upload:
- Upload an image → Save → Refresh → Image persisted
- Replace image → Save → New image shown
- Remove image → Save → Image removed
- Video URL:
- Enter valid YouTube URL → Save → Refresh → URL persisted
- Enter valid Vimeo URL → works
- Enter invalid URL → validation error
- Display Organization Logo toggle:
- ON → logo shows on campaign page
- OFF → logo hidden
- Save → Refresh → persisted
- Title (required):
- Enter title → Save → Refresh → persisted
- Clear title → validation error (required)
- Max 50 characters enforced
- Message (rich text, landscape mode only):
- Type message with bold, italic, underline → formatting preserved
- Add bullet list → preserved
- Add link → preserved
- Insert merge tag variable → variable tag shows
- Max 250 characters enforced
- Message hidden in portrait mode
- Title Text Color (portrait mode only):
- Color picker appears for text overlay color
- Pick color → Save → Refresh → persisted
- Public page check: Content reflects on campaign page (title, message, media, logo)
- Public page check: Portrait vs landscape modes display differently
5. Campaign Page Tab#
Route: /dashboard/{org}/fundraising/campaigns/{id}/campaign-page
5.1 Supporter Feed Card#
- Display Supporter Feed toggle:
- ON → Save → Refresh → persisted
- OFF → Save → Refresh → persisted
- Public page check: Supporter feed shows/hides on the campaign page based on toggle
5.2 Content Override Card#
- Override fields are optional — empty means fallback to Essentials content
- Image Override: Upload different image → Save → page uses override image
- Video Override: Enter different video URL → page uses override
- Title Override: Enter custom title → page uses override title
- Message Override: Enter custom message (rich text) → page uses override
- Clear all overrides → Save → page falls back to main content
- Public page check: Campaign page shows override content when set, main content when not
6. Devices Tab#
Route: /dashboard/{org}/fundraising/campaigns/{id}/devices
6.1 StandPro Device Media Card#
- Display Media toggle:
- ON: Image upload area visible
- OFF: Media hidden on StandPro devices
- Upload StandPro-specific image → Save → Refresh → persisted
- Enter StandPro video URL → Save → Refresh → persisted
- If no StandPro media set: falls back to main content image (vertical/portrait orientation)
- Device check: StandPro device displays correct media
6.2 Handheld Device Media Card#
- Display Media toggle works same as StandPro
- Upload Handheld-specific image → Save → Refresh → persisted
- Enter Handheld video URL → Save → Refresh → persisted
- If no Handheld media set: falls back to main content image (landscape orientation)
- Device check: Handheld device displays correct media
7. Amounts Tab#
Route: /dashboard/{org}/fundraising/campaigns/{id}/amounts
7.1 Intelligence Card#
- Suggest Personalized Upsells toggle:
- ON → "Nizam Intelligence" badge appears → Save → Refresh → persisted
- OFF → Save → Refresh → persisted
- Suggest Personalized Amounts toggle:
- ON → "Nizam Intelligence" badge appears → Save → Refresh → persisted
- OFF → Save → Refresh → persisted
- Suggest Personalized Intervals toggle:
- ON → Save → Refresh → persisted
- OFF → Save → Refresh → persisted
7.2 Frequencies Card#
- Frequency 1 dropdown:
- Options: One-time, Daily, Weekly, Biweekly, Monthly, Quarterly, Semiannually, Annually
- Select a frequency → Save → Refresh → persisted
- Frequency 2 dropdown (optional):
- Enable second frequency → Save → Refresh → persisted
- Cannot remove a frequency if it has giving levels configured (confirmation modal)
- Default Frequency (when 2 frequencies selected):
- Adaptive (Nizam Intelligence) option available
- Manual select Frequency 1 or 2
- Save → Refresh → persisted
- Public page check: Available frequencies match configuration on donation form
7.3 Giving Amounts Card#
Amounts Mode#
- Select "Amounts" giving type
- Preset Amounts:
- Multiple amount buttons shown (e.g., $25, $50, $100, $250)
- Edit an amount → value updates
- Amount = 0 → validation error
- Amount > 100,000 → validation error
- Duplicate amount → validation error
- Add new amount → Save → Refresh → persisted
- Remove an amount → Save → Refresh → persisted
- Default Amount:
- Select one amount as default (radio button)
- "Default" badge shows on selected amount
- Save → Refresh → default persisted
- Allow Custom Amount toggle:
- ON: Minimum amount input appears
- Set minimum (e.g., $5) → Save → Refresh → persisted
- Min < 1 → validation
- Min > 100,000 → validation
- OFF: Custom amount disabled for donors
- Public page check: Donation amounts show correctly, default is pre-selected
- Public page check: Custom amount field shows/hides based on toggle
Giving Levels Mode#
- Switch to "Giving Levels" type
- Core Levels (1-3):
- Add a core level → opens level editor modal
- Set Amount (required), Title (required, max 50 chars), Description (max 150 chars), Goal (0-9999)
- One core level must be set as default
- Max 3 core levels enforced
- Min 1 core level enforced
- Additional Levels (0-7):
- Add additional levels beyond core
- Max 10 total levels enforced
- Drag and Drop:
- Drag level from Core to Additional → updates is_core
- Drag level from Additional to Core → updates is_core (if under 3 limit)
- Reorder levels within a section
- Display Claimed toggle:
- ON: Shows claimed count per level on public page
- OFF: Hides claimed count
- Save → Refresh → persisted
- Allow Custom Amount toggle (same as amounts mode)
- Public page check: Giving levels display with titles, descriptions, and amounts
- Public page check: Core levels are prominently displayed vs additional
Recurring End Date Settings (if a recurring frequency exists)#
- Enable Recurring End Date toggle:
- ON: End date configuration appears
- OFF: No end date for recurring plans
- End Date Setting (when enabled):
- Optional Off: Shows end date option, not pre-selected
- Optional On: Shows end date option, pre-selected
- Required: Forces end date selection
- End Date Type:
- "Length" mode: Count + Unit inputs
- Days: max 1825
- Weeks: max 260
- Months: max 60
- Years: max 5
- "Date" mode: Date picker
- Min date: Today
- Max date: 5 years from today
- "Length" mode: Count + Unit inputs
- Allow Custom End Date toggle (when not Required):
- ON: Supporters can pick their own end date
- OFF: Uses configured default
- Save → Refresh → all recurring settings persisted
- Public page check: Recurring end date options show correctly on donation form
Tab Switching (when 2 frequencies configured)#
- Separate tab for each frequency
- Each tab has independent amounts/levels configuration
- Switching tabs preserves unsaved changes warning (if any)
8. Post Donation Tab#
Route: /dashboard/{org}/fundraising/campaigns/{id}/post-donation
8.1 Thank You Card#
- Three default options: "JazakAllah Khair!", "JazakAllah!", "Thank you!"
- Select each option → Save → Refresh → persisted
- Custom values preserved if previously saved
- Public page check: Correct thank you message shows after donation
8.2 Redirect Card#
- Enable Redirect toggle:
- OFF: No redirect settings shown
- ON: URL input + Auto Redirect toggle appear
- Redirect URL:
- Enter valid URL (https://example.com) → Save → Refresh → persisted
- Enter invalid URL → validation error
- Empty URL when enabled → validation error
- Auto Redirect toggle:
- ON: Auto-redirects after donation
- OFF: Shows "Continue" button for manual redirect
- Public page check: After donation, redirect behavior matches setting
8.3 Sharing Channels Card#
- Enable Sharing Channels toggle:
- OFF: Sharing disabled after donation
- ON: URL + Message inputs appear
- Sharing URL:
- Defaults to campaign URL
- Can customize to different URL
- Enter URL → Save → Refresh → persisted
- Message:
- Enter sharing message → Save → Refresh → persisted
- Public page check: After donation, sharing options show with correct URL and message
9. Sharing Tab#
Route: /dashboard/{org}/fundraising/campaigns/{id}/sharing
9.1 Slug Card#
- Shows current slug with full URL preview:
nizam.co/{org}/campaigns/{slug} - Change slug to valid kebab-case value → Save → Refresh → persisted
- Invalid characters → validation error
- Empty slug → validation error
- Duplicate slug (already exists for org) → error from server
- Public page check: Campaign is accessible at the new slug URL
- Public page check: Old slug URL no longer works (or redirects)
9.2 SEO Card#
- SEO Title: Enter title → Save → Refresh → persisted
- Falls back to campaign page_content.title or content.title if empty
- SEO Description: Enter description → Save → Refresh → persisted
- Social Image: Upload image → Save → Refresh → persisted
- Falls back to campaign content image if not set
- Public page check: Share campaign URL on social media (or use meta tag inspector):
- og:title matches SEO title (or fallback)
- og:description matches SEO description
- og:image matches uploaded social image (or fallback)
10. Settings Tab#
Route: /dashboard/{org}/fundraising/campaigns/{id}/settings
10.1 General Card#
- Enable Anonymous Supporters toggle:
- ON → Save → Refresh → persisted
- OFF → Save → Refresh → persisted
- Enable Supporter Comments toggle:
- ON → Save → Refresh → persisted
- OFF → Save → Refresh → persisted
- Public page check: Anonymous option shows/hides on donation form
- Public page check: Comment field shows/hides on donation form
10.2 Financial Card#
- Parent Fund dropdown:
- Shows all available funds
- Select different fund → Save → Refresh → persisted
- Fund chip updates in campaign list
- External ID:
- Enter external ID → Save → Refresh → persisted
- Clear external ID → Save → Refresh → cleared
10.3 End Date Card#
- Has End Date toggle:
- OFF: Campaign runs indefinitely
- ON: Date picker appears
- End Date:
- Select future date → Save → Refresh → persisted
- Cannot select past date (timezone-aware)
- Accept Late Payments toggle:
- ON: Donations accepted after end date
- OFF: Donations blocked after end date
- Save → Refresh → persisted
- Public page check: Campaign stops accepting donations after end date (unless Accept Late is ON)
10.4 Zakat Card#
- Is Zakat Eligible toggle:
- OFF: No zakat options shown
- ON: Zakat mode radio group appears
- Zakat Mode (when eligible):
- Optional On: Shows zakat checkbox, pre-checked → Save → Refresh → persisted
- Optional Off: Shows zakat checkbox, unchecked → Save → Refresh → persisted
- Required: Always zakat, no checkbox → Save → Refresh → persisted
- Disabled: No zakat option → Save → Refresh → persisted
- Public page check: Zakat option shows/hides based on eligibility
- Public page check: Zakat checkbox default matches mode (on/off/required/disabled)
10.5 Fees Card#
- Fees Mode radio options:
- Smart (Nizam Intelligence badge) → Save → Refresh → persisted
- Optional On → Save → Refresh → persisted
- Optional Off → Save → Refresh → persisted
- Required → Save → Refresh → persisted
- Disabled → Save → Refresh → persisted
- Public page check: Fee coverage option behavior matches selected mode
10.6 Other Section (Bottom of Settings)#
- Duplicate Campaign button → Opens DuplicateCampaignModal
- Delete/Archive buttons:
- Delete shows when raised === 0
- Archive shows when raised > 0 and not archived
11. Emails Tab#
Route: /dashboard/{org}/fundraising/campaigns/{id}/emails
11.1 One-Time Donation Receipt#
- Enable Receipt toggle:
- ON → Save → Refresh → persisted
- OFF → No receipt sent for one-time donations
- Customize Message toggle (when enabled):
- OFF: Uses default receipt template
- ON: Custom fields appear:
- Subject (rich text, single line): Enter subject with merge tags → Save → Refresh → persisted
- Image: Upload receipt image → Save → Refresh → persisted
- Content Title (rich text, single line): Enter with merge tags → Save → Refresh → persisted
- Content Message (rich text, multi-line): Enter with formatting + merge tags → Save → Refresh → persisted
- Merge Tags Test:
- Insert
{supporter.first_name}→ Save → tag persisted - Insert
{supporter.last_name}→ Save → tag persisted - Insert
{supporter.email}→ Save → tag persisted - Insert
{transaction.amount}→ Save → tag persisted - Insert
{transaction.id}→ Save → tag persisted - Insert
{campaign.title}→ Save → tag persisted - Insert
{campaign.total_raised}→ Save → tag persisted
- Insert
- Email check: Make a one-time donation → receipt email received with correct custom content and resolved merge tags
11.2 Recurring Plan Receipt#
- Same test cases as One-Time Receipt above
- Additional merge tags available:
{recurring.id}→ Save → tag persisted{recurring.frequency}→ Save → tag persisted{recurring.next_installment_date}→ Save → tag persisted
- Email check: Set up recurring plan → receipt email reflects custom content
11.3 Installment Receipt#
- Same test cases as One-Time Receipt above
- Recurring merge tags available (same as Recurring Plan Receipt)
- Email check: Installment payment triggers → receipt email reflects custom content
12. Cross-Cutting Concerns#
12.1 Save Behavior#
- Every card shows unsaved changes indicator when modified
- Save button is disabled until changes are made
- Saving shows loading state (spinner/disabled button)
- Success toast appears after save
- Error toast appears on failure with descriptive message
- Concurrent saves are prevented (second save blocked while first is in-flight)
- Navigating away with unsaved changes — expected behavior (warning or silent discard?)
12.2 Loading States#
- Campaign detail shows loading spinner while fetching
- Individual cards show skeleton/loading states
- Campaign list shows loading state while fetching
12.3 Error Handling#
- Network error during save → error toast, form data not lost
- Network error during load → error state displayed with retry option
- Server validation error → error message displayed to user
12.4 URL State Persistence#
- Campaign list: filters, sort, pagination, search persist in URL params
- Copy/paste URL with params → same view loads
- Browser back/forward navigates between filter states
12.5 Campaign Status Lifecycle#
- Create campaign → status is DRAFT
- Publish draft campaign → status becomes PUBLISHED
- Archive published campaign → status becomes ARCHIVED
- Re-publish archived campaign → status becomes PUBLISHED
- Delete campaign (raised = 0) → campaign removed entirely
- Cannot delete campaign with donations (raised > 0) — only archive
12.6 Data Consistency (List ↔ Detail)#
- Edit campaign name → campaign list reflects new name without full page refresh
- Change campaign status → list status chip updates
- Change fund → list fund chip updates
- Change goal → list goal column + footer progress bar update
12.7 Rich Text Editor#
- Bold, italic, underline formatting saves and loads correctly
- Links save and load correctly (clickable in preview)
- Bullet/numbered lists save and load correctly
- Merge tag variables insert and display correctly as chips/tags
- Character limits enforced where specified (50 for title, 250 for message)
- Copy-paste from external sources doesn't break formatting
12.8 Media Upload#
- Image upload works for all image fields (content, page, device, SEO, receipt)
- Image preview displays after upload
- Replace existing image works
- Remove image works
- Video URLs (YouTube, Vimeo) validate and display correctly
- Invalid video URLs show validation error
- Large file upload handles gracefully (progress indicator or size limit)
13. End-to-End Donation Flow#
13.1 Full Donor Journey (One-Time)#
- Create a new campaign with all settings configured
- Publish the campaign
- Open the public campaign URL
- Verify: Theme color, title, message, media, logo all match dashboard settings
- Verify: Goal progress bar shows (if enabled)
- Verify: Supporter feed shows (if enabled)
- Verify: Donation amounts match configured amounts
- Verify: Default amount is pre-selected
- Verify: Custom amount option shows (if enabled) with correct minimum
- Verify: Anonymous toggle shows (if enabled)
- Verify: Comment field shows (if enabled)
- Verify: Zakat option shows with correct default (if eligible)
- Verify: Fee coverage option matches fee mode
- Complete a one-time donation
- Verify: Thank you message matches setting
- Verify: Redirect behavior matches setting (auto or manual)
- Verify: Sharing options show (if enabled) with correct URL and message
- Verify: Receipt email received with correct content (if enabled)
- Verify: Campaign raised amount increments in dashboard
- Verify: Supporter count increments in dashboard
- Verify: Supporter appears in feed (if enabled and not anonymous)
13.2 Full Donor Journey (Recurring)#
- Configure a campaign with a recurring frequency (e.g., Monthly)
- Set recurring end date settings
- Open public campaign URL
- Verify: Frequency tabs/options match configuration
- Verify: Default frequency matches setting (adaptive or manual)
- Verify: Amounts on each frequency tab are independent and correct
- Verify: Recurring end date options match configuration (length vs date, optional vs required)
- Complete a recurring donation
- Verify: Recurring plan receipt email received with correct content
- Verify: Installment receipt email received on subsequent payments
13.3 Device-Specific Flows#
- Open campaign on StandPro device
- Verify: StandPro-specific media shows (or fallback to portrait content image)
- Open campaign on Handheld device
- Verify: Handheld-specific media shows (or fallback to landscape content image)
- Complete donation on each device type — verify full flow works
Verification Checklist#
| Area | Total Tests | Pass | Fail | Notes |
|---|---|---|---|---|
| Campaign List | ~35 | |||
| Campaign Creation/Duplication | ~20 | |||
| Layout & Header | ~15 | |||
| Essentials Tab | ~30 | |||
| Campaign Page Tab | ~10 | |||
| Devices Tab | ~10 | |||
| Amounts Tab | ~50 | |||
| Post Donation Tab | ~15 | |||
| Sharing Tab | ~12 | |||
| Settings Tab | ~25 | |||
| Emails Tab | ~25 | |||
| Cross-Cutting | ~25 | |||
| E2E Flows | ~30 | |||
| TOTAL | ~300 |