Skip to content

Expand test suite to 3562 tests, fix 3 emulator bugs#5

Merged
Segfaultd merged 8 commits intomainfrom
massive-unit-test-expansion
Apr 10, 2026
Merged

Expand test suite to 3562 tests, fix 3 emulator bugs#5
Segfaultd merged 8 commits intomainfrom
massive-unit-test-expansion

Conversation

@Segfaultd
Copy link
Copy Markdown
Contributor

@Segfaultd Segfaultd commented Apr 10, 2026

Summary

  • Expanded test suite from 512 to 3,562 tests (7x increase) — all passing
  • Added 376 real-world SDK simulation tests using the official Stripe Node client
  • Fixed 3 emulator bugs discovered during testing
  • Zero false positives in pre-landing review

Bug fixes (commit 3)

  1. Refund amount string concatenationsrc/routes/refunds.ts didn't parseInt the amount from form-encoded body, causing 0 + "2000" = "02000" on partial refunds
  2. Expand param format mismatch — routes only supported expand[]=field (curl) but not expand[0]=field (Stripe SDK). Added parseExpandParams() helper handling both formats across all 4 expandable routes
  3. No decline magic token — added tok_chargeDeclined which creates a card with last4 0002 (auto-decline), making decline testing possible without the internal actionFlags mechanism

Unit test expansion (commit 1)

Area Before After
Customers 22 202
Payment Intents 32 351
Payment Methods 26 200
Subscriptions 20 300
Invoices 25 250
Charges 0 150
Refunds 17 206
Products 24 149
Prices 22 156
Setup Intents 24 200
Events 26 114
Test Clocks 16 122
Webhook Endpoints 5 80
Webhook Delivery 11 120
Lib utilities 44 258
Middleware 22 86
Errors 4 47
DB 4 19

SDK simulation tests (commit 2)

Real flows using stripe npm package — testing actual Stripe API behavior:

File Tests Scenarios
e-commerce.test.ts 69 Checkout, capture, decline (actionFlags + tok_chargeDeclined), 3DS, refunds, idempotency, SDK expand
saas-subscription.test.ts 55 Onboarding, trials, plan changes, cancellation, billing cycles via test clocks
billing-invoices.test.ts 49 Invoice lifecycle, state machine enforcement, subscription invoicing
webhook-ecosystem.test.ts 49 Event delivery with HMAC verification, routing, signature validation
error-handling-and-edge-cases.test.ts 45 Auth errors, 404s, validation, state transitions, idempotency
product-catalog.test.ts 40 Product/price CRUD, SaaS pricing page, catalog→subscription
search-and-pagination.test.ts 40 Customer/PI search, cursor pagination, expand resources
setup-and-future-payments.test.ts 39 Save card via SetupIntent, charge later, 3DS setup

Test plan

  • bun test — 3,562 pass, 0 fail (47s)
  • bun x tsc --noEmit — clean
  • Pre-landing review: no issues found

Next.js requires @types/node for TypeScript type checking during
build. Without it, the docs CI build fails.
Comprehensive coverage across all services, lib utilities, and middleware:

- Customers: 22 → 202 tests
- Payment Intents: 32 → 351 tests (full state machine coverage)
- Payment Methods: 26 → 200 tests (all magic tokens)
- Subscriptions: 20 → 300 tests (items, trials, billing)
- Invoices: 25 → 250 tests (draft→open→paid/void lifecycle)
- Charges: 0 → 150 tests (new file)
- Refunds: 17 → 206 tests (partial/full refund scenarios)
- Products: 24 → 149 tests
- Prices: 22 → 156 tests (one-time + recurring)
- Setup Intents: 24 → 200 tests
- Events: 26 → 114 tests
- Test Clocks: 16 → 122 tests (advance + billing integration)
- Webhook Endpoints: 5 → 80 tests
- Webhook Delivery: 11 → 120 tests (signatures, matching, retries)
- Lib utilities: 44 → 258 tests (expand, id-gen, pagination, search, timestamps, event-bus, action-flags)
- Middleware: 22 → 86 tests (auth, form-parser, idempotency)
- Errors: 4 → 47 tests
- DB: 4 → 19 tests
8 new test files with 376 tests that exercise full Stripe API flows
through the official SDK, testing actual business logic and state
transitions rather than field-level assertions:

