Stripe's Payment Element requires elements.submit() to be awaited before
stripe.confirmPayment() in any flow that does async work between the
user click and confirm (deferred-intent, billing-details/plan resolution,
client_secret fetch). Without it Stripe throws:
IntegrationError: elements.submit() must be called before
stripe.confirmPayment()
This restores the guard originally added in 9f51583 (shipped in
preview.6) which was lost in the merge that produced preview.9, leaving
preview.9 and preview.10 unable to complete paid checkout.
Applied to both payment surfaces:
- utils/confirmPayment.ts (used by PaymentForm via CheckoutLayout)
- primitives/TopupForm.tsx
Added a regression test in confirmPayment.test.ts asserting the
submit-before-confirm ordering and that submitError short-circuits
confirmPayment, so CI will catch this regression next time.
Ref: https://stripe.com/docs/payments/accept-a-payment-deferred
Made-with: Cursor