Promo Codes Testing Checklist (2026)

Promo Codes Testing Checklist (2026)

January 22, 2026 · 20 min read · Testing Checklists

Promo Codes Testing Checklist (2026)

A promo code is a short alphanumeric token that unlocks a discount, free trial, gift, or other incentive when entered during checkout or account creation. Testing promo codes thoroughly prevents revenue leakage, protects brand trust, and avoids regulatory pitfalls. The checklist below groups 38 concrete items into seven functional areas plus a release‑readiness section. Each item includes a pass criterion, a real‑world example, and notes on how manual, automated, or autonomous exploration (e.g., with SUSA) can cover it.

---

Promo Codes Testing Checklist (2026) – Happy Path

Core redemption flow

#Test ItemPass CriterionExampleAutomation Hint
1Valid code entry on checkout pageDiscount applied correctly, order total reflects new amount, confirmation shows code usedCode “SPRING20” gives 20 % off a $100 cart → $80 totalUI test enters code, asserts price change
2Code applied before paymentDiscount visible on cart summary before proceeding to paymentUser sees “- $20” line item after code entryAssert DOM element text before “Pay” button click
3Code works on first‑time userNew account receives discount, no prior purchase requiredGuest checkout with code “WELCOME10” → 10 % offCreate fresh test user, run flow
4Code works for returning userExisting logged‑in user can redeem without re‑authenticationLogged‑in user applies “LOYALTY15” → discount appliedUse session cookie or login API
5Code works across devicesSame code yields identical discount on mobile web, native app, and desktopCode “BLACKFRIDAY” works on iOS app, Android web, ChromeRun matrix of device/OS combos
6Code works with multiple itemsDiscount applies to cart total, not per‑item unless specifiedCart with 3 items ($30 each) → 10 % off total $90 → $81Assert total after code entry
7Code works with shipping taxesDiscount calculated before tax/shipping or after, per business ruleIf discount pre‑tax: $100 + $10 tax → 20 % off $100 = $80 + $10 tax = $90Verify tax line matches rule
8Code works with gift cardsGift‑card balance + promo discount both applied$50 gift card + “SAVE5” → $5 off → final $45 chargeCheck both balances updated
9Code works with subscription plansRecurring discount applied to first billing cycleCode “FIRSTMONTHFREE” → $0 first month, then regular priceVerify subscription object shows discount flag
10Code works with bundled offersBundle discount stacks or does not stack per policyBundle “BOXSET” 15 % off + code “EXTRA10” → either 23.5 % stacked or 15 % onlyValidate against promo‑stacking rule

Success messaging & receipt

#Test ItemPass CriterionExampleAutomation Hint
11Success toast/message appearsNon‑blocking toast with code name and discount amount displayed for ≥2 s“SPRING20 applied – saved $20”Wait for toast element, assert text
12Order confirmation email includes codeEmail body lists redeemed promo and discounted amount“Promo: SPRING20 – Discount: $20.00”Parse email fixture, assert substring
13Order history shows promo usageUser’s order detail page shows promo code field populatedOrder #12345 → Promo: WELCOME10API GET /orders/{id} assert promo field
14Loyalty points adjusted (if applicable)Points earned reflect discounted spend, not originalSpend $80 after 20 % off → earn 8 points (10 pts/$)Check points balance after order
15Referral credit not double‑countedIf promo and referral both apply, each credited onceReferral gives $5, promo gives 10 % → total correctVerify both credits in ledger

---

Promo Codes Testing Checklist (2026) – Error Handling

Invalid code detection

