This document covers QA test cases for the Affiliates business app located at /business/apps/affiliates. The app supports managing an affiliate program with approve/reject actions, viewing dashboard stats (active affiliates, total referrals, pending payouts), and managing payouts.
| Route | Purpose |
|---|
/business/apps/affiliates | Dashboard with stats, affiliate list, approve/reject actions |
/business/apps/affiliates/payouts | Payouts list with approve/reject actions |
| Route | Action | Method | Key Fields |
|---|
/business/apps/affiliates | approve | POST | affiliate_id |
/business/apps/affiliates | reject | POST | affiliate_id |
/business/apps/affiliates/payouts | approve | POST | payout_id |
/business/apps/affiliates/payouts | reject | POST | payout_id |
| Test ID | Description | Preconditions | Steps | Expected Result | Priority |
|---|
| AFF-001 | Dashboard loads with stats | User is logged in as program owner with affiliates | 1. Navigate to /business/apps/affiliates | Stats cards display: Active Affiliates (count of approved), Total Referrals, Pending Payouts (sum of commission amounts). Affiliate list is shown. | P0 |
| AFF-002 | Dashboard shows empty state | User is logged in with no affiliates | 1. Navigate to /business/apps/affiliates | Empty state with UsersIcon and “No affiliates yet.” message. | P1 |
| AFF-003 | Unauthenticated user gets empty data | User is not logged in | 1. Navigate to /business/apps/affiliates | Page loads with empty affiliates array and stats: null. No crash. | P1 |
| AFF-004 | Payouts button navigates correctly | User is logged in | 1. Click “Payouts” button | Navigates to /business/apps/affiliates/payouts. | P1 |
| AFF-005 | Affiliate list shows user info and referral count | User has affiliates with referrals | 1. View affiliate list | Each affiliate shows avatar/initial, full_name or username, referral count, join date. | P1 |
| AFF-006 | Status badges render correctly | Affiliates with pending, approved, rejected statuses exist | 1. View affiliate list | pending = secondary, approved = default, rejected = destructive. | P2 |
| Test ID | Description | Preconditions | Steps | Expected Result | Priority |
|---|
| AFF-010 | Approve a pending affiliate | User is program owner, affiliate is pending | 1. Click the approve (check) button on a pending affiliate | approve action fires. Affiliate status updates to “approved”. Toast “Affiliate approved!” appears. | P0 |
| AFF-011 | Reject a pending affiliate | User is program owner, affiliate is pending | 1. Click the reject (X) button on a pending affiliate | reject action fires. Affiliate status updates to “rejected”. Toast “Affiliate rejected.” appears. | P0 |
| AFF-012 | Approve/reject buttons only visible for pending | Affiliates with various statuses exist | 1. View affiliate list | Approve and reject buttons only appear for affiliates with status “pending”. | P0 |
| AFF-013 | Approve action requires authentication | User is not logged in | 1. POST to ?/approve with affiliate_id | Returns 401 fail. | P1 |
| AFF-014 | Reject action requires authentication | User is not logged in | 1. POST to ?/reject with affiliate_id | Returns 401 fail. | P1 |
| AFF-015 | Approve scoped to program owner | User is logged in but not the program owner | 1. POST to ?/approve with affiliate_id belonging to another owner | Update query matches on program_owner_id, so no rows are affected. Affiliate status remains unchanged. | P1 |
| AFF-016 | Reject scoped to program owner | User is logged in but not the program owner | 1. POST to ?/reject with affiliate_id belonging to another owner | Update query matches on program_owner_id, so no rows are affected. | P1 |
| AFF-017 | Hidden input sends correct affiliate_id | User is program owner | 1. Inspect form markup for pending affiliate | Hidden input name="affiliate_id" contains the correct affiliate ID value. | P2 |
| Test ID | Description | Preconditions | Steps | Expected Result | Priority |
|---|
| AFF-020 | Referral count shown per affiliate | Affiliates have referrals | 1. View affiliate list | Each affiliate row shows {count} referrals from affiliate_referrals join. | P1 |
| AFF-021 | Pending payouts calculated from commissions | Referrals exist with commission_amount | 1. View dashboard stats | Pending Payouts equals sum of all commission_amount values for the program owner. | P1 |
| AFF-022 | Total referrals count matches | Referrals exist | 1. View dashboard stats | Total Referrals equals the count of rows in affiliate_referrals for the program owner. | P1 |
| Test ID | Description | Preconditions | Steps | Expected Result | Priority |
|---|
| AFF-030 | Payouts page loads with payout list | User is program owner with payouts | 1. Navigate to /business/apps/affiliates/payouts | Payout list loads with affiliate user info, ordered by newest first. | P0 |
| AFF-031 | Payouts page empty state | User has no payouts | 1. Navigate to /business/apps/affiliates/payouts | Empty payouts array. No crash. | P1 |
| AFF-032 | Approve a payout | User is program owner | 1. Submit approve action with payout_id | Payout status updates to “approved”. approved_at timestamp is set. Returns { approved: true }. | P0 |
| AFF-033 | Reject a payout | User is program owner | 1. Submit reject action with payout_id | Payout status updates to “rejected”. Returns { rejected: true }. | P0 |
| AFF-034 | Approve payout requires authentication | User is not logged in | 1. POST to ?/approve with payout_id | Returns 401 fail. | P1 |
| AFF-035 | Reject payout requires authentication | User is not logged in | 1. POST to ?/reject with payout_id | Returns 401 fail. | P1 |
| AFF-036 | Approve payout scoped to program owner | User is not the program owner | 1. POST to ?/approve with payout_id belonging to another owner | Update matches on program_owner_id, so no rows are affected. | P1 |
| AFF-037 | Unauthenticated user gets empty payouts | User is not logged in | 1. Navigate to /business/apps/affiliates/payouts | Returns empty payouts array. No crash. | P1 |