Campaign Groups

Comprehensive manual QA testing plan for the fundraising campaign groups feature (~290 tests).

Context#

Comprehensive manual QA testing plan for the fundraising campaign groups feature. Campaign groups are a parent entity that contain multiple campaigns, either in Aggregated mode (combined metrics) or Split mode (independent campaigns). This plan covers every setting, toggle, field, and interaction — including the split/aggregate mode behavior that disables certain cards.


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 group page to confirm the setting is reflected to donors
  • Pay special attention to Split vs Aggregate mode — several cards are disabled in Split mode
  • Mark each item pass/fail as you go

Key Differences from Campaigns#

FeatureCampaignCampaign Group
Parent entityBelongs to a FundStandalone (no fund)
Child entitiesNoneContains campaigns array
Anonymous supportersHas enable_anonymous toggleNot available
Supporter commentsHas enable_comments toggleNot available
Zakat field nameis_zakat_eligibleoverride_zakat_mode (overrides child campaigns)
Accept late paymentsHas accept_late toggleNot available
External IDHas external_id fieldNot available
Amounts tabFrequencies + Giving Amounts + IntelligenceIntelligence card only
Emails tab3 receipt types (one-time, recurring, installment)No Emails tab
Split/Aggregate modeNot applicableenable_aggregate toggle disables Goal, Supporter Feed, End Date
Delete restrictionCannot delete if raised > 0Always deletable
Tabs8 tabs7 tabs (no Emails)

1. Campaign Groups List Page#

Route: /dashboard/{org}/fundraising/campaign-groups

1.1 Data Table Display#

  • Page loads and displays all campaign groups in a table
  • Default visible columns: Name, Status, # Campaigns, Raised, % of Goal, Goal, Supporters, Created
  • Name column shows internal name, sortable, min-width 350px
  • Status chips show correct colors (Published = green, Draft = yellow, Archived = grey)
  • # Campaigns column shows count of child campaigns, right-aligned
  • Raised column shows correct currency formatting (e.g., $1,234.56), right-aligned
  • % of Goal column shows percentage with color coding:
    • < 30%: light blue
    • < 70%: medium blue
    • > = 70%: dark blue
  • Goal column shows correct currency formatting
  • Supporters column shows count
  • Created column shows formatted date, sortable

1.2 Optional Columns#

  • Click column settings and toggle on each optional column one by one:
    • ID
    • Slug
    • End Date
    • Mode (displays "Aggregate" or "Split" based on enable_aggregate)
    • Most Recent Donation Date
    • Zakat Raised
    • Average Donation Amount
    • Recurring Supporters
    • 1 Month Estimated Recurring
    • 1 Year Estimated Recurring
  • Each column shows correct data
  • Column preferences persist after page refresh

1.3 Sorting#

  • Created Date (default: descending) — click to toggle asc/desc
  • Name — click to sort alphabetically asc/desc
  • Amount Raised — click to sort by raised amount
  • Number of Campaigns — click to sort by campaign count
  • 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
  • Amount Raised: Set min/max range — filters correctly
  • Fundraising Goal: Set min/max range — filters correctly (desktop only)
  • Supporter Count: Set min/max range — filters correctly (desktop only)
  • Number of Campaigns: Set min/max range — filters correctly
  • Combining multiple filters works correctly
  • Clearing filters restores full list
  • Filter state persists in URL params
  • Search by campaign group 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 campaign groups 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
  • Mobile card shows:
    • Title + status chip in header row
    • Raised amount + progress bar (if goal exists)
    • Campaign count chip in footer
    • Status chip in footer
    • Actions menu accessible
  • Card data matches table data

1.8 Row Actions#

  • On a Draft campaign group (with campaigns):
    • "Publish" action appears and works (status becomes Published)
    • "Edit" navigates to campaign group detail page
    • "Copy Link" copies public URL to clipboard
    • "Duplicate" opens DuplicateCampaignGroupModal
    • "Delete" appears and works
  • On a Draft campaign group (with NO campaigns):
    • "Publish" action does NOT appear (requires at least 1 campaign)
    • All other actions still work
  • On a Published campaign group:
    • "View" appears and opens public URL in new tab
    • "Edit" navigates to detail page
    • "Copy Link" works
    • "Duplicate" works
    • Publish action is NOT shown (already published)
    • "Delete" still appears (no raise restriction for groups)
  • On an Archived campaign group:
    • "Publish" action appears if has campaigns (re-publish)
    • "Delete" appears

2. Campaign Group Creation#