#Test ItemPass CriterionExampleAutomation Hint
16Non‑existent codeError message “Invalid promo code” displayed, no discount appliedEnter “FAKE123” → toast: “Code not found”Assert error element visible, price unchanged
17Expired codeMessage “This promo has expired”Enter “SUMMER21” after 30 Sep 2021 → errorSet system date or use backend flag
18Code used beyond usage limitMessage “This promo has reached its usage limit”Code limited to 100 uses, 101st entry failsPre‑populate usage counter via API
19Code not applicable to cart itemsMessage “Promo not valid for selected items”Code for “Shoes only”, cart contains a shirtVerify error, discount not applied
20Code requires minimum spendMessage “Spend $50 to use this promo”Cart $30 + code “SAVE10” → errorTest cart just below and just above threshold
21Code restricted to user segmentMessage “This promo is for new users only”Existing user tries “NEWUSER20” → errorAttach user‑type flag, assert denial
22Code case‑sensitivity handlingSystem treats code as case‑insensitive (or as defined)If case‑insensitive, “spring20” works; if strict, failsTry both variations
23Code with special charactersAccepts hyphen, underscore, or rejects per spec“SPRING-20” accepted; “SPRING@20” rejected if not allowedSend varied strings, check response
24Leading/trailing whitespaceSystem trims whitespace before validationEnter “ SPRING20 ” → acceptedSend code with spaces, assert success
25Code length limitsRejects codes shorter than min length or longer than maxMin 5, max 12 → “ABCD” rejected, “ABCDEFGHIJKL” rejectedBoundary test with 4,5,12,13 chars
26Duplicate submission preventionSecond submit of same code shows “already applied” not errorAfter first apply, clicking Apply again → toast “Code already used”Click button twice, verify state
27Network timeout fallbackUI shows retry option, does not apply discount twiceSimulate 5 s delay on /apply endpoint → show retryMock server delay, assert UI behavior
28Server error (5xx) handlingShows generic “Try again later”, does not consume codeReturn 500 on apply → error toast, code still validMock 500, verify code not marked used
29Client‑side validation bypassEven if JS disabled, server rejects invalid codeDisable JS, submit “BADCODE” → server errorUse curl or fetch without JS, assert 400
30Race condition under high loadConcurrent requests for same limited‑use code grant discount to only one user10 users submit same code simultaneously → only 1 succeedsUse k6 or Locust to fire parallel requests, check counts

---

Promo Codes Testing Checklist (2026) – Edge / Boundary Cases

Discount calculations

#Test ItemPass CriterionExampleAutomation Hint
31Percentage >100%System rejects or caps at 100 % (per policy)Code “FREE200” → error or free itemTry 150 % code, assert rejection or zero price
32Fixed amount > cart totalDiscount cannot make total negative; total set to $0Cart $5, code “TAKE10” → $0 total, not –$5Assert max(0, total‑discount)
33Fractional cents handlingRounding follows bankers’ rounding or defined rule$49.99 with 33 % off → $33.4935 → $33.49 or $33.50Compute expected, assert exact cents
34Multiple percentage stacksIf stacking allowed, apply sequentially not additively10 % then 10 % on $100 → $81, not $80Apply two codes, verify final
35Tiered discount thresholdsDifferent % based on spend brackets$0‑$49 → 5 %; $50‑$99 → 10 %; $100+ → 15 %Test cart values at each boundary
36Time‑zone sensitivityPromo active based on UTC start/end, not localCode active 00:00 UTC Jan 1 – 23:59 UTC Jan 31Set device TZ, verify activation/inactivation
37Daylight‑saving shiftNo double‑count or skip when clocks changePromo runs 01:00‑03:00 local, DSB shift → still 2 h windowSimulate clock change, check active period
38Leap year February 29Promo scheduled for Feb 29 works only on leap yearsCode “LEAP2024” active Feb 29 2024, not 2025Set date to 2024‑02‑29, assert active; 2025‑02‑28 assert inactive

Input & UI edge cases

#Test ItemPass CriterionExampleAutomation Hint
39Max length fieldInput field accepts up to defined max, blocks extraField max 12 → typing 13th char blocked or trimmedSend long string, assert length
40Paste from clipboardPasted code validated same as typedPaste “SPRING20” → worksUse clipboard API in test
41Autocomplete suggestionsNo suggestion reveals inactive or expired codesTyping “SPR” shows only active codesObserve dropdown, assert no expired
42Right‑to‑left language layoutField aligns correctly, cursor moves as expectedArabic UI: code entry right‑alignedSwitch locale, inspect direction
43Zoom level 200%All elements readable, no overlapPromo entry visible at 200% zoomSet browser zoom, assert no overflow
44Screen orientation changeState preserved on rotateEnter code, rotate to landscape → code still shownRotate device/emulator, assert field value
45Hardware keyboard vs on‑keyboardBoth produce same resultDesktop keyboard entry works, mobile OSK worksTest both input methods
46Voice input transcriptionVoice‑to‑text yields correct codeSay “spring two zero” → “SPRING20”Use speech API, verify result
47Barcode/QR code scanScanned code populates field and validatesScan QR encoding “SPRING20” → field filledUse camera mock, assert success
48Copy‑protected fieldRight‑click copy disabled if requiredAttempt to copy code from tooltip → blockedTry document.execCommand('copy'), expect failure
49Invalid Unicode normalizationDifferent visual forms treated same“SPRING20” with full‑width chars → acceptedSend full‑width variants, assert same outcome
50Emoji injectionEmoji ignored or causes validation errorEnter “SPRING20😀” → rejectedSend emoji, assert error

