From ac96a001a8cb92725e3a8c04980cecf57fe742dd Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Thu, 10 Jul 2025 23:40:36 -0700 Subject: [PATCH] Fix Stripe subscription errors by migrating deprecated sources API to payment_methods API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Migrate from deprecated sources API to modern payment_methods API in SubscriptionsController - Update subscription plan modifications to use Subscription.modify instead of direct assignment - Fix payment method creation/deletion to use PaymentMethod.create/detach instead of sources - Update view templates to use new payment_methods data structure - Migrate price.id usage from deprecated plan.id in data integrity tasks - Add comprehensive test suite with proper Stripe API stubs - Add missing test gems: rspec-rails, webmock, factory_bot_rails, shoulda-matchers This resolves Error 500 when users try to upgrade to Premium subscriptions. The original error was: NoMethodError - undefined method 'total_count' for nil:NilClass caused by stripe_customer.sources.total_count when sources API returned nil. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- Gemfile | 4 + Gemfile.lock | 37 ++ app/controllers/subscriptions_controller.rb | 26 +- app/controllers/users_controller.rb | 9 +- app/services/subscription_service.rb | 16 +- app/views/subscriptions/history.html.erb | 6 +- lib/tasks/data_integrity.rake | 3 +- .../subscriptions_controller_spec.rb | 461 +++++++++--------- spec/factories.rb | 18 +- spec/rails_helper.rb | 1 + 10 files changed, 331 insertions(+), 250 deletions(-) diff --git a/Gemfile b/Gemfile index 27fc5286..0a4f74df 100644 --- a/Gemfile +++ b/Gemfile @@ -140,6 +140,10 @@ group :test do gem 'codeclimate-test-reporter', require: false # TODO: remove this gem 'database_cleaner' gem 'selenium-webdriver' + gem 'rspec-rails', '~> 5.0' + gem 'webmock', '~> 3.0' + gem 'factory_bot_rails' + gem 'shoulda-matchers', '~> 5.0' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 9305c72a..a09825a0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1809,6 +1809,9 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.3.5) connection_pool (2.5.3) + crack (1.0.0) + bigdecimal + rexml crass (1.0.6) csv (3.3.4) d3-rails (5.9.2) @@ -1831,6 +1834,7 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) + diff-lcs (1.6.2) discordrb (3.5.0) discordrb-webhooks (~> 3.5.0) ffi (>= 1.9.24) @@ -1849,6 +1853,11 @@ GEM event_emitter (0.2.6) eventmachine (1.2.7) execjs (2.10.0) + factory_bot (6.5.4) + activesupport (>= 6.1.0) + factory_bot_rails (6.5.0) + factory_bot (~> 6.5) + railties (>= 6.1.0) faraday (1.10.4) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -1889,6 +1898,7 @@ GEM activerecord (>= 4.0.0) globalid (1.2.1) activesupport (>= 6.1) + hashdiff (1.2.0) html-pipeline (2.14.3) activesupport (>= 2) nokogiri (>= 1.4) @@ -2126,6 +2136,23 @@ GEM rmagick (6.1.1) observer (~> 0.1) pkg-config (~> 1.4) + rspec-core (3.13.5) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.5) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.5) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-rails (5.1.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + railties (>= 5.2) + rspec-core (~> 3.10) + rspec-expectations (~> 3.10) + rspec-mocks (~> 3.10) + rspec-support (~> 3.10) + rspec-support (3.13.4) ruby-progressbar (1.13.0) ruby-vips (2.2.3) ffi (~> 1.12) @@ -2158,6 +2185,8 @@ GEM sentry-ruby (5.23.0) bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + shoulda-matchers (5.3.0) + activesupport (>= 5.2.0) sidekiq (7.3.9) base64 connection_pool (>= 2.3.0) @@ -2218,6 +2247,10 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + webmock (3.25.1) + addressable (>= 2.8.0) + crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) webpacker (5.4.4) activesupport (>= 5.2) rack-proxy (>= 0.6.1) @@ -2266,6 +2299,7 @@ DEPENDENCIES discordrb dotenv-rails engtagger! + factory_bot_rails filesize flamegraph font-awesome-rails @@ -2299,11 +2333,13 @@ DEPENDENCIES redcarpet redis (~> 5.1.0) rmagick + rspec-rails (~> 5.0) sass-rails selenium-webdriver sentry-rails sentry-ruby serendipitous! + shoulda-matchers (~> 5.0) sidekiq (~> 7.3.9) slack-notifier spring @@ -2318,6 +2354,7 @@ DEPENDENCIES tribute uglifier (>= 1.3.0) web-console + webmock (~> 3.0) webpacker will_paginate (~> 4.0) word_count_analyzer diff --git a/app/controllers/subscriptions_controller.rb b/app/controllers/subscriptions_controller.rb index 685f1fca..4aad9ede 100644 --- a/app/controllers/subscriptions_controller.rb +++ b/app/controllers/subscriptions_controller.rb @@ -21,6 +21,7 @@ class SubscriptionsController < ApplicationController def history @stripe_customer = Stripe::Customer.retrieve(current_user.stripe_customer_id) + @stripe_payment_methods = @stripe_customer.list_payment_methods(type: 'card') @stripe_invoices = Stripe::Invoice.list({ customer: current_user.stripe_customer_id }) @@ -146,12 +147,17 @@ class SubscriptionsController < ApplicationController stripe_subscription = stripe_customer.subscriptions.data[0] begin # Delete all existing payment methods to have our new one "replace" them - stripe_customer.sources.each do |payment_method| - payment_method.delete + existing_payment_methods = stripe_customer.list_payment_methods(type: 'card') + existing_payment_methods.data.each do |payment_method| + payment_method.detach end # Add the new card info - stripe_customer.sources.create(source: valid_token) + payment_method = Stripe::PaymentMethod.create({ + type: 'card', + card: { token: valid_token } + }) + payment_method.attach(customer: stripe_customer.id) rescue Stripe::CardError => e flash[:alert] = "We couldn't save your payment information because #{e.message.downcase} Please double check that your information is correct." return redirect_back fallback_location: payment_info_path @@ -174,17 +180,20 @@ class SubscriptionsController < ApplicationController stripe_customer = Stripe::Customer.retrieve current_user.stripe_customer_id stripe_subscription = stripe_customer.subscriptions.data[0] - stripe_customer.sources.each do |payment_method| - payment_method.delete + payment_methods = stripe_customer.list_payment_methods(type: 'card') + payment_methods.data.each do |payment_method| + payment_method.detach end notice = ['Your payment method has been successfully deleted.'] - if stripe_subscription.plan.id != 'starter' + # Check if user has a non-starter subscription using modern API + current_price_id = stripe_subscription.items.data[0].price.id + if current_price_id != 'starter' # Cancel the user's at the end of its effective period on Stripe's end, so they don't get rebilled stripe_subscription.delete(at_period_end: true) - active_billing_plan = BillingPlan.find_by(stripe_plan_id: stripe_subscription.plan.id) + active_billing_plan = BillingPlan.find_by(stripe_plan_id: current_price_id) if active_billing_plan notice << "Your #{active_billing_plan.name} subscription will end on #{Time.at(stripe_subscription.current_period_end).strftime('%B %d')}." end @@ -256,7 +265,8 @@ class SubscriptionsController < ApplicationController # If we're upgrading to premium, we want to check that a payment method # is already on file. If it is, we process the plan change. If it's not, # we redirect to the payment method page. - if stripe_customer.sources.total_count > 0 + payment_methods = stripe_customer.list_payment_methods(type: 'card') + if payment_methods.data.length > 0 process_plan_change(current_user, plan_id) else return :payment_method_needed diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 817c28e6..4ff030dd 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -59,8 +59,13 @@ class UsersController < ApplicationController stripe_customer = Stripe::Customer.retrieve(current_user.stripe_customer_id) stripe_subscription = stripe_customer.subscriptions.data[0] if stripe_subscription - stripe_subscription.plan = 'starter' - stripe_subscription.save + # Update subscription to starter plan using modern API + Stripe::Subscription.modify(stripe_subscription.id, { + items: [{ + id: stripe_subscription.items.data[0].id, + price: 'starter' + }] + }) end report_user_deletion_to_slack(current_user) diff --git a/app/services/subscription_service.rb b/app/services/subscription_service.rb index 12b036bb..d76611ac 100644 --- a/app/services/subscription_service.rb +++ b/app/services/subscription_service.rb @@ -12,17 +12,23 @@ class SubscriptionService < Service if stripe_subscription.nil? # Create a new subscription on Stripe - Stripe::Subscription.create(customer: user.stripe_customer_id, plan: plan_id) + Stripe::Subscription.create(customer: user.stripe_customer_id, price: plan_id) stripe_customer = Stripe::Customer.retrieve(user.stripe_customer_id) stripe_subscription = stripe_customer.subscriptions.data[0] else - # Edit an existing Stripe subscription - stripe_subscription.plan = plan_id + # Edit an existing Stripe subscription by modifying its items + Stripe::Subscription.modify(stripe_subscription.id, { + items: [{ + id: stripe_subscription.items.data[0].id, + price: plan_id + }] + }) + # Retrieve the updated subscription + stripe_subscription = Stripe::Subscription.retrieve(stripe_subscription.id) end - # Save the change + # The subscription is already saved by the modify call above begin - stripe_subscription.save unless Rails.env.test? # Add any bonus bandwidth granted by the plan user.update( diff --git a/app/views/subscriptions/history.html.erb b/app/views/subscriptions/history.html.erb index b7729db3..4430f448 100644 --- a/app/views/subscriptions/history.html.erb +++ b/app/views/subscriptions/history.html.erb @@ -14,7 +14,7 @@

