Commit 1a11604
test(e2e): Wave 4b — UI-driven Razorpay TEST-card payment E2E (free → upgrade → Pro) (#194)
* test(e2e): Wave 4b — UI-driven Razorpay TEST-card payment E2E (free → upgrade → Pro)
The CEO ask: "There is no CI that actually tries to create a test user, then
tries to upgrade and enter test details and check everything is working fine."
This adds the real UI loop. Design: docs/ci/01-CI-INTEGRATION-DESIGN.md
§"Razorpay test-card payment E2E" (Approach A) + the api Wave 4b PR (cohort
test-mode rzp_test_* checkout routing).
e2e/live-ui-payment.spec.ts — TWO tests, two lanes:
1. @pr-smoke CONTRACT-ONLY (PR-able, no card entry): mint a free cohort user
via the factory → drive the dashboard /app/checkout?plan=pro UI →
createCheckout → assert the SPA reaches a Razorpay checkout URL, OR the
inert cohort path (synthetic_test_cohort 403, when rzp_test_* keys aren't
wired), OR the honest billing-not-configured fallback. All three prove the
UI→api→checkout wiring end-to-end against the REAL api. Reaped.
2. FULL card-entry (nightly only, gated on E2E_RAZORPAY_TEST_MODE=1): same up
to the Razorpay page, then fill the subscription test card
4718 6091 0820 4366 + OTP 1234 (cross-origin iframes + popup handled), submit
→ poll /api/v1/capabilities for tier=pro (the real TEST-mode webhook drives
the upgrade). RESILIENT + SOFT-FAILS (skip-with-reason) on a Razorpay
markup change or an unreachable webhook so a UI change never reds the
nightly. Deterministic upgrade is covered by the api webhook-injection suite.
Wiring: the spec matches live-*.spec.ts so it runs in e2e-prod.yml (30-min) +
e2e-live.yml (nightly staging); the @pr-smoke leg runs per-PR via
e2e-pr-smoke.yml. Both nightly workflows now pass E2E_RAZORPAY_TEST_MODE from a
repo var (inert until the operator wires test keys) + arm the factory token.
Gating: skips clean until E2E_LIVE/E2E_ACCOUNT_TOKEN (and, for the card leg,
E2E_RAZORPAY_TEST_MODE) are set. Verified live: the @pr-smoke contract-only test
PASSES against prod api.instanode.dev (minted free cohort → UI → reached the
inert cohort path, reaped). npm run gate green (tsc + build + 1129 vitest).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(e2e): anchor Razorpay host check — fix CodeQL js/regex/missing-regexp-anchor
CodeQL flagged the unanchored /(razorpay\.com|rzp\.io)/i regex used to validate
a reached checkout URL: an unanchored substring match means a hostile URL like
https://evil.com/?x=razorpay.com would pass. Replace the assertion with a parsed
isRazorpayCheckoutHost() that inspects the URL hostname (exact apex or subdomain
match), and anchor the Playwright route() regex on scheme + exact host segment.
No security weakening — strictly tightens the host check.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent fec01d6 commit 1a11604
3 files changed
Lines changed: 572 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
107 | 116 | | |
108 | 117 | | |
109 | 118 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
160 | 160 | | |
161 | 161 | | |
162 | 162 | | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
163 | 170 | | |
164 | 171 | | |
165 | 172 | | |
| |||
0 commit comments