---

Promo Codes Testing Checklist (2026) – Accessibility

#Test ItemPass CriterionExampleAutomation Hint
51Label associationEach input has associated or aria-labelaxe-core asserts label present
52Keyboard navigableTab moves focus to code field, Apply button, then nextTab order: field → button → continueSimulate Tab key, check focus order
53Visible focus indicatorField shows outline ≥2 px when focusedCSS outline: 2px solid #005fccCheck computed style on focus
54Error message ARIA liveInvalid code triggers aria-live="assertive" region
Assert live region updates on error
55Contrast ratioText and background meet WCAG AA (≥4.5:1)Promo text #212529 on #fff → 7.5:1Use axe or manual contrast tool
56Scalable textUp to 200% text size does not break layoutIncrease browser font size → field still usableSet font-size: 200%, assert no overflow
57Screen reader announces discountAfter successful apply, reader says “Promo SPRING20 applied, saved $20”Use NVDA or TalkBack to verifyRecord utterance, assert phrase
58Touch target sizeApply button ≥44 dp × 44 dpButton dimensions 48 × 48 dpMeasure via UIAutomator or Espresso
59Reduced motion respectedAnimation disabled if prefers-reduced-motionNo fade/tooltip slide when setting enabledCheck CSS media query, assert no animation
60High contrast modeColors invert or adapt correctlyIn Windows HC mode, promo field uses system colorsEnable HC, assert readable contrast
61Language switch preserves stateChanging language does not clear entered codeEnter code, switch to French → code still presentChange lang attribute, assert field value
62Error announcement timingError announced within 400 ms of invalid entryLive region triggers promptlyMeasure time between input and screen reader output
63Focus returned after modalAfter promo‑info modal closes, focus returns to fieldClose “How promo works” dialog → focus on fieldTrigger modal, close, assert activeElement
64No placeholder as sole labelPlaceholder not used as only label (fails WCAG)Field has both placeholder and visible labelInspect DOM, fail if only placeholder
65Accessible name for icon-only buttonApply button with icon has aria-label="Apply promo"Icon button Assert aria-label present
66Skip link to promo fieldEarly skip link jumps directly to promo entrySkip to promoActivate link, assert focus on field
67Responsive breakpoint accessibilityLayout does not hide promo field on small screens@media (max-width:320px) field still visibleResize viewport, assert field present
68No autoplay audio on promo pagePage does not play sound automaticallyNo Scan DOM for audio elements without user gesture
69Error message announced in user languageIf UI language is Spanish, error appears in Spanish“Código no válido”Change locale, assert translated message
70Focus trap in modalWhen promo‑info modal opens, tab does not escapeTab cycles within modal until closedOpen modal, press Tab repeatedly, assert focus stays inside

---

Promo Codes Testing Checklist (2026) – Security & Privacy

#Test ItemPass CriterionExampleAutomation Hint
71Code leakage in URLPromo code never appears in query string or fragmenthttps://shop.example/cart?promo=SPRING20 → forbiddenInspect network calls, assert no promo in URL
72Code masked in logsBackend logs replace promo with *Log line: Applied promo: ****Check log samples, assert masking
73Rate limiting on apply endpointMax N requests per IP/minute to prevent brute force10 requests/min → 11th returns 429Use curl loop, assert 429 after limit
74JWT/session bindingPromo apply requires valid authenticated sessionAnonymous POST to /apply returns 401Send request without cookie, assert 401
75Code entropy checkSystem rejects predictable sequences (e.g., “111111”)“111111” → error “code too weak”Try weak patterns, assert rejection
76No SQL injection via promo fieldInput sanitized, injection attempt fails' OR 1=1-- → error, no DB errorSend payload, assert no 500, DB unchanged
77No XSS via promo displayRendered code escaped, no script execution rendered as textInject script, assert not executed in DOM
78CSP blocks inline scriptContent‑Security‑Policy prevents inline JS from promo UIscript-src 'self' blocks attemptsVerify CSP header, try to inject