- e-commerce.test.ts (59): Checkout, manual capture, partial capture,
  declined cards, 3DS authentication, refunds, idempotency, expansion
- saas-subscription.test.ts (55): Onboarding, trials, plan upgrades,
  cancellation, billing cycles via test clocks, multi-subscription
- billing-invoices.test.ts (49): Invoice lifecycle (draft→open→paid/void),
  state machine enforcement, subscription invoicing, search
- webhook-ecosystem.test.ts (49): Event delivery with HMAC verification,
  customer/payment/subscription webhooks, routing, signature validation
- product-catalog.test.ts (40): Product/price CRUD, SaaS pricing page
  setup, catalog-to-subscription flow
- search-and-pagination.test.ts (40): Customer/PI search, cursor-based
  pagination, expand related resources
- setup-and-future-payments.test.ts (39): Save card via SetupIntent,
  charge later, 3DS setup, cancel flows
- error-handling-and-edge-cases.test.ts (45): Auth errors, 404s,
  validation errors, state transition errors, idempotency
@Segfaultd Segfaultd changed the title Expand unit test suite from 512 to 3176 tests Expand test suite from 512 to 3552 tests with real SDK simulation Apr 10, 2026
…lined

Three bugs discovered during SDK testing:

1. Refund route didn't parseInt the amount from form-encoded body,
   causing string concatenation when accumulating partial refunds
   (e.g. 0 + "2000" = "02000" instead of 2000)

2. Expand params only supported expand[]=field format (curl/raw) but
   not expand[0]=field (Stripe SDK). Added parseExpandParams() helper
   that handles both formats, updated all 4 routes that use expansion.

3. No magic token for declined cards — added tok_chargeDeclined which
   creates a card with last4 "0002" (triggers automatic decline in
   the payment simulation). Previously, decline testing required the
   internal actionFlags.failNextPayment mechanism.

Added 10 new SDK tests verifying all three fixes work end-to-end.
@Segfaultd Segfaultd changed the title Expand test suite from 512 to 3552 tests with real SDK simulation Expand test suite to 3562 tests, fix 3 emulator bugs Apr 10, 2026
All list endpoints used `gt(created, cursor.created)` for cursor-based
pagination, which broke when multiple items shared the same second-
precision timestamp — the cursor would skip items or return empty pages.

Fix: Added `cursorCondition()` helper that uses a composite cursor:
  (created > cursor.created) OR (created = cursor.created AND id > cursor.id)

Combined with `ORDER BY created, id` on all list queries, this ensures
deterministic, gap-free pagination regardless of creation timing.

Also fixed:
- Events service: was using eq() instead of lt() for desc-ordered cursor
- Events service: added secondary desc(id) sort for same-second ordering
- Test clocks service: cursor was validated but completely ignored
- Webhook endpoints service: cursor was validated but completely ignored
Removed all workarounds that weakened pagination test assertions:

- Replaced toBeGreaterThanOrEqual(0) with exact count assertions
- Removed createSIsWithDistinctTimestamps() manual timestamp patching
- Removed setTimeout(1100ms) delays between item creation
- Removed "same-second limitation" comments and test name suffixes
- Removed 2 trivial workaround-only tests (prices, products)
- Rewrote charges pagination tests to use service.create() instead
  of manual DB insertion with fake timestamps

All pagination tests now properly assert:
- Exact item counts per page
- No duplicates across pages
- All items collected across full traversal
@Segfaultd Segfaultd merged commit c6dd603 into main Apr 10, 2026
2 checks passed
@Segfaultd Segfaultd deleted the massive-unit-test-expansion branch April 10, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant