Skip to content

test(billing): W3 billing-block integration suite — purchasable-set, no self-serve cancel/downgrade, webhook tier transitions#247

Merged
mastermanas805 merged 2 commits into
masterfrom
w3/billing-block-integration-tests-2026-06-04
Jun 4, 2026
Merged

test(billing): W3 billing-block integration suite — purchasable-set, no self-serve cancel/downgrade, webhook tier transitions#247
mastermanas805 merged 2 commits into
masterfrom
w3/billing-block-integration-tests-2026-06-04

Conversation

@mastermanas805

Copy link
Copy Markdown
Member

What

Closes the biggest gap in docs/sessions/2026-06-04/USER-FLOW-INVENTORY-AND-TEST-MATRIX.md §E: the revenue-critical billing block had near-zero real-backend integration coverage. Adds a DB-backed (TEST_DATABASE_URL) integration suite in the handlers package.

All NEW files — no edits to billing.go or any existing billing_*_test.go, so no conflict with the in-flight #246 (W0). Reuses existing helpers (seedVerifiedTeamUser, cov2CheckoutApp, changePlanAppReal/changePlanReq, postCheckoutReq, cov2WebhookAppReal, signRazorpayPayload, makeSubscriptionChargedPayloadWithPlan, makeSubscriptionCancelledPayload); none redefined.

Coverage

  • Team is NOT buyable (§E3) — registry-iterating assertion TestBillingBlock_SelfServePurchasableSet_IsExactlyHobbyHobbyPlusPro drives every plans.Registry tier through the real CreateCheckoutAPI and asserts the set reaching the Razorpay CreateSubscription seam is exactly {hobby, hobby_plus, pro}. Reds if Team is re-enabled or a new tier silently becomes chargeable (rule 18). Team → 400 tier_not_yet_available; growth → invalid_plan. Mirrored for the change-plan surface.
  • No self-serve cancel/downgrade (§E10) — router.go source-scan negative assertion (no non-admin cancel/downgrade route) + ChangePlanAPI rejects every lower/equal target with downgrade_not_self_serve + a support agent_action, asserting team tier is left unchanged. same_plan edge covered.
  • Webhook tier transitions (§E4/E5/E6/E7)subscription.charged upgrade elevates plan_tier AND promotes all active resources (rule 5); subscription.cancelled downgrade drops plan_tier to the courtesy floor but leaves resource tiers (user-benefit asymmetry); bad signature → 400 invalid_signature (tier unchanged); unknown team → 404 team_not_found (rows-affected-0 / ErrTeamNotFound).
  • Checkout graceful failure — unconfigured plan_id → 503 billing_not_configured; live-key-in-nonprod → 503 billing_misconfigured (CreateSubscription never called).

Gate

internal/handlers green for all new tests. The registry-iterating assertion was verified failing-then-passing (reds when team is added to the expected purchasable set). The 20 unrelated handlers/models failures in full ./... are pre-existing local-env flakes (NATS/customer-DB/GitHub creds unreachable on a bare laptop) — verified to reproduce identically on clean origin/master with these files stashed (diff of introduced failures is empty). CI is authoritative.

🤖 Generated with Claude Code

…no self-serve cancel/downgrade, webhook tier transitions

Closes the matrix's biggest gap (USER-FLOW-INVENTORY-AND-TEST-MATRIX.md §E):
the revenue-critical billing block had near-zero real-backend integration
coverage. New DB-backed tests (handlers package, TEST_DATABASE_URL), all NEW
files — no edits to billing.go or existing billing_*_test.go (avoids #246 W0).

- Registry-iterating purchasable-set assertion (§E3): drives EVERY plans.Registry
  tier through the real CreateCheckoutAPI handler; asserts the set that reaches
  the Razorpay CreateSubscription seam is EXACTLY {hobby, hobby_plus, pro}.
  Reds if Team is re-enabled or a new tier silently becomes chargeable (rule 18).
  Team → 400 tier_not_yet_available; growth → invalid_plan; both checkout +
  change-plan surfaces gated.
- No self-serve cancel/downgrade (§E10): router.go source-scan negative
  assertion (no non-admin cancel/downgrade route) + ChangePlanAPI rejects every
  lower/equal-tier target with downgrade_not_self_serve + support agent_action,
  asserting the team tier is left UNCHANGED. same_plan edge covered.
- Webhook tier transitions (§E4/E5/E6/E7): subscription.charged upgrade elevates
  plan_tier AND promotes all active resources (rule 5); subscription.cancelled
  downgrade drops plan_tier to the courtesy floor but LEAVES resource tiers
  (user-benefit asymmetry); bad signature → 400 invalid_signature, tier
  unchanged; unknown team → 404 team_not_found (rows-affected-0 / ErrTeamNotFound).
- Checkout graceful failure: unconfigured plan_id → 503 billing_not_configured;
  live-key-in-nonprod → 503 billing_misconfigured (CreateSubscription never called).

Reuses existing helpers (seedVerifiedTeamUser, cov2CheckoutApp,
changePlanAppReal/Req, postCheckoutReq, cov2WebhookAppReal, signRazorpayPayload,
makeSubscriptionChargedPayloadWithPlan, makeSubscriptionCancelledPayload) — none
redefined. Handlers package green; the 20 unrelated handlers/models failures in
full ./... are pre-existing local-env flakes (NATS/customer-DB/GitHub creds),
verified to reproduce identically on clean origin/master — CI is authoritative.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mastermanas805 mastermanas805 enabled auto-merge (squash) June 4, 2026 19:56
@mastermanas805 mastermanas805 merged commit 804bffe into master Jun 4, 2026
18 checks passed
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