2.1 New Campaign Group Modal#

  • Click "Add Campaign Group" button — modal opens
  • Internal Name field is required — cannot submit empty
  • Display Title field (content.title) is present
  • No fund selection (campaign groups don't belong to funds)
  • No zakat eligible toggle (set later in settings)
  • Submit creates campaign group with status DRAFT
  • After creation, navigates to the new campaign group's detail page
  • New campaign group appears in the list
  • Campaign group list cache is invalidated
  • Cancel button closes modal without creating

2.2 Duplicate Campaign Group Modal#

  • Open duplicate modal from row actions or settings tab
  • Shows loading state while fetching source campaign group data
  • Pre-fills name as "Copy of {original name}"
  • Creates a new DRAFT campaign group with all settings copied
  • Verify duplicated campaign group has:
    • Same enable_aggregate mode
    • Same campaigns array (campaign_id, label, sort_order, override preserved)
    • Same goal settings
    • Same content (title, message, media) — media passed as ID only
    • Same page_content, standpro_content, handheld_content — media as ID only
    • Same theme color
    • Same zakat settings (override_zakat_mode + zakat_mode)
    • Same fees_mode
    • Same end_date
    • Same thank_you_message
    • Same redirect settings
    • Same sharing settings
    • Same SEO content — media as ID only
    • Same intelligence toggles (enable_smart_upsells, enable_smart_amounts)
    • Fresh slug (not duplicated from original)
    • raised = 0, currency not copied
    • Status is DRAFT
  • After creation, navigates to the new duplicate's detail page

2.3 Delete Campaign Group Modal#

  • Available for ANY campaign group (no raise restriction, unlike campaigns)
  • Shows confirmation modal with campaign group internal name
  • Shows warning callout: "Any links or widgets pointing to this campaign group will break"
  • Confirming deletes the campaign group
  • Campaign group disappears from list
  • Navigates back to campaign groups list
  • Campaign groups list cache is invalidated
  • Cancel button closes modal without deleting

3. Campaign Group Detail — Layout & Header#

Route: /dashboard/{org}/fundraising/campaign-groups/{id}

3.1 Header#

  • Breadcrumb shows "Campaign Groups" and links back to list
  • Campaign group 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 group data
  • Error state displays if fetch fails
  • Aggregate mode + raised > 0 + goal set: Footer shows progress bar
    • Displays: "Raised ${amount} | [progress bar] | ${goal} Goal"
    • Progress percentage is visually correct
  • Aggregate mode + no goal or raised = 0: No footer
  • Split mode: No footer regardless of goal/raised

3.3 Tabs#

  • All 7 tabs visible: Essentials, Campaign Page, Devices, Amounts, Post Donation, Sharing, Settings
  • No Emails tab (campaign groups don't have receipt configuration)
  • 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 brand_color as 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 group page
  • No split mode restrictions on this card

4.2 Campaigns Card (Campaign Group-Specific)#

Mode Toggle#

  • Segmented control at top: "Aggregated" vs "Split"
  • Default mode for new campaign group is Aggregated
  • Toggle to Split → Save → Refresh → enable_aggregate = false persisted
  • Toggle back to Aggregated → Save → Refresh → enable_aggregate = true persisted
  • Switching mode affects other cards immediately (Goal, Supporter Feed, End Date become disabled/enabled)

Campaign List#

  • Shows all campaigns currently assigned to this group
  • Each campaign row displays:
    • Drag handle (grip icon) for reordering
    • Label input field (editable, max 40 characters)
    • Campaign info chip showing the campaign's internal name
    • Delete button to remove campaign from group
  • Override Switch (Split mode only):
    • Switch appears on each campaign row ONLY when in Split mode
    • Switch hidden when in Aggregated mode
    • Toggle override ON for a campaign → Save → Refresh → persisted
    • Toggle override OFF → Save → Refresh → persisted

Adding Campaigns#

  • Click "Add Campaign" button → AddCampaignModal opens
  • Modal shows combobox/search for campaigns
  • Excluded from list: Campaigns already in this group
  • Excluded from list: ARCHIVED campaigns
  • Each option shows: internal_name + title as description
  • Select a campaign → it's added to the campaigns list
  • New campaign appears at end of list with next sort_order
  • Label defaults to campaign's internal name (or empty)
  • Save → Refresh → new campaign persisted in group

Removing Campaigns#

  • Click delete button on a campaign row → campaign removed from list
  • Save → Refresh → removal persisted
  • Removing all campaigns → Publish button should no longer appear (requires >= 1)

Reordering Campaigns#

  • Drag and drop campaigns to reorder
  • sort_order values update correctly (0, 1, 2...)
  • Save → Refresh → new order persisted
  • Public page check: Campaign order on public page matches sort_order

Editing Labels#

  • Change campaign label text → Save → Refresh → persisted
  • Max 40 characters enforced
  • Label displayed on public page (if applicable)

4.3 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 (Aggregate mode only)
  • Edge cases:
    • Amount = 0 when goal enabled → validation error
    • Amount > 99,999,999 → validation error
    • Negative amount → validation error

Split Mode Behavior#

  • When in Split mode: Goal card shows "Disabled in Split Mode" badge

  • Toggle is locked/cannot be changed

  • Amount input is disabled

  • Save button is disabled

  • When switching back to Aggregate mode: Card re-enables, previous values restored

  • Public page check (Aggregate): Goal and progress bar display on campaign group page

  • Public page check (Aggregate): Toggling goal OFF hides it from public page

  • Public page check (Split): No group-level goal shown

4.4 Content Card#

  • Media Mode segmented control:
    • "Landscape" mode: Shows message + image/video
    • "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 group 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
    • Available merge tags: campaign_group.title, campaign_group.supporter_count, campaign_group.total_raised
    • 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
  • No split mode restrictions on this card
  • Public page check: Content reflects on campaign group page (title, message, media, logo)

5. Campaign Page Tab#

Route: /dashboard/{org}/fundraising/campaign-groups/{id}/campaign-page

5.1 Supporter Feed Card#

  • Display Supporter Feed toggle:
    • ON → Save → Refresh → persisted
    • OFF → Save → Refresh → persisted
  • Description text mentions "campaign group" (not just "campaign")

Split Mode Behavior#

  • When in Split mode: Card shows "Disabled in Split Mode" badge

  • Toggle is locked/cannot be changed

  • When switching back to Aggregate mode: Card re-enables

  • Public page check (Aggregate): Supporter feed shows/hides based on toggle

  • Public page check (Split): No group-level supporter feed

5.2 Content Override Card#

  • Override fields are optional — empty means fallback to Essentials content
  • Image Override: Upload different image → Save → campaign page uses override image
  • Video Override: Enter different video URL → campaign page uses override
  • Title Override: Enter custom title → campaign page uses override title
  • Message Override: Enter custom message (rich text) → campaign page uses override
  • Clear all overrides → Save → campaign page falls back to main content
  • No split mode restrictions on this card
  • Public page check: Campaign group page shows override content when set, main content when not

6. Devices Tab#

Route: /dashboard/{org}/fundraising/campaign-groups/{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
  • Fallback logic:
    • If no StandPro media AND content is portrait mode (display_vertical_media = true): falls back to content media
    • If no StandPro media AND content is landscape mode: no fallback
  • Device check: StandPro device displays correct media

6.2 Handheld Device Media Card#

  • Display Media toggle:
    • ON: Image upload area visible
    • OFF: Media hidden on Handheld devices
  • Upload Handheld-specific image → Save → Refresh → persisted
  • Enter Handheld video URL → Save → Refresh → persisted
  • Fallback logic:
    • If no Handheld media AND content is landscape mode (display_vertical_media = false): falls back to content media
    • If no Handheld media AND content is portrait mode: no fallback
  • Device check: Handheld device displays correct media

7. Amounts Tab#

Route: /dashboard/{org}/fundraising/campaign-groups/{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

7.2 No Frequencies or Giving Amounts Cards#

  • Verify: There is NO Frequencies card on this tab (unlike campaigns)
  • Verify: There is NO Giving Amounts card on this tab (unlike campaigns)
  • Only the Intelligence card is present
  • Campaign groups inherit amounts/frequencies from their child campaigns

8. Post Donation Tab#

Route: /dashboard/{org}/fundraising/campaign-groups/{id}/post-donation

8.1 Thank You Card#

  • Thank You Message field (rich text):
    • Three default quick-select options: "JazakAllah Khair!", "JazakAllah!", "Thank you!"
    • Select each option → Save → Refresh → persisted
    • Custom rich text message → Save → Refresh → persisted
    • Merge tags available: campaign_group.title, campaign_group.supporter_count, campaign_group.total_raised
  • Public page check: Correct thank you message shows after donation through group

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
    • Save → Refresh → persisted
  • Public page check: After donation through group, redirect behavior matches setting

8.3 Sharing Channels Card#

  • Entity type is "campaign-group" (affects default URL format)
  • Enable Sharing Channels toggle:
    • OFF: Sharing disabled after donation
    • ON: URL + Message inputs appear
  • Sharing URL:
    • Defaults to: {baseUrl}/{org-slug}/campaigns/{campaign-group-slug}
    • Can customize to different URL
    • Enter URL → Save → Refresh → persisted
  • Message:
    • Enter sharing message → Save → Refresh → persisted
  • Public page check: After donation through group, sharing options show with correct URL and message

9. Sharing Tab#

Route: /dashboard/{org}/fundraising/campaign-groups/{id}/sharing

9.1 Slug Card#

  • Entity type is "campaign-group"
  • Shows current slug with full URL preview
  • 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 group is accessible at the new slug URL
  • Public page check: Old slug URL no longer works (or redirects)

9.2 SEO Card#

  • Entity type is "campaign-group"
  • SEO Title: Enter title → Save → Refresh → persisted
    • Placeholder falls back to: page_content.title → content.title → "Write an SEO title"
  • SEO Description: Enter description → Save → Refresh → persisted
  • Social Image: Upload image → Save → Refresh → persisted
    • Falls back to campaign group content image if not set
  • Public page check: Share campaign group 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/campaign-groups/{id}/settings

10.1 No General Card#

  • Verify: There is NO "General" card (no anonymous supporters or comments toggles)
  • These settings are controlled at the individual campaign level, not the group level

10.2 No Financial Card#

  • Verify: There is NO "Financial" card (no fund selection or external ID)
  • Campaign groups don't belong to funds — individual campaigns do

10.3 End Date Card#

  • Has End Date toggle:
    • OFF: Campaign group runs indefinitely
    • ON: Date picker appears
  • End Date:
    • Select future date → Save → Refresh → persisted
    • Cannot select past date (timezone-aware)
  • No "Accept Late Payments" toggle (unlike campaigns, campaign groups don't have this)

Split Mode Behavior#

  • When in Split mode: End Date card shows "Disabled in Split Mode" badge

  • Toggle is locked/cannot be changed

  • Date picker is disabled

  • When switching back to Aggregate mode: Card re-enables

  • Public page check (Aggregate): Campaign group stops accepting donations after end date

  • Public page check (Split): End date controlled at individual campaign level

10.4 Zakat Card#

  • Title shows as "Override Zakat selection mode" (not just "Zakat")
  • Override Zakat Mode toggle (maps to override_zakat_mode):
    • OFF: No zakat override — child campaigns use their own zakat settings
    • ON: Zakat mode radio group appears, overrides all child campaigns
  • Zakat Mode (when override enabled):
    • 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
  • Verify data mapping: is_zakat_eligible from card maps to override_zakat_mode in the API
  • Public page check (override ON): Zakat behavior on group page matches selected mode, regardless of individual campaign settings
  • Public page check (override OFF): Each campaign within group uses its own zakat setting

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
  • No split mode restrictions on this card
  • Public page check: Fee coverage option behavior on group page matches selected mode

10.6 Other Section (Bottom of Settings)#

  • "Duplicate Campaign Group" button → Opens DuplicateCampaignGroupModal (tested in Section 2.2)
  • "Delete Campaign Group" button → Opens DeleteCampaignGroupModal (tested in Section 2.3)
  • Both buttons always present (no conditional visibility based on raised amount)

11. Split vs Aggregate Mode — Comprehensive Test#

This section tests the complete impact of switching between modes.

11.1 Switch from Aggregate to Split#

  1. Start with a campaign group in Aggregate mode
  2. Set up: Enable goal, enable supporter feed, set end date
  3. Go to Essentials → Campaigns Card → Switch to "Split"
  4. Save the change
  5. Verify Essentials tab: Goal card shows "Disabled in Split Mode" badge, toggle locked
  6. Verify Campaign Page tab: Supporter Feed card shows "Disabled in Split Mode" badge, toggle locked
  7. Verify Settings tab: End Date card shows "Disabled in Split Mode" badge, toggle locked
  8. Verify header: Footer progress bar disappears
  9. Verify Campaigns Card: Override switch now visible on each campaign row
  10. Verify all other cards (Content, Devices, Amounts Intelligence, Post Donation, Sharing, Fees, Zakat) remain fully functional

11.2 Switch from Split to Aggregate#

  1. Start with a campaign group in Split mode
  2. Go to Essentials → Campaigns Card → Switch to "Aggregated"
  3. Save the change
  4. Verify Essentials tab: Goal card re-enabled, badge removed
  5. Verify Campaign Page tab: Supporter Feed card re-enabled, badge removed
  6. Verify Settings tab: End Date card re-enabled, badge removed
  7. Verify header: Footer progress bar reappears (if raised > 0 and goal set)
  8. Verify Campaigns Card: Override switch hidden on campaign rows
  9. Previously saved values for goal, supporter feed, end date are still intact

11.3 Mode Persistence#

  • Switch to Split → Save → Refresh page → Still in Split mode
  • Switch to Aggregate → Save → Refresh page → Still in Aggregate mode
  • Go to list page → Mode column shows correct value ("Split" or "Aggregate")

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 group detail shows loading spinner while fetching
  • Individual cards show skeleton/loading states
  • Campaign groups 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 groups 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 Group Status Lifecycle#

  • Create campaign group → status is DRAFT
  • Add at least 1 campaign → Publish button appears
  • Publish draft campaign group → status becomes PUBLISHED
  • Remove all campaigns from a DRAFT group → Publish button disappears
  • Delete campaign group → group removed entirely (no raise restriction)

12.6 Data Consistency (List ↔ Detail)#

  • Edit campaign group name → list reflects new name without full page refresh
  • Change status → list status chip updates
  • Change goal → list goal column updates
  • Add/remove campaigns → list # Campaigns column updates
  • Change mode → list Mode column updates (if visible)

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
    • {campaign_group.title} inserts correctly
    • {campaign_group.supporter_count} inserts correctly
    • {campaign_group.total_raised} inserts correctly
  • 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)
  • 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

13. End-to-End Donation Flow#

13.1 Aggregate Mode — Full Donor Journey#

  1. Create a new campaign group
  2. Set mode to Aggregated
  3. Add 2-3 published campaigns to the group
  4. Configure: goal, content (title, message, media), theme color
  5. Configure: thank you message, sharing channels, SEO
  6. Configure: fees mode, zakat override
  7. Enable supporter feed
  8. Publish the campaign group
  9. Open the public campaign group URL
  10. Verify: Theme color, title, message, media, logo all match dashboard settings
  11. Verify: Child campaigns are listed and selectable
  12. Verify: Campaign order matches sort_order from dashboard
  13. Verify: Group-level goal and progress bar display correctly
  14. Verify: Supporter feed shows (if enabled)
  15. Verify: Zakat option matches override mode (or falls back to campaign setting)
  16. Verify: Fee coverage option matches group fee mode
  17. Select a campaign and complete a donation
  18. Verify: Thank you message matches group setting
  19. Verify: Sharing options show with correct URL and message
  20. Verify: Redirect behavior matches setting
  21. Verify: Group raised amount increments in dashboard
  22. Verify: Group supporter count increments
  23. Verify: The correct child campaign also shows updated raised amount
  24. Verify: Supporter appears in group feed (if enabled)

13.2 Split Mode — Full Donor Journey#

  1. Create a campaign group
  2. Set mode to Split
  3. Add 2-3 published campaigns
  4. Configure override switches for some campaigns
  5. Configure: content, theme color (group-level)
  6. Publish the campaign group
  7. Open the public campaign group URL
  8. Verify: Child campaigns are listed
  9. Verify: NO group-level goal or progress bar
  10. Verify: NO group-level supporter feed
  11. Verify: Each campaign shows its own goal/amounts (not group-level)
  12. Verify: Campaigns with override ON show group content; override OFF show their own content
  13. Select a campaign and complete a donation
  14. Verify: Donation goes to the selected campaign
  15. Verify: Campaign's own thank you/receipt settings apply (not group-level for overridden settings)

13.3 Edge Cases#

  1. Campaign group with only 1 campaign — still functions correctly
  2. Campaign group with a mix of Published and Draft child campaigns — only Published show on public page
  3. Remove all campaigns from a Published group — what happens on public page? (should show empty or error)
  4. Archive a child campaign that's in a group — verify it's removed or hidden from public group page
  5. Change a campaign's fund while it's in a group — no impact on group (groups don't have funds)

Verification Checklist#

AreaTotal TestsPassFailNotes
Campaign Groups List~40
Creation/Duplication/Deletion~25
Layout & Header~15
Essentials Tab (incl. Campaigns Card)~50
Campaign Page Tab~12
Devices Tab~12
Amounts Tab~6
Post Donation Tab~15
Sharing Tab~12
Settings Tab~25
Split vs Aggregate Mode~20
Cross-Cutting~25
E2E Flows~30
TOTAL~290