Files
fizzy/saas/test/models/account/billing_test.rb
T
Jeremy Daer f2ff5af4f5 Sync email to Stripe when user changes email address (#2432)
* Sync owner email to Stripe when changed

When an account owner changes their email address, update the
corresponding Stripe customer record via a background job.

Also handles ownership transfers: when a user becomes the account
owner, their email is synced to Stripe.

Responsibility chain:
- User::NotifiesAccountOfEmailChange triggers on owner identity change
  or when a user becomes owner
- Account::Billing#owner_email_changed enqueues sync job
- Account::SyncStripeCustomerEmailJob performs the update with
  polynomial backoff retries
- Account::Subscription#sync_customer_email_to_stripe calls Stripe API

* Address PR feedback: error handling and test coverage

- Handle Stripe::InvalidRequestError in sync_customer_email_to_stripe
  (mirrors cancel method behavior for deleted customers)
- Add test for deactivated owner (owner with nil identity)
- Add test for deleted Stripe customer scenario
2026-01-25 14:20:39 -08:00

94 lines
2.5 KiB
Ruby

require "test_helper"
class Account::BillingTest < ActiveSupport::TestCase
test "plan reflects active subscription" do
account = accounts(:initech)
# No subscription
assert_equal Plan.free, account.plan
# Subscription but it is not active
account.create_subscription!(plan_key: "monthly_v1", status: "canceled", stripe_customer_id: "cus_test")
assert_equal Plan.free, account.plan
# Active subscription exists
account.subscription.update!(status: "active")
assert_equal Plan.paid, account.plan
end
test "comped account" do
account = accounts(:"37s")
assert_not account.comped?
account.comp
assert account.comped?
# Calling comp again does not create duplicate
account.comp
assert_equal 1, Account::BillingWaiver.where(account: account).count
end
test "cancel callback pauses subscription" do
account = accounts(:"37s")
user = users(:david)
subscription = mock("subscription")
subscription.expects(:pause).once
account.stubs(:subscription).returns(subscription)
account.cancel(initiated_by: user)
end
test "reactivate callback resumes subscription" do
account = accounts(:"37s")
user = users(:david)
# First cancel with a subscription mock
subscription_for_cancel = mock("subscription")
subscription_for_cancel.expects(:pause).once
account.stubs(:subscription).returns(subscription_for_cancel)
account.cancel(initiated_by: user)
# Now stub for reactivation
subscription_for_reactivate = mock("subscription")
subscription_for_reactivate.expects(:resume).once
account.stubs(:subscription).returns(subscription_for_reactivate)
account.reactivate
end
test "incinerate callback cancels subscription before destroying account" do
account = accounts(:"37s")
subscription = mock("subscription")
subscription.expects(:cancel).once
account.stubs(:subscription).returns(subscription)
account.incinerate
end
test "owner_email_changed enqueues sync job when subscription exists" do
account = accounts(:"37s")
account.create_subscription!(
stripe_customer_id: "cus_test",
plan_key: "monthly_v1",
status: "active"
)
assert_enqueued_with(job: Account::SyncStripeCustomerEmailJob, args: [ account.subscription ]) do
account.owner_email_changed
end
end
test "owner_email_changed does nothing without subscription" do
account = accounts(:initech)
account.subscription&.destroy
assert_no_enqueued_jobs do
account.owner_email_changed
end
end
end