How to Write Test Cases for Refund Flow (With Examples)
How to Write Test Cases for Refund Flow (With Examples) starts with a clear understanding of the refund process and the risks it introduces. Refunds touch payment gateways, order state, inventory, loy
How to Write Test Cases for Refund Flow (With Examples) starts with a clear understanding of the refund process and the risks it introduces. Refunds touch payment gateways, order state, inventory, loyalty points, tax calculations, and user communication. A single missed condition can lead to revenue loss, compliance violations, or damaged trust. This guide walks you through building a high‑signal test suite that covers happy paths, error conditions, boundaries, security, accessibility, and concurrency. You will see a concrete test matrix with 20+ cases, learn how to set up data, prioritize effort, and trace each case to requirements. The final sections show how manual execution, automated scripts, and autonomous exploration (using SUSA) complement each other to give real coverage in production.
How to Write Test Cases for Refund Flow (With Examples): Foundations
Refund Flow Overview
A typical refund flow begins when a customer initiates a return request from an order details page. The system validates eligibility (time window, item condition, payment method), creates a refund transaction, communicates with the payment gateway, updates order status, adjusts inventory, possibly restocks items, notifies the customer via email or push, and logs the event for auditing. Depending on the business model, refunds may be full, partial, store‑credit, or exchanged for another item. Each step introduces failure points: gateway timeouts, idempotency issues, race conditions with concurrent orders, tax‑recalculation mismatches, and accessibility barriers in the UI.
Why Test Cases Matter Here
Refunds are high‑value transactions. A bug that erroneously approves a refund can drain funds; a bug that blocks a legitimate refund leads to chargebacks and brand damage. Moreover, refund flows often intersect with compliance regimes (PCI‑DSS, GDPR, PSD2) and accessibility standards (WCAG 2.1 AA). A well‑structured test case captures preconditions, precise steps, and measurable expected results, making it easy to automate, review, and trace back to user stories or regulatory clauses.
Core Elements of a Test Case
Every test case should contain the following fields:
| Field | Description |
|---|---|
| ID | Unique identifier (e.g., REF‑001) |
| Title | Short, descriptive summary |
| Related Requirement | Link to user story, epic, or regulation |
| Preconditions | State that must exist before execution (e.g., order placed, payment captured) |
| Test Data | Specific values needed (order amount, payment method, coupon code) |
| Steps | Ordered actions the tester or script performs |
| Expected Result | Observable outcome (UI message, DB state, gateway response) |
| Postconditions | State left after test (useful for chaining) |
| Priority | P0 (critical), P1 (high), P2 (medium), P3 (low) |
| Type | Positive, negative, boundary, security, accessibility, performance |
Using this template keeps reviews focused and enables automatic generation of test‑management artifacts.
Setting Up a Refund‑Ready Environment
Before writing cases, ensure you have a stable test harness:
- Isolated test tenant – prevents cross‑contamination with production data.
- Stubbed payment gateway – allows simulation of success, failure, timeout, and partial‑capture responses.
- Order factory – script or API that creates orders with configurable attributes (amount, currency, items, tax, discounts).
- Inventory mock – tracks stock levels so you can verify restock behavior.
- Notification capture – mailbox or webhook that records emails, SMS, push.
- Audit log access – read‑only view of transaction logs for post‑condition verification.
Many teams use Docker Compose to spin up these services; a snippet is shown later in the automation section.
How to Write Test Cases for Refund Flow (With Examples): Positive Scenarios
Positive test cases verify that the system behaves correctly when all inputs are valid and the user follows the intended path. Below is a representative set; you can expand based on your specific business rules.
| ID | Title | Related Requirement | Preconditions | Test Data | Steps | Expected Result |
|---|---|---|---|---|---|---|
| REF‑001 | Full refund for eligible order within return window | US‑REF‑10 (Full refund) | Order placed, payment captured, order status = Delivered, return window = 30 days | Order #1001, $75.00, Visa, no coupons | 1. Navigate to Order Details → Request Refund 2. Select Full Refund 3. Confirm reason “Changed mind” 4. Submit | Refund initiated, gateway returns approved, order status = Refunded, inventory increased by 1, email sent with refund details |
| REF‑002 | Partial refund for damaged item | US‑REF‑12 (Partial refund) | Order delivered, item marked as damaged in return request | Order #1002, $120.00 (two $60 items), Mastercard, one item damaged | 1. Open Order Details → Request Refund 2. Choose Partial Refund 3. Select damaged item, enter refund amount $45 4. Upload photo proof 5. Submit | Gateway approves $45, order status = Partially Refunded, inventory unchanged for undamaged item, email shows $45 refund |
| REF‑003 | Refund to original payment method with store‑credit fallback | US‑REF‑15 (Fallback to store credit) | Original payment method expired or blocked | Order #1003, $50.00, expired Visa, store‑credit enabled | 1. Initiate refund 2. System detects card invalid 3. Offers store‑credit option 4. User accepts | Refund processed as $50 store credit, order status = Refunded, store‑credit balance increased, email indicates store credit |
| REF‑004 | Refund with applied coupon, coupon re‑issued | US‑REF‑18 (Coupon handling) | Order used a coupon, coupon is reusable | Order #1004, $80.00, 10% off coupon CODE10, PayPal | 1. Request full refund 2. Confirm | Refund of $72.00 (post‑coupon) issued, coupon CODE10 made available again in user’s coupon wallet, order status = Refunded |
| REF‑005 | Refund triggers tax reversal | US‑REF‑20 (Tax adjustment) | Order includes tax, tax jurisdiction requires reversal on refund | Order #1005, $100.00 + $8.00 tax, Amex | 1. Full refund request 2. Submit | Gateway refunds $108.00, tax amount $8.00 reversed in tax service, order shows $0 tax, email includes tax breakdown |
| REF‑006 | Refund for subscription cancellation (prorated) | US‑REF‑22 (Subscription) | Active monthly subscription, mid‑cycle cancellation | Subscription #2001, $30/month, cancelled on day 15 of billing cycle | 1. Navigate to Subscription → Cancel → Request Refund for unused period 2. Confirm | System calculates $15 prorated refund, gateway approves, subscription status = Cancelled, email confirms refund |
| REF‑007 | Refund with loyalty points deduction and restoration | US‑REF‑25 (Loyalty) | Order earned 500 points, user redeemed 200 points for discount | Order #1006, $60.00, 200 points redeemed, remaining 300 points balance | 1. Full refund request 2. Submit | Refund of $48.00 (post‑points) issued, loyalty points restored to 500, order status = Refunded, notification shows points reinstated |
| REF‑008 | Refund initiated via guest checkout (no account) | US‑REF‑28 (Guest users) | Guest order, email captured at checkout | Order #1007, $40.00, guest email guest@example.com, Card | 1. Click link in order confirmation email → Refund portal 2. Enter order ID and email 3. Request full refund | Refund processed, order status = Refunded, confirmation email sent to guest@example.com |
| REF‑009 | Refund after failed delivery attempt (carrier‑initiated) | US‑REF‑30 (Carrier trigger) | Order marked Delivery Failed by carrier, auto‑refund enabled | Order #1008, $55.00, UPS, auto‑refund flag true | 1. Carrier webhook posts delivery‑failed event 2. System validates eligibility 3. Initiates refund automatically | Refund issued to original payment, order status = Refunded, email sent to customer explaining carrier issue |
| REF‑010 | Refund with split payment (multiple methods) | US‑REF‑33 (Split tender) | Order paid with $40 gift card + $20 credit card | Order #1009, $60.00 total, gift card GC123, Visa ending 4242 | 1. Full refund request 2. System splits refund proportionally | $40 refunded to gift card balance, $20 refunded to Visa, order status = Refunded, receipt shows split |
| REF‑011 | Refund initiated from mobile app (native) | US‑REF‑35 (Mobile) | App version 2.4+, user logged in | Order #1010, $70.00, logged in user | 1. Tap Orders → Select order → Tap Refund 2. Choose full refund 3. Confirm with biometrics | Refund processed, order status = Refunded, push notification received, app UI updates to refunded state |
| REF‑012 | Refund with promo code that is non‑refundable | US‑REF‑38 (Non‑refundable promo) | Order used a “non‑refundable” promo giving $10 discount | Order #1011, $90.00, promo NRF10, PayPal | 1. Request full refund 2. Submit | System refunds $80.00 (excluding promo discount), order status = Refunded, email notes promo amount not returned |
| REF‑013 | Refund after order modification (price adjustment) | US‑REF‑40 (Price adjust) | Order modified after placement, price increased by $15 via add‑on | Order #1012, original $50.00, add‑on $15, total $65.00, Mastercard | 1. Request full refund after modification 2. Submit | Refund of $65.00 issued, order status = Refunded, inventory reflects add‑on removal |
| REF‑014 | Refund with international currency conversion | US‑REF‑42 (FX) | Order placed in EUR, refund issued in USD with FX rate | Order #1013, €80.00, EUR→USD rate 1.10, card in USD | 1. Full refund request 2. Submit | Refund of $88.00 issued (80 * 1.10), order status = Refunded, FX rate stored in audit log |
| REF‑015 | Refund triggered by admin override (fraud suspicion cleared) | US‑REF‑45 (Admin override) | Order initially flagged fraud, later cleared by analyst | Order #1014, $120.00, flag cleared | 1. Analyst clicks “Override & Refund” 2. Enter reason “False positive” 3. Submit | Refund processed, order status = Refunded, audit log shows admin action and reason |
| REF‑016 | Refund with delayed gateway response (simulated timeout then success) | US‑REF‑48 (Retry logic) | Gateway occasionally times out, system retries twice | Order #1015, $30.00, Visa | 1. Initiate refund 2. Mock gateway returns timeout on first attempt, success on second | System retries, eventual approval, order status = Refunded, retry count logged |
| REF‑017 | Refund with concurrent refund request (idempotency) | US‑REF‑50 (Idempotent) | Two simultaneous refund requests for same order | Order #1016, $90.00, PayPal | 1. Send two refund API calls within 200 ms | Only one refund processed, second returns already refunded error, order status = Refunded |
| REF‑018 | Refund with insufficient funds in merchant account (gateway declines) | US‑REF‑52 (Insufficient funds) | Merchant account balance < refund amount | Order #1017, $150.00, merchant balance $50 | 1. Request refund 2. Gateway returns insufficient_funds | System marks refund as failed, order status stays Settled, alert sent to finance team, user sees “Refund could not be processed, please try later” |
| REF‑019 | Refund after chargeback (duplicate protection) | US‑REF‑55 (Chargeback guard) | Order already charged back, refund attempted | Order #1018, $70.00, chargeback received | 1. Attempt refund via UI/API | System blocks refund, returns chargeback_present error, order status unchanged, log entry |
| REF‑020 | Refund with accessibility screen‑reader announcement | US‑REF‑58 (a11y) | User navigates with TalkBack/VoiceOver | Order #1019, $55.00 | 1. Open refund flow with screen reader enabled 2. Complete steps | Each step announces purpose (e.g., “Refund amount, edit text”), successful submission announces “Refund submitted, you will receive email shortly” |
These twenty cases illustrate the breadth of positive validation you should cover. Adjust IDs, preconditions, and data to match your domain.
Negative and Invalid Input Cases
Negative test cases verify that the system gracefully rejects malformed or unauthorized inputs. They protect against security loopholes and user confusion.
| ID | Title | Preconditions | Test Data | Steps | Expected Result |
|---|---|---|---|---|---|
| REF‑N01 | Refund request for non‑existent order | No order with given ID | Order ID = 999999 | 1. Enter ID in refund portal 2. Submit | Error “Order not found”, no state change |
| REF‑N02 | Refund request outside return window | Order delivered 45 days ago | Order #1020, $40.00 | 1. Attempt refund | Message “Return period expired”, refund blocked |
| REF‑N03 | Refund request with negative amount | Order #1021, $60.00 | Amount = -10 | 1. Enter negative amount 2. Submit | Validation error “Amount must be greater than zero” |
| REF‑N04 | Refund request exceeding order total | Order #1022, $30.00 | Amount = 50.00 | 1. Enter amount > total 2. Submit | Error “Refund amount cannot exceed order total” |
| REF‑N05 | Refund request with invalid payment method (expired card) | Order #1023, expired Visa | Card expiry 01/22 | 1. Initiate refund 2. System detects expiry | Offer store‑credit fallback or error “Payment method invalid” |
| REF‑N06 | Refund request with missing mandatory reason | Order #1024, $50.00 | Reason left blank | 1. Submit without selecting reason | Inline validation highlights reason field, submission disabled |
| REF‑N07 | Refund request after order already refunded | Order #1025, already refunded | — | 1. Attempt second refund | Message “Order already refunded”, no duplicate transaction |
| REF‑N08 | Refund request with tampered API signature | Order #1026, $70.00 | Invalid HMAC | 1. Call refund API with bad signature | HTTP 401 Unauthorized, audit log records attempt |
| REF‑N09 | Refund request with SQL injection in reason field | Order #1027, $55.00 | Reason = “'; DROP TABLE refunds; --” | 1. Submit reason | Input sanitized, stored as literal string, no DB effect |
| REF‑N10 | Refund request with excessively long reason (beyond DB limit) | Order #1028, $50.00 | Reason = 5000‑char string | 1. Submit | Validation error “Reason too long (max 500 chars)” |
| REF‑N11 | Refund request from unauthenticated user (guest token missing) | Order #1029, guest order | No token | 1. Access refund endpoint without token | HTTP 403 Forbidden, redirect to login |
| REF‑N12 | Refund request with disabled user account | Order #1030, $40.00 | User account disabled | 1. Log in disabled user 2. Attempt refund | Error “Account not active”, refund blocked |
| REF‑N13 | Refund request with mismatched currency | Order #1031, USD order | Attempt to refund in EUR via API | 1. Send refund with currency=EUR | Error “Currency mismatch with original order” |
| REF‑N14 | Refund request with duplicate idempotency key | Order #1032, $60.00 | Same Idempotency-Key header twice | 1. Send two requests with same key | Second returns 200 OK with body indicating already processed, no extra refund |
| REF‑N15 | Refund request with exceeded rate limit | Order #1033, $20.00 | Rapid fire 20 requests/sec | 1. Burst of requests | HTTP 429 Too Many Requests after threshold, retry‑after header |
| REF‑N16 | Refund request with invalid tax override | Order #1034, $80.00 + tax | Tax amount manually set to negative | 1. Submit custom tax | Validation rejects negative tax, uses calculated tax |
| REF‑N17 | Refund request with unsupported payment gateway (test mode) | Order #1035, test gateway | Gateway configured in test mode | 1. Attempt refund | System allows test mode refund but logs as test, no real money movement |
| REF‑N18 | Refund request with missing required shipping address (for physical goods) | Order #1036, digital good | No shipping address required | 1. Attempt refund | Process proceeds, no address validation error |
| REF‑N19 | Refund request with future date (scheduled refund) not allowed | Order #1037, $50.00 | Scheduled date = tomorrow | 1. Attempt to schedule refund | Error “Scheduled refunds not supported” |
| REF‑N20 | Refund request with inaccessible file upload (corrupt image) | Order #1038, damaged item | Upload zero‑byte file | 1. Attempt to attach proof | Error “File too small or corrupt”, upload blocked |
These negative cases ensure defensive programming, proper validation, and clear user feedback.
Boundary and Edge Cases
Boundary tests focus on limits defined by business rules or technical constraints. Edge cases combine multiple boundaries or unusual states.
| ID | Title | Boundary Condition | Test Data | Steps | Expected Result |
|---|---|---|---|---|---|
| REF‑E01 | Refund exactly at return window cutoff | 30‑day window, order delivered 30 days ago today | Order #1040, delivered 2024‑10‑01, today 2024‑10‑31 | 1. Attempt refund at 23:59:59 | Refund allowed |
| REF‑E02 | Refund just outside cutoff (30 days + 1 sec) | Order delivered 30 days + 1 sec ago | Order #1041, delivered 2024‑09‑30 23:59:58, now 2024‑10‑31 00:00:01 | 1. Attempt refund | Error “Return period expired” |
| REF‑E03 | Minimum refund amount (e.g., $0.01) | lowest currency subunit | Order #1042, $0.01 | 1. Request full refund | Refund of $0.01 processed, gateway accepts sub‑cent if supported, else error “Amount too low” |
| REF‑E04 | Maximum refund amount (system limit) | e.g., $10,000 per transaction | Order #1043, $10,000.00 | 1. Request full refund | If allowed, processed; else error “Amount exceeds per‑transaction limit” |
| REF‑E05 | Refund with maximum line items (cart limit) | 100 items max | Order #1044, 100 × $1.00 items | 1. Request refund | Refund processes, inventory updated for all 100 items |
| REF‑E06 | Refund with zero‑price items (promo freebies) | Items priced $0 | Order #1045, 2 × $0.00 items + 1 × $20.00 | 1. Request full refund | $20.00 refunded, zero‑price items ignored in amount |
| REF‑E07 | Refund with decimal precision beyond currency subunits | Amount with 4 decimal places | Order #1046, $10.0045 | 1. Request refund | System rounds to nearest cent (or rejects based on config) |
| REF‑E08 | Refund with leap second or DST transition | Order timestamp at DST fall‑back | Order #1047, timestamp 2024‑11‑03 01:30:00 (ambiguous) | 1. Request refund | System uses UTC internally, processes correctly |
| REF‑E09 | Refund with maximum Unicode characters in reason | 500‑char limit, all Unicode | Order #1048, reason = 500 × emoji | 1. Submit reason | Accepted, stored correctly, no truncation |
| REF‑E10 | Refund with concurrent order modification (price drop) | Order price changed while refund pending | Order #1049, price $50 → $40 while refund API call in flight | 1. Start refund 2. Meanwhile admin reduces price 3. Complete refund | Refund uses original order amount at time of capture ($50) or system rejects due to version mismatch – depends on implementation; verify behavior |
| REF‑E11 | Refund with inventory at zero (out of stock) then restock during process | Inventory 0 → restocked while refund pending | Order #1050, item out of stock | 1. Request refund 2. Warehouse restocks item 3. Refund completes | Refund proceeds, inventory increased by 1 (restock + refund) – ensure no double count |
| REF‑E12 | Refund with payment gateway returning asynchronous pending status | Gateway returns “pending” then later “approved” | Order #1051, $45.00 | 1. Initiate refund 2. Gateway returns pending 3. Poll until approved | System shows “Refund pending”, later updates to completed, email sent on final state |
| REF‑E13 | Refund with network partition causing half‑sent request | Simulate lost ACK after request sent | Order #1052 | 1. Send refund request 2. Drop ACK 3. Retry logic | Idempotency prevents duplicate refund, final state consistent |
| REF‑E14 | Refund with user switching language mid‑flow | Start in English, switch to Spanish | Order #1053 | 1. Begin refund in EN 2. Change language to ES 3. Continue | All labels and messages displayed in ES, no loss of data |
| REF‑E15 | Refund with accessibility zoom 200% | Browser zoom 200% | Order #1054 | 1. Set zoom 200% 2. Navigate refund flow | All controls visible, no overlap, touch targets ≥44 dp |
| REF‑E16 | Refund with slow 3G network (simulated 150 ms latency) | Network throttling | Order #1055 | 1. Enable 150 ms latency 2. Complete refund | Flow completes within acceptable timeout, UI shows loading spinner |
| REF‑E17 | Refund with biometric authentication failure then fallback to PIN | Face ID fails, user selects PIN | Order #1056 | 1. Attempt refund 2. Face ID fails 3. Choose PIN 4. Enter correct PIN | Refund proceeds after PIN verification |
| REF‑E18 | Refund with expired session (token refresh) | Auth token expires after 5 min | Order #1057 | 1. Start refund 2. Wait 6 min 3. Continue | System silently refreshes token or prompts re‑login without losing entered data |
| REF‑E19 | Refund with mixed payment methods where one method is partially refunded earlier | Gift card $20 used, $10 remaining, card $30 | Order #1058 | 1. Refund $10 gift card (partial) 2. Later request full refund | System refunds remaining $10 gift card + $30 card, respects prior partial |
| REF‑E20 | Refund with audit log write failure (simulated DB deadlock) | DB deadlock on log insert | Order #1059 | 1. Trigger refund 2. Inject deadlock on log table 3. Observe | Refund still completed (or rolled back based on policy), alert raised for manual log reconciliation |
These edge cases often surface only under load or specific timing; automating them with tools that can inject faults (e.g., Chaos Mesh, WireMock) increases confidence.
Security and Compliance Cases
Refunds touch payment data, personal data, and are subject to regulations like PCI‑DSS, GDPR, and PSD2. Test cases must verify that controls are enforced.
| ID | Title | Regulation | Preconditions | Test Data | Steps | Expected Result |
|---|---|---|---|---|---|---|
| REF‑S01 | Refund API requires TLS 1.2+ | PCI‑DSS 4.1 | Order #1060, $50.00 | 1. Attempt refund via TLS 1.0 | Connection rejected, handshake failure | |
| REF‑S02 | Refund request logs mask PAN | PCI‑DSS 3.4 | Order #1061, Visa ending 4242 | 1. Refund 2. Inspect logs | Log shows “** ** 4242” or first six/last four digits only | |
| REF‑S03 | Refund does not return raw gateway response with sensitive fields | PCI‑DSS 6.5 | Order #1062 | 1. Refund 2. Capture API response | Response contains only transaction ID, status, amount; no CVV, full PAN | |
| REF‑S04 | Refund request enforces strong customer authentication (SCA) for amounts > €30 | PSD2 RTS | Order #1063, €35, EU card | 1. Refund without SCA challenge | Gateway declines with authentication_required, UI prompts 3DS2 challenge | |
| REF‑S05 | Refund request respects GDPR right to erasure – personal data removed after refund completion | GDPR Art. 17 | Order #1064, user requests deletion after refund | 1. Refund processed 2. User invokes delete account 3. Wait retention period | Personal data (name, email, address) anonymized or deleted per policy, transaction ID retained for legal hold | |
| REF‑S06 | Refund workflow prevents replay attacks using nonce | OWASP ASVS 4.0 | Order #1065 | 1. Capture valid refund request 2. Re‑send same request | Second request rejected with invalid nonce or duplicate transaction error | |
| REF‑S07 | Refund amount cannot be tampered via client‑side manipulation | OWASP A05:2021 | Order #1066, $100.00 | 1. Modify client‑side amount to $500 before submit 2. Submit | Server‑side validation rejects, logs tampering attempt | |
| REF‑S08 | Refund endpoint rate‑limits brute‑force attempts | OWASP A04:2020 | Order #1067 | 1. Send 100 rapid refund requests with varying amounts | After threshold, HTTP 429, IP temporarily blocked | |
| REF‑S09 | Refund data exported for audit is encrypted at rest | ISO 27001 A.10.1 | Order #1068 | 1. Trigger refund 2. Check database/filesystem | Refund tables/fields encrypted (AES‑256), key management logs present | |
| REF‑S10 | Refund notifications do not leak sensitive info in subject line | GDPR Art. 5(1)(f) | Order #1069 | 1. Refund 2. Inspect email subject | Subject contains order reference only, no amount or payment details | |
| REF‑S11 | Refund process verifies merchant account ownership before payout | PCI‑DSS 12.3 | Order #1070, merchant account ID M123 | 1. Attempt refund to different merchant ID | System rejects, logs unauthorized payout attempt | |
| REF‑S12 | Refund logs are immutable (write‑once) for forensic integrity | NIST SP 800‑53 AU‑9 | Order #1071 | 1. Attempt to update log entry via DB admin | Update prevented, attempt triggers alert | |
| REF‑S13 | Refund workflow includes automated fraud‑score check and can halt high‑risk transactions | Internal policy | Order #1072, high fraud score | 1. Refund request triggers score > threshold | System holds refund for manual review, notifies fraud team | |
| REF‑S14 | Refund respects regional law forbidding refunding refunds for digital goods after download | Consumer Rights Directive (EU) | Order #1073, e‑book downloaded | 1. Attempt refund after download | System blocks refund, shows “Non‑refundable after download” | |
| REF‑S15 | Refund test data is purged after test run to avoid leakage | Internal test policy | Order #1074 (test) | 1. Execute test suite 2. Verify test DB | No test‑specific order IDs remain in staging/production clones |
These cases ensure that your refund implementation does not become a weak point for attackers or regulators.
Accessibility and Localization Cases
Accessibility (WCAG 2.1 AA) and localization (i18n/l10n) are
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free