jam-cloud/web/ai/tasks/test-subscriptions-plan.md

3.8 KiB
Raw Blame History

Subscription/Recurly Test Plan (Rails 8 Branch)

Objective

Close subscription lifecycle regressions by adding executable tests in web and ruby that do not depend on live Recurly network calls.

What Exists

  • Webhook coverage exists (request + model) and is active.
  • Legacy Recurly suites were revived and are now active:
    • ruby/spec/jam_ruby/recurly_client_spec.rb
    • ruby/spec/jam_ruby/models/user_subscriptions_spec.rb
  • Active live Recurly integration coverage now exists in (opt-out via SKIP_LIVE_RECURLY=1):
    • ruby/spec/jam_ruby/integration/recurly_live_integration_spec.rb

Priority 1: API Subscription Lifecycle (web/spec/requests)

Add request specs for ApiRecurlyController with RecurlyClient stubbed.

1.1 Plan-first then payment

  • POST /api/recurly/change_subscription with paid plan and no billing info:
    • expect desired plan is set and response indicates payment method still needed.
  • POST /api/recurly/update_payment with token:
    • expect handle_create_subscription called with users desired plan.
    • expect success payload includes plan metadata and has_billing_info = true.

1.2 Payment-first then plan

  • POST /api/recurly/update_payment first (no desired plan yet):
    • expect no failure and billing info persisted.
  • Then POST /api/recurly/change_subscription to paid plan:
    • expect desired plan update call and success response.

1.3 Negative paths

  • change_subscription with unchanged plan:
    • expect 422 and No change made to plan.
  • update_payment when client raises RecurlyClientError:
    • expect 404 + serialized error payload.

Priority 2: Sync Decision Tree (ruby/spec/jam_ruby/models)

Add focused unit specs for RecurlyClient#sync_subscription with Recurly API mocked.

2.1 Unchanged/good-standing path

  • account exists, not past_due, active subscription, desired == effective.
  • expect sync code good_standing_unchanged and no plan mutation.

2.2 Canceled/expired path

  • no active subscription (or expired).
  • expect effective plan set to free (nil) and sync code no_subscription_or_expired.

2.3 Past-due path

  • account has_past_due_invoice = true.
  • expect effective plan dropped to free and sync code is_past_due_changed.

2.4 Trial and free-month behavior

  • user in trial with desired gold and active account.
  • verify trial code path + post-trial behavior once time advances (use Timecop or travel_to depending what is stable in this suite).

Priority 3: Hourly Job Integration (ruby/spec/jam_ruby/resque or model-level)

  • Validate JamRuby::HourlyJob.perform triggers User.hourly_check.
  • Validate User.subscription_sync only selects intended users and calls client sync.
  • Validate User.subscription_transaction_sync advances GenericState.recurly_transactions_last_sync_at using mocked transaction stream.

Priority 4: Browser Coverage (web/spec/features)

Add high-value feature coverage for subscription management screen:

  • plan-first flow shows payment-needed state and routes to update payment.
  • payment-first flow then selecting plan results in active paid subscription state.

Use stubs/fakes around RecurlyClient in feature env to avoid external dependency.

Execution Order

  1. Request specs for ApiRecurlyController (fast, high signal).
  2. RecurlyClient#sync_subscription specs (logic-heavy, deterministic).
  3. Hourly sync integration coverage.
  4. Browser feature tests for UX flow parity.

Definition of Done

  • New tests are active (not xdescribe/commented out).
  • Both plan-first and payment-first lifecycles are covered.
  • Hourly sync scenarios for unchanged, canceled/expired, and past-due are covered.
  • First-free-month/gold behavior has explicit time-based assertions.
  • docs/dev/subscriptions.md updated with links to new spec files and scenarios.