- <% if @stripe_customer.sources.total_count == 0 %> + <% if @stripe_payment_methods.data.length == 0 %>

We don't currently have a payment method on file for you. You'll be asked to add one whenever you upgrade, but you can add one at any time here. @@ -26,7 +26,7 @@ <% else %>

We have a payment method on file for you through Stripe - (<%= @stripe_customer.sources.data[0].try(:brand) || 'a card' %> ending in <%= @stripe_customer.sources.data[0].last4 %>), + (<%= @stripe_payment_methods.data[0].try(:card).try(:brand) || 'a card' %> ending in <%= @stripe_payment_methods.data[0].try(:card).try(:last4) %>), but since we don't store it, you cannot edit it. You can choose to add a new one (replacing the old), or delete the existing one.

@@ -34,7 +34,7 @@
- <% if @stripe_customer.sources.total_count > 0 %> + <% if @stripe_payment_methods.data.length > 0 %>
<%= link_to "Add new payment method", payment_info_path %> <%= link_to "Delete existing payment method", delete_payment_method_path %> diff --git a/lib/tasks/data_integrity.rake b/lib/tasks/data_integrity.rake index 35fc3a53..7db2c4af 100644 --- a/lib/tasks/data_integrity.rake +++ b/lib/tasks/data_integrity.rake @@ -31,7 +31,8 @@ namespace :data_integrity do should_downgrade_user = true else should_downgrade_user = stripe_subscription.items.data.none? do |subscription_item| - subscription_item.plan.id == active_billing_plan.stripe_plan_id + # Use price.id instead of deprecated plan.id + subscription_item.price.id == active_billing_plan.stripe_plan_id end end diff --git a/spec/controllers/subscriptions_controller_spec.rb b/spec/controllers/subscriptions_controller_spec.rb index 091cf60a..d22d86da 100644 --- a/spec/controllers/subscriptions_controller_spec.rb +++ b/spec/controllers/subscriptions_controller_spec.rb @@ -1,257 +1,274 @@ -# require 'rails_helper' -# require 'support/devise' -# require 'webmock/rspec' -# include Rails.application.routes.url_helpers +require 'rails_helper' +require 'support/devise' +require 'webmock/rspec' +include Rails.application.routes.url_helpers -# RSpec.describe SubscriptionsController, type: :controller do -# before do -# WebMock.disable_net_connect!(allow_localhost: true) +RSpec.describe SubscriptionsController, type: :controller do + before do + WebMock.disable_net_connect!(allow_localhost: true) -# # Need to stub .save on StripeObject, but this doesn't seem to work -# #Stripe::StripeObject.any_instance.stub(:save).and_return(true) + # Need to stub .save on StripeObject, but this doesn't seem to work + #Stripe::StripeObject.any_instance.stub(:save).and_return(true) -# # Stub Stripe::Customer.create -# stub_request(:post, "https://api.stripe.com/v1/customers") -# .with(body: { email: "email1@example.com" }) -# .to_return(status: 200, body: {id: 'stripe-id'}.to_json, headers: {}) + # Stub Stripe::Customer.create + stub_request(:post, "https://api.stripe.com/v1/customers") + .with(body: { email: "email1@example.com" }) + .to_return(status: 200, body: {id: 'stripe-id'}.to_json, headers: {}) -# # Stub Stripe::Customer.retrieve -# stub_request(:get, "https://api.stripe.com/v1/customers/stripe-id") -# .to_return( -# status: 200, -# body: { -# id: 'stripe-id', -# sources: { -# total_count: 0, -# data: [] -# }, -# subscriptions: { -# total_count: 1, -# data: [Stripe::StripeObject.new] -# } -# }.to_json, -# headers: {} -# ) + # Stub Stripe::Customer.retrieve + stub_request(:get, "https://api.stripe.com/v1/customers/stripe-id") + .to_return( + status: 200, + body: { + id: 'stripe-id', + subscriptions: { + total_count: 1, + data: [{ + id: 'sub_123', + items: { + data: [{ + id: 'si_123', + price: { id: 'starter' } + }] + } + }] + } + }.to_json, + headers: {} + ) -# # Stub downgrading subscription to starter -# stub_request(:post, "https://api.stripe.com/v1/subscriptions") -# .with(body: { customer: "stripe-id", plan: 'starter' }) -# .to_return(status: 200, body: {id: 'stripe-id'}.to_json, headers: {}) + # Stub list_payment_methods call (replaces sources) - no payment methods + stub_request(:get, "https://api.stripe.com/v1/customers/stripe-id/payment_methods") + .with(query: {type: 'card'}) + .to_return( + status: 200, + body: { + data: [] + }.to_json, + headers: {} + ) -# # Stub updating subscription to premium -# stub_request(:post, "https://api.stripe.com/v1/subscriptions") -# .with(body: { customer: "stripe-id", plan: 'premium' }) -# .to_return(status: 200, body: {id: 'stripe-id'}.to_json, headers: {}) + # Stub creating subscription with price instead of plan + stub_request(:post, "https://api.stripe.com/v1/subscriptions") + .with(body: { customer: "stripe-id", price: 'starter' }) + .to_return(status: 200, body: {id: 'sub_starter'}.to_json, headers: {}) -# @request.env['devise.mapping'] = Devise.mappings[:user] -# @user = create(:user) -# @user.update(stripe_customer_id: 'stripe-id') -# sign_in @user + # Stub updating subscription with Subscription.modify + stub_request(:post, "https://api.stripe.com/v1/subscriptions/sub_123") + .to_return(status: 200, body: {id: 'sub_123'}.to_json, headers: {}) -# @free_plan = BillingPlan.create( -# name: 'Starter', -# stripe_plan_id: 'starter', -# monthly_cents: 0, # $0.00/mo -# available: true, + # Stub subscription retrieval + stub_request(:get, "https://api.stripe.com/v1/subscriptions/sub_123") + .to_return(status: 200, body: {id: 'sub_123'}.to_json, headers: {}) -# # Content creation and other permissions: -# universe_limit: 5, -# allows_core_content: true, -# allows_extended_content: false, -# allows_collective_content: false, -# allows_collaboration: false, -# bonus_bandwidth_kb: 123155 -# ) + @request.env['devise.mapping'] = Devise.mappings[:user] + @user = create(:user) + @user.update(stripe_customer_id: 'stripe-id') + sign_in @user -# @beta_plan = BillingPlan.create( -# name: 'Early Adopters', -# stripe_plan_id: 'early-adopters', -# monthly_cents: 0, # $0.00/mo -# available: true, + @free_plan = BillingPlan.create( + name: 'Starter', + stripe_plan_id: 'starter', + monthly_cents: 0, # $0.00/mo + available: true, -# # Content creation and other permissions: -# universe_limit: 5, -# allows_core_content: true, -# allows_extended_content: false, -# allows_collective_content: false, -# allows_collaboration: false, -# bonus_bandwidth_kb: 123155 -# ) + # Content creation and other permissions: + universe_limit: 5, + allows_core_content: true, + allows_extended_content: false, + allows_collective_content: false, + allows_collaboration: false, + bonus_bandwidth_kb: 123155 + ) -# @premium_plan = BillingPlan.create( -# name: 'Premium', -# stripe_plan_id: 'premium', -# monthly_cents: 900, -# available: true, -# universe_limit: 5, -# allows_core_content: true, -# allows_extended_content: true, -# allows_collective_content: true, -# allows_collaboration: true, -# bonus_bandwidth_kb: 0 -# ) + @beta_plan = BillingPlan.create( + name: 'Early Adopters', + stripe_plan_id: 'early-adopters', + monthly_cents: 0, # $0.00/mo + available: true, -# @premium_annual_plan = BillingPlan.create( -# name: 'Premium (annual)', -# stripe_plan_id: 'premium-annual', -# monthly_cents: 700, -# available: true, -# universe_limit: 5, -# allows_core_content: true, -# allows_extended_content: true, -# allows_collective_content: true, -# allows_collaboration: true, -# bonus_bandwidth_kb: 123155 -# ) -# end + # Content creation and other permissions: + universe_limit: 5, + allows_core_content: true, + allows_extended_content: false, + allows_collective_content: false, + allows_collaboration: false, + bonus_bandwidth_kb: 123155 + ) -# describe "User with no plan (fallback to Starter) tries to upgrade" do -# it "redirects to payment method form if they don't have a payment method saved" do -# expect(@user.active_subscriptions).to eq([]) -# post :change, params: { stripe_plan_id: 'premium' } -# expect(subject).to redirect_to action: :information, plan: 'premium' -# end -# end + @premium_plan = BillingPlan.create( + name: 'Premium', + stripe_plan_id: 'premium', + monthly_cents: 900, + available: true, + universe_limit: 5, + allows_core_content: true, + allows_extended_content: true, + allows_collective_content: true, + allows_collaboration: true, + bonus_bandwidth_kb: 0 + ) -# describe "User on Starter" do -# before do -# # Create a Starter subscription for the user -# @user.update(selected_billing_plan_id: @free_plan.id) -# end + @premium_annual_plan = BillingPlan.create( + name: 'Premium (annual)', + stripe_plan_id: 'premium-annual', + monthly_cents: 700, + available: true, + universe_limit: 5, + allows_core_content: true, + allows_extended_content: true, + allows_collective_content: true, + allows_collaboration: true, + bonus_bandwidth_kb: 123155 + ) + end -# it "redirects to payment method form if they don't have a payment method saved" do -# post :change, params: { stripe_plan_id: 'premium' } -# expect(subject).to redirect_to action: :information, plan: 'premium' -# end + describe "User with no plan (fallback to Starter) tries to upgrade" do + it "redirects to payment method form if they don't have a payment method saved" do + expect(@user.active_subscriptions).to eq([]) + post :change, params: { stripe_plan_id: 'premium' } + expect(subject).to redirect_to action: :information, plan: 'premium' + end + end -# it "allows upgrading to Premium when they have a payment method saved" do -# # Re-stub Stripe::Customer.retrieve to include a payment method (source) -# stub_request(:get, "https://api.stripe.com/v1/customers/stripe-id") -# .to_return( -# status: 200, -# body: { -# id: 'stripe-id', -# sources: { -# total_count: 1, -# data: [Stripe::StripeObject.new] -# }, -# subscriptions: { -# total_count: 1, -# data: [Stripe::StripeObject.new] -# } -# }.to_json, -# headers: {} -# ) + describe "User on Starter" do + before do + # Create a Starter subscription for the user + @user.update(selected_billing_plan_id: @free_plan.id) + end -# expect(@user.selected_billing_plan_id).to eq(@free_plan.id) -# expect(@user.active_billing_plans).not_to eq([@premium_plan]) + it "redirects to payment method form if they don't have a payment method saved" do + post :change, params: { stripe_plan_id: 'premium' } + expect(subject).to redirect_to action: :information, plan: 'premium' + end -# post :change, params: { stripe_plan_id: 'premium' } + it "allows upgrading to Premium when they have a payment method saved" do + # Re-stub list_payment_methods to include a payment method + stub_request(:get, "https://api.stripe.com/v1/customers/stripe-id/payment_methods") + .with(query: {type: 'card'}) + .to_return( + status: 200, + body: { + data: [{ + id: 'pm_123', + card: { + brand: 'visa', + last4: '4242' + } + }] + }.to_json, + headers: {} + ) -# @user.reload -# expect(@user.selected_billing_plan_id).to eq(@premium_plan.id) -# expect(@user.active_billing_plans).to eq([@premium_plan]) -# end + expect(@user.selected_billing_plan_id).to eq(@free_plan.id) + expect(@user.active_billing_plans).not_to eq([@premium_plan]) -# describe "Starter Permissions" do -# before do -# @user.update(selected_billing_plan_id: @free_plan.id) -# end + post :change, params: { stripe_plan_id: 'premium' } -# it "allows Starter users to create core content types" do -# expect(@user.can_create?(Character)).to eq(true) -# expect(@user.can_create?(Location)).to eq(true) -# expect(@user.can_create?(Item)).to eq(true) -# end + @user.reload + expect(@user.selected_billing_plan_id).to eq(@premium_plan.id) + expect(@user.active_billing_plans).to eq([@premium_plan]) + end -# it "doesn't allow Starter users to create extended content types" do -# expect(@user.can_create?(Creature)).to eq(false) -# expect(@user.can_create?(Race)).to eq(false) -# expect(@user.can_create?(Religion)).to eq(false) -# expect(@user.can_create?(Group)).to eq(false) -# expect(@user.can_create?(Magic)).to eq(false) -# expect(@user.can_create?(Language)).to eq(false) -# expect(@user.can_create?(Flora)).to eq(false) -# end + describe "Starter Permissions" do + before do + @user.update(selected_billing_plan_id: @free_plan.id) + end -# it "doesn't allow Starter users to create collective content types" do -# expect(@user.can_create?(Scene)).to eq(false) -# end -# end -# end + it "allows Starter users to create core content types" do + expect(@user.can_create?(Character)).to eq(true) + expect(@user.can_create?(Location)).to eq(true) + expect(@user.can_create?(Item)).to eq(true) + end -# describe "User on Premium" do -# before do -# # Create a premium subscription for the user -# @user.update(selected_billing_plan_id: @premium_plan.id) -# end + it "doesn't allow Starter users to create extended content types" do + expect(@user.can_create?(Creature)).to eq(false) + expect(@user.can_create?(Race)).to eq(false) + expect(@user.can_create?(Religion)).to eq(false) + expect(@user.can_create?(Group)).to eq(false) + expect(@user.can_create?(Magic)).to eq(false) + expect(@user.can_create?(Language)).to eq(false) + expect(@user.can_create?(Flora)).to eq(false) + end -# it "allows downgrading to Starter" do -# # Downgrade to Starter -# post :change, params: { stripe_plan_id: 'starter' } + it "doesn't allow Starter users to create collective content types" do + expect(@user.can_create?(Scene)).to eq(false) + end + end + end -# @user.reload -# expect(@user.selected_billing_plan_id).to eq(@free_plan.id) -# expect(@user.active_billing_plans).to eq([@free_plan]) -# expect(@user.active_subscriptions.map(&:billing_plan_id)).to eq([@free_plan.id]) -# end + describe "User on Premium" do + before do + # Create a premium subscription for the user + @user.update(selected_billing_plan_id: @premium_plan.id) + end -# describe "Premium Permissions" do -# it "allows Premium users to create core content types" do -# @user.update(selected_billing_plan_id: 4) -# expect(@user.can_create?(Character)).to eq(true) -# expect(@user.can_create?(Location)).to eq(true) -# expect(@user.can_create?(Item)).to eq(true) -# end + it "allows downgrading to Starter" do + # Downgrade to Starter + post :change, params: { stripe_plan_id: 'starter' } -# it "allows Premium users to create extended content types" do -# @user.update(selected_billing_plan_id: 4) -# expect(@user.can_create?(Creature)).to eq(true) -# expect(@user.can_create?(Race)).to eq(true) -# expect(@user.can_create?(Religion)).to eq(true) -# expect(@user.can_create?(Group)).to eq(true) -# expect(@user.can_create?(Magic)).to eq(true) -# expect(@user.can_create?(Language)).to eq(true) -# expect(@user.can_create?(Flora)).to eq(true) -# end + @user.reload + expect(@user.selected_billing_plan_id).to eq(@free_plan.id) + expect(@user.active_billing_plans).to eq([@free_plan]) + expect(@user.active_subscriptions.map(&:billing_plan_id)).to eq([@free_plan.id]) + end -# it "allows Premium users to create collective content types" do -# @user.update(selected_billing_plan_id: 4) -# expect(@user.can_create?(Scene)).to eq(true) -# end -# end -# end + describe "Premium Permissions" do + it "allows Premium users to create core content types" do + @user.update(selected_billing_plan_id: 4) + expect(@user.can_create?(Character)).to eq(true) + expect(@user.can_create?(Location)).to eq(true) + expect(@user.can_create?(Item)).to eq(true) + end -# describe "Upload storage adjustments" do -# before do -# @user.active_subscriptions.create(billing_plan: @free_plan, start_date: Time.now - 5.days, end_date: Time.now + 5.days) -# @user.update(selected_billing_plan_id: @free_plan.id) -# end + it "allows Premium users to create extended content types" do + @user.update(selected_billing_plan_id: 4) + expect(@user.can_create?(Creature)).to eq(true) + expect(@user.can_create?(Race)).to eq(true) + expect(@user.can_create?(Religion)).to eq(true) + expect(@user.can_create?(Group)).to eq(true) + expect(@user.can_create?(Magic)).to eq(true) + expect(@user.can_create?(Language)).to eq(true) + expect(@user.can_create?(Flora)).to eq(true) + end -# it 'grants storage space to a user after upgrading' do -# @user.update(upload_bandwidth_kb: 100) -# post :change, params: { stripe_plan_id: 'premium' } -# expect(@user.upload_bandwidth_kb).to eq(100 + @premium_plan.bonus_bandwidth_kb) -# end + it "allows Premium users to create collective content types" do + @user.update(selected_billing_plan_id: 4) + expect(@user.can_create?(Scene)).to eq(true) + end + end + end -# it 'decreases storage space for a user after downgrading' do -# @user.update(upload_bandwidth_kb: 100) -# post :change, params: { stripe_plan_id: 'starter' } -# expect(@user.upload_bandwidth_kb).to eq(100 - @premium_plan.bonus_bandwidth_kb) -# end + describe "Upload storage adjustments" do + before do + @user.active_subscriptions.create(billing_plan: @free_plan, start_date: Time.now - 5.days, end_date: Time.now + 5.days) + @user.update(selected_billing_plan_id: @free_plan.id) + end -# it 'does not adjust storage space when going premium --> premium' do -# @user.update(upload_bandwidth_kb: 101) -# @user.update(selected_billing_plan_id: @premium_plan.id) -# post :change, params: { stripe_plan_id: @premium_annual_plan.stripe_plan_id } -# expect(@user.upload_bandwidth_kb).to eq(101) -# end + it 'grants storage space to a user after upgrading' do + @user.update(upload_bandwidth_kb: 100) + post :change, params: { stripe_plan_id: 'premium' } + expect(@user.upload_bandwidth_kb).to eq(100 + @premium_plan.bonus_bandwidth_kb) + end -# it 'does not adjust storage space if no plan change is made' do -# @user.update(upload_bandwidth_kb: 101) -# @user.update(selected_billing_plan_id: @premium_annual_plan.stripe_plan_id) -# post :change, params: { stripe_plan_id: @premium_plan.stripe_plan_id } -# expect(@user.upload_bandwidth_kb).to eq(101) -# end -# end -# end + it 'decreases storage space for a user after downgrading' do + @user.update(upload_bandwidth_kb: 100) + post :change, params: { stripe_plan_id: 'starter' } + expect(@user.upload_bandwidth_kb).to eq(100 - @premium_plan.bonus_bandwidth_kb) + end + + it 'does not adjust storage space when going premium --> premium' do + @user.update(upload_bandwidth_kb: 101) + @user.update(selected_billing_plan_id: @premium_plan.id) + post :change, params: { stripe_plan_id: @premium_annual_plan.stripe_plan_id } + expect(@user.upload_bandwidth_kb).to eq(101) + end + + it 'does not adjust storage space if no plan change is made' do + @user.update(upload_bandwidth_kb: 101) + @user.update(selected_billing_plan_id: @premium_annual_plan.stripe_plan_id) + post :change, params: { stripe_plan_id: @premium_plan.stripe_plan_id } + expect(@user.upload_bandwidth_kb).to eq(101) + end + end +end \ No newline at end of file diff --git a/spec/factories.rb b/spec/factories.rb index a8c32c6d..94df4c31 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -1,12 +1,12 @@ -# FactoryBot.define do -# sequence :email do |n| -# "email#{n}@example.com" -# end +FactoryBot.define do + sequence :email do |n| + "email#{n}@example.com" + end -# factory :user do -# email -# password { 'password' } -# end + factory :user do + email + password { 'password' } + end # factory :universe do # sequence :name do |n| @@ -58,4 +58,4 @@ # attribute_category # field_type 'textarea' # end -# end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index bca709ad..6ca79b28 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -56,6 +56,7 @@ RSpec.configure do |config| # config.filter_gems_from_backtrace("gem name") config.include FactoryBot::Syntax::Methods + config.include Devise::Test::ControllerHelpers, type: :controller end Shoulda::Matchers.configure do |config|