Skip to main content
This playbook is the minimum required test matrix before any change to cart, shipping, payment, or order modules merges to main. It pairs backend orchestration, the payment gateway, the checkout UI, and the storefront — a missed regression in any of these costs real orders.

Cadence

  • Per PR touching cart, order, payments, or any PSP module: run the smoke sequence
  • Weekly against production: full matrix (smoke + cross-PSP + idempotency)
  • Pre-release for every backend tag: full matrix + chaos drills

1. Test fixtures

A reliable stability program needs known-good and known-broken fixtures so every regression test has predictable inputs.
Never point smoke tests at real merchant shops. Use the fixture shops below.

Fixture shops

Fixture customer accounts

Test-mode-only — never real cards.

Fixture environments

  • Stage (apiv3stage + checkoutstage) — primary smoke target. Hits Stripe test mode, EasyPost test API, PayMob sandbox, Telr sandbox.
  • Production (apiv3prod + checkout.droplinked.io) — full live target. Run from a UAE-IP runner for IP-allowlist coverage.
  • Local docker compose — backend-only assertions; can’t exercise full Stripe Elements.

Fixture freshness

Schedule a weekly clean of qa-* shop carts older than 7 days, void all qa+* test charges, and archive completed test orders. Stops fixture rot from masking regressions.

2. Per-PR smoke sequence

Twelve assertions. Should complete in under 10 minutes against stage.
A PR that breaks any of S1–S12 against stage must not merge.
S1–S6 + S7 + S9 should run automatically in CI. S5, S11, S12 require Stripe sandbox client interaction (Playwright against test mode).

3. Cross-PSP matrix (weekly)

Run the same 12 scenarios across each enabled PSP for the relevant currency. For each row, capture:
  • Time-to-complete checkout (p50, p95)
  • Webhook latency (PSP → integration service → backend)
  • Order status transition path
  • Cart-preserved-on-failure behavior

4. Idempotency + replay matrix

Every PR that touches webhook handlers or cart-status transitions must pass:

5. Chaos drills (pre-release / monthly)

Test failure modes that only happen in production.

6. Known regression — EasyPost silently uses custom strategy

A product configured with shippingProfileId = 'easypost' can silently fall through to the custom shipping strategy if the strategy factory only registers Printful + Custom. The custom strategy’s canHandle returns true for any non-Printful profile, so EasyPost-tagged products get routed to a strategy expecting merchant flat-rate config. Result: empty availableShipping, checkout dead-ends at “Shipping these items is not available to this address.”
Fix path:
1

Implement an EasyPost shipping strategy

Wrap the easy-post module’s rate-fetch in a ShippingRateStrategy adapter.
2

Register it ahead of the custom strategy

Add it to the strategy factory’s default-initialization list before the custom strategy.
3

Tighten canHandle

Update the custom strategy to only return true for explicit 'custom' / 'flat-rate' identifiers — never as a catch-all.
4

Guard the regression

S9 in the per-PR smoke matrix is the standing regression guard once the strategy ships.

7. Tooling roadmap

What we have:
  • A narrowly-Bonum stress-test script — pattern-extend for other PSPs
  • Some payment-gateway specs needing repo-level jest cleanup
  • A backend CI workflow with lint+test as a soft-fail
What we need:
1

Playwright suite for S1–S12

Drive Stripe Elements test-mode card entry; assert on backend cart state via direct API checks between UI steps.
2

GitHub Actions workflow

checkout-smoke.yml runs the Playwright suite on every PR labelled area:checkout or touching cart/order/payments modules.
3

Tagged Stripe test-mode dashboard

Isolate regressions from real-money flow with a dedicated dashboard tag.
4

Weekly UAE-egress cron

Run sections 2 + 3 + 4 against production weekly from a UAE-IP runner; post to a #stability channel.
5

Chaos toolkit

Toxiproxy (or similar) for section 5 drills.

Appendix — “Shipping these items is not available” fault tree

Walk this tree from leaf upward to pin which node fired. Update the tree when a new node is discovered.