diff --git a/app/assets/javascripts/components/__tests__/__snapshots__/notify_tier_change-test.jsx.snap b/app/assets/javascripts/components/__tests__/__snapshots__/notify_tier_change-test.jsx.snap index f838e84f0..509d14349 100644 --- a/app/assets/javascripts/components/__tests__/__snapshots__/notify_tier_change-test.jsx.snap +++ b/app/assets/javascripts/components/__tests__/__snapshots__/notify_tier_change-test.jsx.snap @@ -43,7 +43,7 @@ exports[`NotifyTierChange snapshots renders plans appropriately (Chihuahua -> La

- Pricing: Change of Plans + Change of Plans

@@ -133,7 +133,7 @@ exports[`NotifyTierChange snapshots renders plans appropriately (Labrador -> Gre

- Pricing: Change of Plans + Change of Plans

diff --git a/app/assets/javascripts/components/notify_tier_change.jsx b/app/assets/javascripts/components/notify_tier_change.jsx index d8606f8b4..7399678bf 100644 --- a/app/assets/javascripts/components/notify_tier_change.jsx +++ b/app/assets/javascripts/components/notify_tier_change.jsx @@ -77,7 +77,7 @@ class NotifyTierChange extends React.Component { {this.renderTierPlans()}
-

Pricing: Change of Plans

+

Change of Plans

Private Repos diff --git a/app/assets/javascripts/components/repos_container.jsx b/app/assets/javascripts/components/repos_container.jsx index 049ad30b7..933e16e80 100644 --- a/app/assets/javascripts/components/repos_container.jsx +++ b/app/assets/javascripts/components/repos_container.jsx @@ -92,7 +92,7 @@ class ReposContainer extends React.Component { updateSubscribedRepoCount() { this.getUser().then(user => { const subscribedRepoCount = user.subscribed_repo_count; - const tierAllowance = user.tier_allowance; + const tierAllowance = user.plan_max; if (subscribedRepoCount === 0) { $("[data-role='allowance-container']").remove(); @@ -123,7 +123,7 @@ class ReposContainer extends React.Component { onSubscriptionError(repo, error) { if (error.status === 402) { - document.location.href = `/pricings?repo_id=${repo.id}`; + document.location.href = `/plans?repo_id=${repo.id}`; } else { alert("Your subscription could not be activated."); } diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb new file mode 100644 index 000000000..bb289e543 --- /dev/null +++ b/app/controllers/plans_controller.rb @@ -0,0 +1,16 @@ +class PlansController < ApplicationController + def index + @plans = ActiveModel::ArraySerializer.new( + Plan.all, + each_serializer: PlanSerializer, + scope: current_user, + ) + @repo = Repo.find(plan_params[:repo_id]) + end + + private + + def plan_params + params.permit(:repo_id) + end +end diff --git a/app/controllers/pricings_controller.rb b/app/controllers/pricings_controller.rb deleted file mode 100644 index 17693d954..000000000 --- a/app/controllers/pricings_controller.rb +++ /dev/null @@ -1,16 +0,0 @@ -class PricingsController < ApplicationController - def index - @pricings = ActiveModel::ArraySerializer.new( - Pricing.all, - each_serializer: PricingSerializer, - scope: current_user, - ) - @repo = Repo.find(pricing_params[:repo_id]) - end - - private - - def pricing_params - params.permit(:repo_id) - end -end diff --git a/app/controllers/subscriptions_controller.rb b/app/controllers/subscriptions_controller.rb index 6edefc9fb..88f18fe6f 100644 --- a/app/controllers/subscriptions_controller.rb +++ b/app/controllers/subscriptions_controller.rb @@ -5,7 +5,7 @@ class FailedToActivate < StandardError; end before_action :update_email def create - if Tier.new(current_user).full? + if current_user.plan_upgrade? render json: {}, status: :payment_required elsif activator.activate && create_subscription render json: repo, status: :created diff --git a/app/models/analytics.rb b/app/models/analytics.rb index 3b7a41e52..67dde6a3c 100644 --- a/app/models/analytics.rb +++ b/app/models/analytics.rb @@ -26,7 +26,7 @@ def track_repo_deactivated(repo) properties: { name: repo.name, private: repo.private, - revenue: -repo.plan_price, + revenue: lost_revenue, } ) end @@ -53,6 +53,8 @@ def track_build_completed(repo) private + attr_reader :user + def track(options) backend.track({ active_repos_count: user.repos.active.count, @@ -60,5 +62,11 @@ def track(options) }.merge(options)) end - attr_reader :user + def lost_revenue + if user.current_plan == user.next_plan + 0 + else + user.current_plan_price - user.next_plan_price + end + end end diff --git a/app/models/home.rb b/app/models/home.rb index bcc88ecf3..c6abe3c66 100644 --- a/app/models/home.rb +++ b/app/models/home.rb @@ -5,29 +5,29 @@ def initialize(user) @user = user end - def open_source_pricings - open_source_repos.map { |pricing| present(pricing) } + def open_source_plans + open_source_repos.map { |plan| present(plan) } end - def private_pricings - private_repos.map { |pricing| present(pricing) } + def private_plans + private_repos.map { |plan| present(plan) } end private - def present(pricing) - PricingPresenter.new(pricing: pricing, user: user) + def present(plan) + PlanPresenter.new(plan: plan, user: user) end - def pricings - Pricing.all + def plans + Plan.all end def private_repos - pricings.reject(&:open_source?) + plans.reject(&:open_source?) end def open_source_repos - pricings.select(&:open_source?) + plans.select(&:open_source?) end end diff --git a/app/models/payment_gateway_customer.rb b/app/models/payment_gateway_customer.rb index 2f2494e31..4348b7cde 100644 --- a/app/models/payment_gateway_customer.rb +++ b/app/models/payment_gateway_customer.rb @@ -32,7 +32,7 @@ def subscription def retrieve_subscription(subscription_id) PaymentGatewaySubscription.new( stripe_subscription: customer.subscriptions.retrieve(subscription_id), - tier: tier, + user: user, ) end @@ -54,7 +54,7 @@ def update_email(email) def create_subscription(options) PaymentGatewaySubscription.new( stripe_subscription: customer.subscriptions.create(options), - tier: tier, + user: user, ) end @@ -67,15 +67,11 @@ def subscriptions customer.subscriptions.map do |subscription| PaymentGatewaySubscription.new( stripe_subscription: subscription, - tier: tier, + user: user, ) end end - def tier - Tier.new(user) - end - class NoRecord def email "" diff --git a/app/models/payment_gateway_subscription.rb b/app/models/payment_gateway_subscription.rb index d5effe40f..93d28b253 100644 --- a/app/models/payment_gateway_subscription.rb +++ b/app/models/payment_gateway_subscription.rb @@ -1,5 +1,5 @@ class PaymentGatewaySubscription - attr_reader :stripe_subscription, :tier + attr_reader :stripe_subscription, :user delegate( :id, @@ -11,14 +11,14 @@ class PaymentGatewaySubscription to: :stripe_subscription, ) - def initialize(stripe_subscription:, tier:) + def initialize(stripe_subscription:, user:) @stripe_subscription = stripe_subscription - @tier = tier + @user = user end def subscribe(repo_id) append_repo_id_to_metadata(repo_id) - self.plan = tier.next.id + self.plan = user.next_plan.id save end @@ -51,11 +51,7 @@ def current_repo_ids end def downgraded_plan - previous_tier.id - end - - def previous_tier - tier.previous + user.previous_plan.id end def stripe_plan diff --git a/app/models/plan.rb b/app/models/plan.rb index 96efa9661..5033a9237 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -1,37 +1,44 @@ class Plan - PRICES = { - bulk: 0, - public: 0, - private: 12 - } - - TYPES = { - bulk: "bulk", - public: "public", - private: "private" - } - - def initialize(repo) - @repo = repo + include ActiveModel::Serialization + + PLANS = [ + { id: "basic", price: 0, range: 0..0, title: "Hound" }, + { id: "tier1", price: 49, range: 1..4, title: "Chihuahua" }, + { id: "tier2", price: 99, range: 5..10, title: "Labrador" }, + { id: "tier3", price: 249, range: 11..30, title: "Great Dane" }, + ].freeze + + attr_reader :id, :price, :title + + def initialize(id:, range:, price:, title:) + @id = id + @range = range + @price = price + @title = title end - def type - if @repo.bulk? - TYPES[:bulk] - elsif @repo.private? - TYPES[:private] - else - TYPES[:public] - end + def self.all + PLANS.map { |plan| new(plan) } end - def price - if @repo.bulk? - PRICES[:bulk] - elsif @repo.private? - PRICES[:private] - else - PRICES[:public] - end + def self.find_by(count:) + found = PLANS.detect { |plan| plan.fetch(:range).include?(count) } + new(found) end + + def ==(other) + id == other.id + end + + def allowance + range.max + end + + def open_source? + price.zero? + end + + private + + attr_reader :range end diff --git a/app/models/plan_selector.rb b/app/models/plan_selector.rb new file mode 100644 index 000000000..9818dba85 --- /dev/null +++ b/app/models/plan_selector.rb @@ -0,0 +1,39 @@ +class PlanSelector + BULK_ID = "bulk".freeze + + def initialize(user) + @user = user + end + + def current_plan + find_plan(repo_count) + end + + def next_plan + find_plan(repo_count.succ) + end + + def previous_plan + find_plan(repo_count.pred) + end + + def upgrade? + current_plan != next_plan + end + + private + + attr_reader :user + + def repo_count + @_repo_count ||= repos.size + end + + def find_plan(count) + Plan.find_by(count: count) + end + + def repos + user.subscribed_repos + end +end diff --git a/app/models/pricing.rb b/app/models/pricing.rb deleted file mode 100644 index c92c90042..000000000 --- a/app/models/pricing.rb +++ /dev/null @@ -1,44 +0,0 @@ -class Pricing - include ActiveModel::SerializerSupport - - PRICINGS = [ - { id: "basic", price: 0, range: 0..0, title: "Hound" }, - { id: "tier1", price: 49, range: 1..4, title: "Chihuahua" }, - { id: "tier2", price: 99, range: 5..10, title: "Labrador" }, - { id: "tier3", price: 249, range: 11..30, title: "Great Dane" }, - ].freeze - - attr_reader :id, :price, :title - - def self.all - PRICINGS.map { |pricing| new(pricing) } - end - - def self.find_by(count:) - found = PRICINGS.detect { |pricing| pricing.fetch(:range).include?(count) } - new(found) - end - - def initialize(id:, range:, price:, title:) - @id = id - @range = range - @price = price - @title = title - end - - def ==(other) - id == other.id - end - - def allowance - range.max - end - - def open_source? - price.zero? - end - - private - - attr_reader :range -end diff --git a/app/models/repo.rb b/app/models/repo.rb index 4e1c51f68..dc1f46fbc 100644 --- a/app/models/repo.rb +++ b/app/models/repo.rb @@ -5,9 +5,6 @@ class Repo < ApplicationRecord has_one :subscription has_many :users, through: :memberships - delegate :type, :price, to: :plan, prefix: true - delegate :price, to: :subscription, prefix: true - validates :github_id, uniqueness: true, presence: true def self.active diff --git a/app/models/tier.rb b/app/models/tier.rb deleted file mode 100644 index 5a98ca916..000000000 --- a/app/models/tier.rb +++ /dev/null @@ -1,51 +0,0 @@ -class Tier - BULK_ID = "bulk".freeze - - def initialize(user) - @user = user - end - - def current - select(count) - end - - def full? - pricing_changes? - end - - def next - select(succ) - end - - def previous - select(previous_repo_count) - end - - private - - attr_reader :user - - def count - @count ||= repos.count - end - - def previous_repo_count - count.pred - end - - def pricing_changes? - self.next != current - end - - def select(count) - Pricing.find_by(count: count) - end - - def succ - count.succ - end - - def repos - user.subscribed_repos - end -end diff --git a/app/models/user.rb b/app/models/user.rb index 89bfa3fbb..14c980f3f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -11,16 +11,22 @@ class User < ApplicationRecord before_create :generate_remember_token - def current_tier - tier.current + delegate :current_plan, :next_plan, :previous_plan, to: :plan_selector + + def plan_upgrade? + plan_selector.upgrade? + end + + def current_plan_price + current_plan.price end - def next_tier - tier.next + def next_plan_price + next_plan.price end - def tier_price - next_tier.price + def plan_max + current_plan.allowance end def to_s @@ -31,10 +37,6 @@ def active_repos repos.active end - def tier_max - current_tier.allowance - end - def billable_email payment_gateway_customer.email end @@ -89,8 +91,8 @@ def payment_gateway_customer @payment_gateway_customer ||= PaymentGatewayCustomer.new(self) end - def tier - @_tier ||= Tier.new(self) + def plan_selector + @_plan_selector ||= PlanSelector.new(self) end def generate_remember_token diff --git a/app/presenters/account_page.rb b/app/presenters/account_page.rb index 0bc3d1e45..8f64323e7 100644 --- a/app/presenters/account_page.rb +++ b/app/presenters/account_page.rb @@ -4,7 +4,7 @@ def initialize(user) end def allowance - current_tier.allowance + current_plan.allowance end def billable_email @@ -16,12 +16,12 @@ def monthly_line_item end def plan - current_tier.title + current_plan.title end - def pricings - Pricing.all.map do |pricing| - PricingPresenter.new(pricing: pricing, user: user) + def plans + Plan.all.map do |plan| + PlanPresenter.new(plan: plan, user: user) end end @@ -45,8 +45,8 @@ def total_monthly_cost attr_reader :user - def current_tier - tier.current + def current_plan + user.current_plan end def repo_count @@ -56,8 +56,4 @@ def repo_count def subscribed_repos user.subscribed_repos end - - def tier - Tier.new(user) - end end diff --git a/app/presenters/plan_presenter.rb b/app/presenters/plan_presenter.rb new file mode 100644 index 000000000..d64c7d847 --- /dev/null +++ b/app/presenters/plan_presenter.rb @@ -0,0 +1,28 @@ +class PlanPresenter + delegate :allowance, :open_source?, :price, :title, to: :plan + + def initialize(plan:, user:) + @plan = plan + @user = user + end + + def current? + user.current_plan == plan + end + + def next? + user.next_plan == plan + end + + def to_partial_path + if open_source? + "plans/open_source" + else + "plans/private" + end + end + + private + + attr_reader :plan, :user +end diff --git a/app/presenters/pricing_presenter.rb b/app/presenters/pricing_presenter.rb deleted file mode 100644 index a21e78097..000000000 --- a/app/presenters/pricing_presenter.rb +++ /dev/null @@ -1,32 +0,0 @@ -class PricingPresenter - delegate :allowance, :open_source?, :price, :title, to: :pricing - - def initialize(pricing:, user:) - @pricing = pricing - @user = user - end - - def current? - tier.current == pricing - end - - def next? - tier.next == pricing - end - - def to_partial_path - if open_source? - "pricings/open_source" - else - "pricings/private" - end - end - - private - - attr_reader :pricing, :user - - def tier - @_tier ||= Tier.new(user) - end -end diff --git a/app/serializers/plan_serializer.rb b/app/serializers/plan_serializer.rb new file mode 100644 index 000000000..65f662dce --- /dev/null +++ b/app/serializers/plan_serializer.rb @@ -0,0 +1,11 @@ +class PlanSerializer < ActiveModel::Serializer + attributes :current, :name, :price, :allowance + + def current + scope.current_plan == object + end + + def name + object.title + end +end diff --git a/app/serializers/pricing_serializer.rb b/app/serializers/pricing_serializer.rb deleted file mode 100644 index 219c7d9b0..000000000 --- a/app/serializers/pricing_serializer.rb +++ /dev/null @@ -1,17 +0,0 @@ -class PricingSerializer < ActiveModel::Serializer - attributes :current, :name, :price, :allowance - - def current - current_tier == object - end - - def name - object.title - end - - private - - def current_tier - scope.current_tier - end -end diff --git a/app/serializers/repo_serializer.rb b/app/serializers/repo_serializer.rb index aacd61acc..0a63aac0e 100644 --- a/app/serializers/repo_serializer.rb +++ b/app/serializers/repo_serializer.rb @@ -16,7 +16,7 @@ def price_in_cents if object.public? || object.bulk? 0 else - scope.tier_price * 100 + scope.next_plan_price * 100 end end diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index f076f827d..692e6df43 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -3,7 +3,7 @@ class UserSerializer < ActiveModel::Serializer :id, :refreshing_repos, :subscribed_repo_count, - :tier_allowance, + :plan_max, :username, ) @@ -14,8 +14,4 @@ def card_exists def subscribed_repo_count object.subscribed_repos.count end - - def tier_allowance - object.current_tier.allowance - end end diff --git a/app/services/repo_subscriber.rb b/app/services/repo_subscriber.rb index 67015f975..de0078d2c 100644 --- a/app/services/repo_subscriber.rb +++ b/app/services/repo_subscriber.rb @@ -29,7 +29,7 @@ def unsubscribe def create_subscription payment_gateway_subscription = customer.find_or_create_subscription( - plan: user.current_tier.id, + plan: user.current_plan.id, repo_id: repo.id, ) @@ -38,7 +38,7 @@ def create_subscription repo.create_subscription!( user_id: user.id, stripe_subscription_id: payment_gateway_subscription.id, - price: repo.plan_price, + price: user.next_plan_price, ) rescue => error report_exception(error) diff --git a/app/views/accounts/show.haml b/app/views/accounts/show.haml index 5db21ca9f..d5be9ae92 100644 --- a/app/views/accounts/show.haml +++ b/app/views/accounts/show.haml @@ -7,13 +7,13 @@ %h3 Plans - - @account_page.pricings.each do |pricing| + - @account_page.plans.each do |plan| = render("shared/plan_vertical", - allowance: pricing.allowance, - current: pricing.current?, - name: pricing.title, - new: pricing.next?, - price: pricing.price, + allowance: plan.allowance, + current: plan.current?, + name: plan.title, + new: plan.next?, + price: plan.price, ) .account-content diff --git a/app/views/application/_header.haml b/app/views/application/_header.haml index b0fca8a4a..9714f6435 100644 --- a/app/views/application/_header.haml +++ b/app/views/application/_header.haml @@ -23,7 +23,7 @@ #{current_user.subscribed_repos.count} \/ %span{ "data-role" => "tier-allowance" } - #{current_user.tier_max} + #{current_user.plan_max} %li = link_to account_path, class: "account" do - if current_user.email.present? diff --git a/app/views/home/index.haml b/app/views/home/index.haml index 535b8579d..9f50f9128 100644 --- a/app/views/home/index.haml +++ b/app/views/home/index.haml @@ -136,13 +136,13 @@ %i.fa.fa-book Private Repos - = render(partial: @home.private_pricings, as: :plan) + = render(partial: @home.private_plans, as: :plan) %h4.plan-category.open-source %i.fa.fa-code-fork Open Source - = render(partial: @home.open_source_pricings, as: :plan) + = render(partial: @home.open_source_plans, as: :plan) %section.home-security .section-content diff --git a/app/views/pricings/_open_source.html.erb b/app/views/plans/_open_source.html.erb similarity index 100% rename from app/views/pricings/_open_source.html.erb rename to app/views/plans/_open_source.html.erb diff --git a/app/views/pricings/_private.html.erb b/app/views/plans/_private.html.erb similarity index 100% rename from app/views/pricings/_private.html.erb rename to app/views/plans/_private.html.erb diff --git a/app/views/pricings/index.html.erb b/app/views/plans/index.html.erb similarity index 80% rename from app/views/pricings/index.html.erb rename to app/views/plans/index.html.erb index 962dfb8c5..e1522cd3e 100644 --- a/app/views/pricings/index.html.erb +++ b/app/views/plans/index.html.erb @@ -3,8 +3,8 @@ <%= react_component( "app.NotifyTierChange", authenticity_token: form_authenticity_token, - next_tier: current_user.next_tier, - plans: @pricings, + next_tier: current_user.next_plan, + plans: @plans, repo_id: @repo.id, repo_name: @repo.name, user_has_card: current_user.stripe_customer_id.present?, diff --git a/config/locales/en.yml b/config/locales/en.yml index d9657be73..4befe7c88 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -22,9 +22,6 @@ en: billable_email: invalid: "Email is invalid" - tier_change: - title: "Pricing: A Change of Plans" - onboarding: title: "Let's keep that code in style:" step_one_title: "Activate Hound on a repo." @@ -44,9 +41,9 @@ en: comment inline on the violation in your GitHub pull request." - pricings: + plans: open_source: - allowance: "Unlimited" + allowance: "Unlimited Public Repos" price_html: "$%{price} month" private: diff --git a/config/routes.rb b/config/routes.rb index 199bf6600..d2d540a1d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,12 +16,11 @@ get "/sign_out", to: "sessions#destroy" get "/configuration", to: "pages#configuration" get "/faq", to: "pages#show", id: "faq" - get "/tier_change", to: "pages#show", id: "tier_change" resource :account, only: [:show, :update] resources :builds, only: [:create, :index] resources :owners, only: [:update] - resources :pricings, only: [:index] + resources :plans, only: [:index] resources :repos, only: [:index] do with_options(defaults: { format: :json }) do diff --git a/spec/controllers/deactivations_controller_spec.rb b/spec/controllers/deactivations_controller_spec.rb index b455b83e6..3ef9c004a 100644 --- a/spec/controllers/deactivations_controller_spec.rb +++ b/spec/controllers/deactivations_controller_spec.rb @@ -27,7 +27,7 @@ properties: { name: repo.name, private: false, - revenue: 0, + revenue: -membership.user.next_plan_price, } ) end diff --git a/spec/controllers/subscriptions_controller_spec.rb b/spec/controllers/subscriptions_controller_spec.rb index 3f3eee885..12b3de62d 100644 --- a/spec/controllers/subscriptions_controller_spec.rb +++ b/spec/controllers/subscriptions_controller_spec.rb @@ -68,13 +68,11 @@ end end - context "when the current tier is full" do + context "when the current plan is full" do it "notifies that payment is required" do membership = create(:membership) repo = membership.repo - tier = instance_double("Tier", full?: true) user = membership.user - allow(Tier).to receive(:new).once.with(user).and_return(tier) stub_sign_in(user) post :create, params: { repo_id: repo.id } @@ -173,7 +171,7 @@ properties: { name: repo.name, private: true, - revenue: -repo.plan_price, + revenue: -subscribed_user.next_plan_price, } ) end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 0cf358a2e..a54f70e18 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -13,7 +13,7 @@ id: user.id, refreshing_repos: user.refreshing_repos, subscribed_repo_count: 0, - tier_allowance: 0, + plan_max: 0, username: user.username, }.to_json ) diff --git a/spec/factories.rb b/spec/factories.rb index 7de4996a3..68b4b4299 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -24,13 +24,13 @@ linter_name "ruby" end - factory :pricing do + factory :plan do id "tier1" price 49 range 1..4 title "Chihuahua" - trait :tier2 do + trait :plan2 do id "tier2" price 99 range 5..10 @@ -76,7 +76,7 @@ sequence(:stripe_subscription_id) { |n| "stripesubscription#{n}" } - price { repo.plan_price } + price Plan::PLANS[1][:price] repo user end diff --git a/spec/features/account_spec.rb b/spec/features/account_spec.rb index 09a4803df..c02640548 100644 --- a/spec/features/account_spec.rb +++ b/spec/features/account_spec.rb @@ -20,7 +20,7 @@ expect(page).to have_text("Update Credit Card") end - scenario "returns a list of all pricings", :js do + scenario "returns a list of all plans", :js do user = create(:user) sign_in_as(user, "letmein") diff --git a/spec/features/listing_pricings_spec.rb b/spec/features/plans_spec.rb similarity index 94% rename from spec/features/listing_pricings_spec.rb rename to spec/features/plans_spec.rb index 54d11f768..318f7731f 100644 --- a/spec/features/listing_pricings_spec.rb +++ b/spec/features/plans_spec.rb @@ -1,12 +1,12 @@ require "rails_helper" -feature "Listing Pricings" do +feature "Plans" do scenario "shows all available plans", :js do user = create(:user) repo = create(:repo) sign_in_as(user, "letmein") - visit pricings_path(repo_id: repo.id) + visit plans_path(repo_id: repo.id) plans = page.all(".plan") expect(plans.count).to eq 4 @@ -56,7 +56,7 @@ stub_customer_find_request stub_subscription_create_request(plan: "tier1", repo_ids: repo.id) stub_subscription_update_request(plan: "tier2", repo_ids: repo.id) - visit pricings_path(repo_id: repo.id) + visit plans_path(repo_id: repo.id) click_on "Upgrade" wait_for_ajax diff --git a/spec/features/user_activates_a_repo_spec.rb b/spec/features/user_activates_a_repo_spec.rb index ac3373adc..d851a8499 100644 --- a/spec/features/user_activates_a_repo_spec.rb +++ b/spec/features/user_activates_a_repo_spec.rb @@ -13,12 +13,12 @@ expect(page).to have_text "Active" end - scenario "user upgrades from free tier" do + scenario "user upgrades from free plan" do user = create(:user, :with_github_scopes, :stripe) repo = create(:repo, :private) create(:membership, :admin, repo: repo, user: user) - current_plan = user.current_tier.id - upgraded_plan = user.next_tier.id + current_plan = user.current_plan.id + upgraded_plan = user.next_plan.id stub_customer_find_request stub_subscription_create_request(plan: current_plan, repo_ids: repo.id) stub_subscription_update_request(plan: upgraded_plan, repo_ids: repo.id) @@ -26,16 +26,16 @@ sign_in_as(user, "letmein") click_on "Activate" - expect(page).to have_text "Pricing: Change of Plans" + expect(page).to have_text "Change of Plans" end - scenario "user upgrades within a tier" do + scenario "user upgrades within a plan" do user = create(:user, :with_github_scopes, :stripe) repo = create(:repo, :private) create(:membership, :admin, repo: repo, user: user) create(:subscription, :active, user: user) - current_plan = user.current_tier.id - upgraded_plan = user.next_tier.id + current_plan = user.current_plan.id + upgraded_plan = user.next_plan.id stub_customer_find_request stub_subscription_create_request(plan: current_plan, repo_ids: repo.id) stub_subscription_update_request(plan: upgraded_plan, repo_ids: repo.id) diff --git a/spec/features/user_deactivates_a_repo_spec.rb b/spec/features/user_deactivates_a_repo_spec.rb index 66e76d30e..45a2cdf9a 100644 --- a/spec/features/user_deactivates_a_repo_spec.rb +++ b/spec/features/user_deactivates_a_repo_spec.rb @@ -33,17 +33,14 @@ end end - scenario "user downgrades within a tier" do + scenario "user deactivates within a plan" do user = create(:user, :with_github_scopes, :stripe) first_subscription = create(:subscription, :active, user: user) second_subscription = create(:subscription, :active, user: user) - tier = Tier.new(user) - previous_tier = tier.previous - downgraded_plan = previous_tier.id stub_customer_find_request stub_subscription_find_request(first_subscription) stub_subscription_find_request(second_subscription) - stub_subscription_update_request(plan: downgraded_plan, repo_ids: "") + stub_subscription_update_request(plan: "tier1", repo_ids: "") sign_in_as(user, "letmein") find(".repo--active:nth-of-type(1) .repo-toggle").click @@ -51,19 +48,14 @@ expect(page).to have_text "Private Repos 1 / 4" end - scenario "user downgrades from another tier" do + scenario "user downgrades to lower plan" do user = create(:user, :with_github_scopes, :stripe) - 4.times do + 5.times do subscription = create(:subscription, :active, user: user) stub_subscription_find_request(subscription) end - subscription = create(:subscription, :active, user: user) - stub_subscription_find_request(subscription) - tier = Tier.new(user) - previous_tier = tier.previous - downgraded_plan = previous_tier.id stub_customer_find_request - stub_subscription_update_request(plan: downgraded_plan, repo_ids: "") + stub_subscription_update_request(plan: "tier1", repo_ids: "") sign_in_as(user, "letmein") find(".repo--active:nth-of-type(1) .repo-toggle").click @@ -75,11 +67,8 @@ user = create(:user, :with_github_scopes, :stripe) subscription = create(:subscription, :active, user: user) stub_subscription_find_request(subscription) - tier = Tier.new(user) - previous_tier = tier.previous - downgraded_plan = previous_tier.id stub_customer_find_request - stub_subscription_update_request(plan: downgraded_plan, repo_ids: "") + stub_subscription_update_request(plan: "basic", repo_ids: "") sign_in_as(user, "letmein") find(".repo--active:nth-of-type(1) .repo-toggle").click diff --git a/spec/models/home_spec.rb b/spec/models/home_spec.rb index 507ad7b48..c7fd80938 100644 --- a/spec/models/home_spec.rb +++ b/spec/models/home_spec.rb @@ -1,45 +1,45 @@ require "spec_helper" require "active_model/serializer_support" -require "app/models/pricing" -require "app/presenters/pricing_presenter" +require "app/models/plan" +require "app/presenters/plan_presenter" require "app/models/home" RSpec.describe Home do - describe "#open_source_pricings" do - it "returns all the presented pricings that are open source" do - open_source_pricing = instance_double("Pricing", open_source?: true) - presenter = instance_double("PricingPresenter") - private_pricing = instance_double("Pricing", open_source?: false) - pricings = [open_source_pricing, private_pricing] + describe "#open_source_plans" do + it "returns all the presented plans that are open source" do + open_source_plan = instance_double("Plan", open_source?: true) + presenter = instance_double("PlanPresenter") + private_plan = instance_double("Plan", open_source?: false) + plans = [open_source_plan, private_plan] user = instance_double("User") home = Home.new(user) - allow(Pricing).to receive(:all).and_return(pricings) - allow(PricingPresenter).to receive(:new).and_return(presenter) + allow(Plan).to receive(:all).and_return(plans) + allow(PlanPresenter).to receive(:new).and_return(presenter) - expect(home.open_source_pricings).to eq [presenter] - expect(Pricing).to have_received(:all).once.with(no_args) - expect(PricingPresenter).to have_received(:new).once.with( - pricing: open_source_pricing, + expect(home.open_source_plans).to eq [presenter] + expect(Plan).to have_received(:all).once.with(no_args) + expect(PlanPresenter).to have_received(:new).once.with( + plan: open_source_plan, user: user, ) end end - describe "#private_pricings" do - it "returns all the presented pricings that are not open source" do - open_source_pricing = instance_double("Pricing", open_source?: true) - presenter = instance_double("PricingPresenter") - private_pricing = instance_double("Pricing", open_source?: false) - pricings = [open_source_pricing, private_pricing] + describe "#private_plans" do + it "returns all the presented plans that are not open source" do + open_source_plan = instance_double("Plan", open_source?: true) + presenter = instance_double("PlanPresenter") + private_plan = instance_double("Plan", open_source?: false) + plans = [open_source_plan, private_plan] user = instance_double("User") home = Home.new(user) - allow(Pricing).to receive(:all).and_return(pricings) - allow(PricingPresenter).to receive(:new).and_return(presenter) + allow(Plan).to receive(:all).and_return(plans) + allow(PlanPresenter).to receive(:new).and_return(presenter) - expect(home.private_pricings).to eq [presenter] - expect(Pricing).to have_received(:all).once.with(no_args) - expect(PricingPresenter).to have_received(:new).once.with( - pricing: private_pricing, + expect(home.private_plans).to eq [presenter] + expect(Plan).to have_received(:all).once.with(no_args) + expect(PlanPresenter).to have_received(:new).once.with( + plan: private_plan, user: user, ) end diff --git a/spec/models/payment_gateway_subscription_spec.rb b/spec/models/payment_gateway_subscription_spec.rb index afbbd01b4..f59998b49 100644 --- a/spec/models/payment_gateway_subscription_spec.rb +++ b/spec/models/payment_gateway_subscription_spec.rb @@ -3,45 +3,41 @@ describe PaymentGatewaySubscription do describe "#subscribe" do it "sets the plan to the upgraded tier" do - plan = "tier1" - succ = instance_double("Pricing") + plan_id = "tier1" repo_id = 1 stripe_subscription = MockStripeSubscription.new(repo_ids: ["1"]) - tier = instance_double("Tier") + next_plan = instance_double("Plan", id: plan_id) + user = instance_double("User", next_plan: next_plan) subscription = PaymentGatewaySubscription.new( stripe_subscription: stripe_subscription, - tier: tier, + user: user, ) - allow(succ).to receive(:id).once.with(no_args).and_return(plan) - allow(tier).to receive(:next).once.with(no_args).and_return(succ) subscription.subscribe(repo_id) expect(stripe_subscription).to be_saved expect(stripe_subscription.metadata).to eq("repo_ids" => repo_id.to_s) - expect(stripe_subscription.plan).to eq plan + expect(stripe_subscription.plan).to eq plan_id end end describe "#unsubscribe" do it "sets the plan to the downgraded tier" do - plan = "basic" - previous = instance_double("Pricing") + plan_id = "basic" repo_id = 1 stripe_subscription = MockStripeSubscription.new(repo_ids: [repo_id]) - tier = instance_double("Tier") + plan = instance_double("Plan", id: plan_id) + user = instance_double("User", previous_plan: plan) subscription = PaymentGatewaySubscription.new( stripe_subscription: stripe_subscription, - tier: tier, + user: user, ) - allow(previous).to receive(:id).once.with(no_args).and_return(plan) - allow(tier).to receive(:previous).once.with(no_args).and_return(previous) subscription.unsubscribe(repo_id) expect(stripe_subscription).to be_saved expect(stripe_subscription.metadata).to eq("repo_ids" => nil) - expect(stripe_subscription.plan).to eq plan + expect(stripe_subscription.plan).to eq plan_id end end diff --git a/spec/models/plan_selector_spec.rb b/spec/models/plan_selector_spec.rb new file mode 100644 index 000000000..2980d7dc2 --- /dev/null +++ b/spec/models/plan_selector_spec.rb @@ -0,0 +1,70 @@ +require "active_model/serialization" + +require "app/models/plan" +require "app/models/plan_selector" + +RSpec.describe PlanSelector do + describe "#current_plan" do + it "returns user's current plan" do + user = instance_double("User", subscribed_repos: [double]) + plan_selector = PlanSelector.new(user) + + expect(plan_selector.current_plan).to eq Plan.new(Plan::PLANS[1]) + end + end + + describe "#upgrade?" do + context "when the next plan is different to the current plan" do + it "returns true" do + user = instance_double( + "User", + subscribed_repos: Array.new(4) { double }, + ) + plan_selector = PlanSelector.new(user) + + expect(plan_selector).to be_upgrade + end + end + + context "when the user has no repos" do + it "returns true" do + user = instance_double("User", subscribed_repos: []) + plan_selector = PlanSelector.new(user) + + expect(plan_selector).to be_upgrade + end + end + + context "when the next plan is not the same as the current plan" do + it "returns false" do + user = instance_double( + "User", + subscribed_repos: Array.new(3) { double }, + ) + plan_selector = PlanSelector.new(user) + + expect(plan_selector).not_to be_upgrade + end + end + end + + describe "#next_plan" do + context "when the user has no subscribed repos" do + it "returns the first paid plan" do + user = instance_double("User", subscribed_repos: []) + plan_selector = PlanSelector.new(user) + + expect(plan_selector.next_plan).to eq Plan.new(Plan::PLANS[1]) + end + end + end + + describe "#previous_plan" do + it "returns the second paid plan" do + user = instance_double("User", subscribed_repos: Array.new(10) { double }) + plan_selector = PlanSelector.new(user) + + expect(plan_selector.previous_plan).to eq Plan.new(Plan::PLANS[2]) + end + end +end diff --git a/spec/models/plan_spec.rb b/spec/models/plan_spec.rb index 88c142d1e..90b6bc7a3 100644 --- a/spec/models/plan_spec.rb +++ b/spec/models/plan_spec.rb @@ -1,62 +1,164 @@ -require "spec_helper" +require "active_model/serialization" + require "app/models/plan" -describe Plan do - describe "#type" do - context "with public repo" do - it "returns public" do - public_repo = double("Repo", private?: false, bulk?: false) - plan = Plan.new(public_repo) +RSpec.describe Plan do + describe ".all" do + it "returns all of the plans" do + plans = Plan.all + + expect(plans.count).to eq 4 - expect(plan.type).to eq "public" + [ + [0, "basic", 0, "Hound"], + [4, "tier1", 49, "Chihuahua"], + [10, "tier2", 99, "Labrador"], + [30, "tier3", 249, "Great Dane"], + ].each_with_index do |(allowance, id, price, title), index| + expect(plans[index].allowance).to eq allowance + expect(plans[index].id).to eq id + expect(plans[index].price).to eq price + expect(plans[index].title).to eq title end end + end + + describe ".find_by" do + it "returns the plan where the count is in range" do + plan = Plan.find_by(count: 7) + + expect(plan.allowance).to eq 10 + expect(plan.id).to eq "tier2" + expect(plan.price).to eq 99 + expect(plan.title).to eq "Labrador" + end + end - context "with private repo" do - it "returns private" do - private_repo = double("Repo", private?: true, bulk?: false) - plan = Plan.new(private_repo) + describe "#==" do + context "when the plans have the same identifiers" do + it "returns true" do + allowance = 4 + id = "tier1" + price = 49 + range = 1..allowance + title = "Chihuahua" + plan1 = Plan.new( + id: id, + price: price, + range: range, + title: title, + ) + plan2 = Plan.new( + id: id, + price: price, + range: range, + title: title, + ) - expect(plan.type).to eq "private" + expect(plan1).to eq(plan2) end end - context "with bulk repo" do - it "returns bulk" do - bulk_repo = double("Repo", bulk?: true) - plan = Plan.new(bulk_repo) + context "when the plans have different identifiers" do + it "returns false" do + allowance = 4 + id = "tier1" + price = 49 + range = 1..allowance + title = "Chihuahua" + plan1 = Plan.new( + id: id, + price: price, + range: range, + title: title, + ) + plan2 = Plan.new( + id: "tier2", + price: price, + range: range, + title: title, + ) - expect(plan.type).to eq "bulk" + expect(plan1).to_not eq(plan2) end end end - describe "#price" do - context "with public repo" do - it "returns public price" do - public_repo = double("Repo", private?: false, bulk?: false) - plan = Plan.new(public_repo) + describe "#allowance" do + it "returns the upper bound of the range" do + allowance = 4 + id = "tier1" + price = 49 + range = 1..allowance + title = "Chihuahua" + plan = Plan.new(id: id, price: price, range: range, title: title) - expect(plan.price).to eq 0 - end + expect(plan.allowance).to eq allowance end + end - context "with private repo" do - it "returns private price" do - private_repo = double("Repo", private?: true, bulk?: false) - plan = Plan.new(private_repo) + describe "#id" do + it "returns the initialized identifier" do + allowance = 4 + id = "tier1" + price = 49 + range = 1..allowance + title = "Chihuahua" + plan = Plan.new(id: id, price: price, range: range, title: title) - expect(plan.price).to eq 12 - end + expect(plan.id).to eq id + end + end + + describe "#open_source?" do + it "returns true" do + plan = Plan.new( + id: "basic", + price: 0, + range: 0..0, + title: "Hound", + ) + + expect(plan).to be_open_source end - context "with bulk repo" do - it "returns bulk price" do - bulk_repo = double("Repo", bulk?: true) - plan = Plan.new(bulk_repo) + context "when the price is positive" do + it "returns false" do + plan = Plan.new( + id: "tier1", + price: 49, + range: 1..4, + title: "Chihuahua", + ) - expect(plan.price).to eq 0 + expect(plan).to_not be_open_source end end end + + describe "#price" do + it "returns the initialized price" do + allowance = 4 + id = "tier1" + price = 49 + range = 1..allowance + title = "Chihuahua" + plan = Plan.new(id: id, price: price, range: range, title: title) + + expect(plan.price).to eq price + end + end + + describe "#title" do + it "returns the initialized title" do + allowance = 4 + id = "tier1" + price = 49 + range = 1..allowance + title = "Chihuahua" + plan = Plan.new(id: id, price: price, range: range, title: title) + + expect(plan.title).to eq title + end + end end diff --git a/spec/models/pricing_spec.rb b/spec/models/pricing_spec.rb deleted file mode 100644 index 210928cfc..000000000 --- a/spec/models/pricing_spec.rb +++ /dev/null @@ -1,164 +0,0 @@ -require "spec_helper" -require "active_model/serializer_support" -require "app/models/pricing" - -RSpec.describe Pricing do - describe ".all" do - it "returns all of the pricings" do - pricings = Pricing.all - - expect(pricings.count).to eq 4 - - [ - [0, "basic", 0, "Hound"], - [4, "tier1", 49, "Chihuahua"], - [10, "tier2", 99, "Labrador"], - [30, "tier3", 249, "Great Dane"], - ].each_with_index do |(allowance, id, price, title), index| - expect(pricings[index].allowance).to eq allowance - expect(pricings[index].id).to eq id - expect(pricings[index].price).to eq price - expect(pricings[index].title).to eq title - end - end - end - - describe ".find_by" do - it "returns the pricing where the count is in range" do - pricing = Pricing.find_by(count: 7) - - expect(pricing.allowance).to eq 10 - expect(pricing.id).to eq "tier2" - expect(pricing.price).to eq 99 - expect(pricing.title).to eq "Labrador" - end - end - - describe "#==" do - context "when the pricings have the same identifiers" do - it "returns true" do - allowance = 4 - id = "tier1" - price = 49 - range = 1..allowance - title = "Chihuahua" - pricing_1 = Pricing.new( - id: id, - price: price, - range: range, - title: title, - ) - pricing_2 = Pricing.new( - id: id, - price: price, - range: range, - title: title, - ) - - expect(pricing_1).to eq(pricing_2) - end - end - - context "when the pricings have different identifiers" do - it "returns false" do - allowance = 4 - id = "tier1" - price = 49 - range = 1..allowance - title = "Chihuahua" - pricing_1 = Pricing.new( - id: id, - price: price, - range: range, - title: title, - ) - pricing_2 = Pricing.new( - id: "tier2", - price: price, - range: range, - title: title, - ) - - expect(pricing_1).to_not eq(pricing_2) - end - end - end - - describe "#allowance" do - it "returns the upper bound of the range" do - allowance = 4 - id = "tier1" - price = 49 - range = 1..allowance - title = "Chihuahua" - pricing = Pricing.new(id: id, price: price, range: range, title: title) - - expect(pricing.allowance).to eq allowance - end - end - - describe "#id" do - it "returns the initialized identifier" do - allowance = 4 - id = "tier1" - price = 49 - range = 1..allowance - title = "Chihuahua" - pricing = Pricing.new(id: id, price: price, range: range, title: title) - - expect(pricing.id).to eq id - end - end - - describe "#open_source?" do - it "returns true" do - pricing = Pricing.new( - id: "basic", - price: 0, - range: 0..0, - title: "Hound", - ) - - expect(pricing).to be_open_source - end - - context "when the price is positive" do - it "returns false" do - pricing = Pricing.new( - id: "tier1", - price: 49, - range: 1..4, - title: "Chihuahua", - ) - - expect(pricing).to_not be_open_source - end - end - end - - describe "#price" do - it "returns the initialized price" do - allowance = 4 - id = "tier1" - price = 49 - range = 1..allowance - title = "Chihuahua" - pricing = Pricing.new(id: id, price: price, range: range, title: title) - - expect(pricing.price).to eq price - end - end - - describe "#title" do - it "returns the initialized title" do - allowance = 4 - id = "tier1" - price = 49 - range = 1..allowance - title = "Chihuahua" - pricing = Pricing.new(id: id, price: price, range: range, title: title) - - expect(pricing.title).to eq title - end - end -end diff --git a/spec/models/repo_spec.rb b/spec/models/repo_spec.rb index ef2427518..0973b3cb2 100644 --- a/spec/models/repo_spec.rb +++ b/spec/models/repo_spec.rb @@ -59,24 +59,6 @@ end end - describe "#plan_type" do - context "when repo is public" do - it "returns public plan type" do - repo = Repo.new(private: false) - - expect(repo.plan_type).to eq "public" - end - end - - context "when repo is private" do - it "returns private plan type" do - repo = Repo.new(private: true) - - expect(repo.plan_type).to eq "private" - end - end - end - describe "#activate" do it "updates repo active value to true" do repo = create(:repo, active: false) diff --git a/spec/models/tier_spec.rb b/spec/models/tier_spec.rb deleted file mode 100644 index bc8462706..000000000 --- a/spec/models/tier_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -require "rails_helper" - -RSpec.describe Tier do - describe "#current" do - it "returns user's current pricing" do - count = 1 - pricing = instance_double("Pricing") - repos = class_double(Repo, count: count) - user = instance_double("User", subscribed_repos: repos) - tier = Tier.new(user) - allow(Pricing).to receive(:find_by).once.with(count: count). - and_return(pricing) - - expect(tier.current).to eq pricing - end - end - - describe "#full?" do - context "when the next tier is different to the current tier" do - it "returns true" do - repos = class_double(Repo, count: 4) - user = instance_double("User", subscribed_repos: repos) - tier = Tier.new(user) - - expect(tier).to be_full - end - end - - context "when the user has no repos" do - it "is full" do - user = create(:user) - tier = Tier.new(user) - - expect(tier).to be_full - end - end - - context "when the next tier is not the same as the current tier" do - it "returns false" do - repos = class_double(Repo, count: 3) - user = instance_double("User", subscribed_repos: repos) - tier = Tier.new(user) - - expect(tier.full?).to be(false) - end - end - end - - describe "#next" do - context "when the user has no subscribed repos" do - it "returns the 'Tier 1' tier" do - count = 1 - pricing = instance_double("Pricing") - repos = class_double(Repo, count: count) - user = instance_double("User", subscribed_repos: repos) - tier = Tier.new(user) - allow(Pricing).to receive(:find_by).once.with(count: count.succ). - and_return(pricing) - - expect(tier.next).to eq pricing - end - end - end - - describe "#previous" do - it "returns the pricing for the preceding count's tier" do - count = 0 - pricing = instance_double("Pricing") - repo = instance_double("Repo") - user = instance_double("User") - tier = Tier.new(user) - allow(Pricing).to receive(:find_by).once.with(count: count). - and_return(pricing) - allow(user).to receive(:subscribed_repos).once.with(no_args). - and_return([repo]) - - expect(tier.previous).to eq pricing - end - end -end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 764320bb2..9ee0c3d17 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -6,44 +6,36 @@ it { should validate_presence_of :username } it { should have_many(:memberships).dependent(:destroy) } - describe "#current_tier" do - it "returns the current tier identifier" do - pricing = Pricing.new(id: "basic", price: 0, range: 0..0, title: "Hound") - user = create(:user) + describe "#current_plan" do + it "returns the current plan" do + user = User.new - expect(user.current_tier).to eq pricing + expect(user.current_plan).to eq Plan.new(Plan::PLANS[0]) end end - describe "#next_tier" do - it "returns the next tier identifier" do - user = build(:user) - id = "NEXT_TIER_ID" - tier = instance_double("Tier", next: id) - allow(Tier).to receive(:new).once.with(user).and_return(tier) + describe "#next_plan" do + it "returns the next plan" do + user = User.new - expect(user.next_tier).to eq id + expect(user.next_plan).to eq Plan.new(Plan::PLANS[1]) end end - describe "#tier_max" do - it "returns the current tier's allowance" do - allowance = 10 - pricing = instance_double("Pricing", allowance: allowance) - tier = instance_double("Tier", current: pricing) - user = User.new - allow(Tier).to receive(:new).once.with(user).and_return(tier) + describe "#plan_max" do + it "returns the current plan's allowance" do + user = User.new(subscribed_repos: Array.new(5) { Repo.new }) - expect(user.tier_max).to eq allowance + expect(user.plan_max).to eq Plan::PLANS[2][:range].max end end - describe "#tier_price" do - it "returns the price of the next tier" do + describe "#next_plan_price" do + it "returns the price of the next plan" do subscription = create(:subscription) user = subscription.user - expect(user.tier_price).to eq 49 + expect(user.next_plan_price).to eq 49 end end diff --git a/spec/presenters/account_page_spec.rb b/spec/presenters/account_page_spec.rb index 347070789..91938d495 100644 --- a/spec/presenters/account_page_spec.rb +++ b/spec/presenters/account_page_spec.rb @@ -2,13 +2,11 @@ RSpec.describe AccountPage do describe "#allowance" do - it "returns the allowance of the current tier" do + it "returns the allowance of the current plan" do allowance = 10 - pricing = instance_double("Pricing", allowance: allowance) - tier = instance_double("Tier", current: pricing) - user = instance_double("User") + plan = instance_double("Plan", allowance: allowance) + user = instance_double("User", current_plan: plan) page = AccountPage.new(user) - allow(Tier).to receive(:new).once.with(user).and_return(tier) expect(page.allowance).to eq allowance end @@ -35,43 +33,43 @@ end describe "#plan" do - it "returns the name of the current tier" do - plan = "Chihuahua" - pricing = instance_double("Pricing", title: plan) - tier = instance_double("Tier", current: pricing) - user = instance_double("User") + it "returns the name of the current plan" do + plan_name = "Chihuahua" + plan = instance_double("Plan", title: plan_name) + user = instance_double("User", current_plan: plan) page = AccountPage.new(user) - allow(Tier).to receive(:new).once.with(user).and_return(tier) - expect(page.plan).to eq plan + expect(page.plan).to eq plan_name end end - describe "#pricings" do - it "returns all of the presentable, available pricings" do - presenter = instance_double("PricingPresenter") - pricing = instance_double("Pricing") + describe "#plans" do + it "returns all of the presentable, available plans" do + presenter = instance_double("PlanPresenter") + plan = instance_double("Plan") user = instance_double("User") page = AccountPage.new(user) - allow(Pricing).to receive(:all).once.with(no_args).and_return([pricing]) - allow(PricingPresenter).to receive(:new).once.with( - pricing: pricing, + allow(Plan).to receive(:all).once.with(no_args).and_return([plan]) + allow(PlanPresenter).to receive(:new).once.with( + plan: plan, user: user, ).and_return(presenter) - expect(page.pricings).to eq [presenter] + expect(page.plans).to eq [presenter] end end describe "#remaining" do - it "returns the number of remaining repos available in the current tier" do - pricing = instance_double("Pricing", allowance: 10) + it "returns the number of remaining repos available in the current plan" do + plan = instance_double("Plan", allowance: 10) remaining = 9 repos = class_double("Repo", count: 1) - tier = instance_double("Tier", current: pricing) - user = instance_double("User", subscribed_repos: repos) + user = instance_double( + "User", + current_plan: plan, + subscribed_repos: repos, + ) page = AccountPage.new(user) - allow(Tier).to receive(:new).once.with(user).and_return(tier) expect(page.remaining).to eq remaining end diff --git a/spec/presenters/plan_presenter_spec.rb b/spec/presenters/plan_presenter_spec.rb new file mode 100644 index 000000000..4aa7f10ec --- /dev/null +++ b/spec/presenters/plan_presenter_spec.rb @@ -0,0 +1,117 @@ +require "rails_helper" + +RSpec.describe PlanPresenter do + describe "#allowance" do + it "returns the plan's allowance" do + user = create(:user) + plan = build_stubbed(:plan) + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter.allowance).to eq plan.allowance + end + end + + describe "#current?" do + context "when the plan matches the user's current plan" do + it "returns true" do + membership = create(:membership) + user = membership.user + create(:subscription, repo: membership.repo, user: user) + plan = build_stubbed(:plan) + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter).to be_current + end + end + + context "when the plan does not match the user's current plan" do + it "returns false" do + membership = create(:membership) + user = membership.user + create(:subscription, repo: membership.repo, user: user) + plan = build_stubbed(:plan, :plan2) + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter).to_not be_current + end + end + end + + describe "#next?" do + context "when the plan matches the user's next plan" do + it "returns true" do + membership = create(:membership) + user = membership.user + create(:subscription, repo: membership.repo, user: user) + plan = build_stubbed(:plan) + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter).to be_next + end + end + + context "when the plan does not match the user's next plan" do + it "returns false" do + membership = create(:membership) + user = membership.user + create(:subscription, repo: membership.repo, user: user) + plan = build_stubbed(:plan, :plan2) + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter).to_not be_next + end + end + end + + describe "#open_source?" do + it "returns the plan's open source state" do + plan = instance_double("Plan", open_source?: true) + user = instance_double("User") + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter).to be_open_source + end + end + + describe "#price" do + it "returns the plan's price" do + user = create(:user) + plan = build_stubbed(:plan) + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter.price).to eq plan.price + end + end + + describe "#to_partial_path" do + context "when the plan is for open source repos" do + it "returns 'plans/open_source'" do + plan = instance_double("Plan", open_source?: true) + user = instance_double("User") + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter.to_partial_path).to eq("plans/open_source") + end + end + + context "when the plan is for private repos" do + it "returns 'plans/private'" do + plan = instance_double("Plan", open_source?: false) + user = instance_double("User") + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter.to_partial_path).to eq("plans/private") + end + end + end + + describe "#title" do + it "returns the plan's title" do + user = create(:user) + plan = build_stubbed(:plan) + presenter = PlanPresenter.new(plan: plan, user: user) + + expect(presenter.title).to eq plan.title + end + end +end diff --git a/spec/presenters/pricing_presenter_spec.rb b/spec/presenters/pricing_presenter_spec.rb deleted file mode 100644 index 2ed48d461..000000000 --- a/spec/presenters/pricing_presenter_spec.rb +++ /dev/null @@ -1,117 +0,0 @@ -require "rails_helper" - -RSpec.describe PricingPresenter do - describe "#allowance" do - it "returns the pricing's allowance" do - user = create(:user) - pricing = build_stubbed(:pricing) - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter.allowance).to eq pricing.allowance - end - end - - describe "#current?" do - context "when the pricing matches the user's current pricing" do - it "returns true" do - membership = create(:membership) - user = membership.user - create(:subscription, repo: membership.repo, user: user) - pricing = build_stubbed(:pricing) - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter).to be_current - end - end - - context "when the pricing does not match the user's current pricing" do - it "returns false" do - membership = create(:membership) - user = membership.user - create(:subscription, repo: membership.repo, user: user) - pricing = build_stubbed(:pricing, :tier2) - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter).to_not be_current - end - end - end - - describe "#next?" do - context "when the pricing matches the user's next pricing" do - it "returns true" do - membership = create(:membership) - user = membership.user - create(:subscription, repo: membership.repo, user: user) - pricing = build_stubbed(:pricing) - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter).to be_next - end - end - - context "when the pricing does not match the user's next pricing" do - it "returns false" do - membership = create(:membership) - user = membership.user - create(:subscription, repo: membership.repo, user: user) - pricing = build_stubbed(:pricing, :tier2) - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter).to_not be_next - end - end - end - - describe "#open_source?" do - it "returns the pricing's open source state" do - pricing = instance_double("Pricing", open_source?: true) - user = instance_double("User") - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter).to be_open_source - end - end - - describe "#price" do - it "returns the pricing's price" do - user = create(:user) - pricing = build_stubbed(:pricing) - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter.price).to eq pricing.price - end - end - - describe "#to_partial_path" do - context "when the pricing is for open source repos" do - it "returns 'pricings/open_source'" do - pricing = instance_double("Pricing", open_source?: true) - user = instance_double("User") - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter.to_partial_path).to eq("pricings/open_source") - end - end - - context "when the pricing is for private repos" do - it "returns 'pricings/private'" do - pricing = instance_double("Pricing", open_source?: false) - user = instance_double("User") - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter.to_partial_path).to eq("pricings/private") - end - end - end - - describe "#title" do - it "returns the pricing's title" do - user = create(:user) - pricing = build_stubbed(:pricing) - presenter = PricingPresenter.new(pricing: pricing, user: user) - - expect(presenter.title).to eq pricing.title - end - end -end diff --git a/spec/serializers/plan_serializer_spec.rb b/spec/serializers/plan_serializer_spec.rb new file mode 100644 index 000000000..2b759f4ab --- /dev/null +++ b/spec/serializers/plan_serializer_spec.rb @@ -0,0 +1,24 @@ +require "active_model_serializers" + +require "app/models/plan" +require "app/serializers/plan_serializer" + +RSpec.describe PlanSerializer do + describe "#as_json" do + it "returns the plan as a JSON object" do + allowance = 0 + price = 0 + title = "Hound" + plan = Plan.new(id: "foo", title: title, range: 0..0, price: price) + user = instance_double("User", current_plan: plan) + serializer = PlanSerializer.new(plan, root: false, scope: user) + + expect(serializer.as_json).to eq( + current: true, + name: title, + price: price, + allowance: allowance, + ) + end + end +end diff --git a/spec/serializers/pricing_serializer_spec.rb b/spec/serializers/pricing_serializer_spec.rb deleted file mode 100644 index 8a405cee7..000000000 --- a/spec/serializers/pricing_serializer_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require "spec_helper" -require "active_model/serializer" -require "app/serializers/pricing_serializer" - -RSpec.describe PricingSerializer do - describe "#as_json" do - it "returns the pricing as a JSON object" do - allowance = 0 - price = 0 - title = "Hound" - pricing = instance_double("Pricing", title: title) - tier = instance_double("Tier") - user = instance_double("User", current_tier: tier) - serializer = PricingSerializer.new(pricing, root: false, scope: user) - allow(pricing).to receive(:read_attribute_for_serialization).once. - with(:allowance).and_return(allowance) - allow(pricing).to receive(:read_attribute_for_serialization).once. - with(:price).and_return(price) - - expect(serializer.as_json).to eq( - current: false, - name: title, - price: price, - allowance: allowance, - ) - end - end -end diff --git a/spec/serializers/repo_serializer_spec.rb b/spec/serializers/repo_serializer_spec.rb index 9cc82639f..4a8659084 100644 --- a/spec/serializers/repo_serializer_spec.rb +++ b/spec/serializers/repo_serializer_spec.rb @@ -75,17 +75,19 @@ end context "when the repo is private" do - it "returns subscription price in cents if the repo were activated" do - repo = create(:repo, private: true) - membership = create(:membership, admin: true, repo: repo) - user = membership.user - serializer = RepoSerializer.new( - repo, - scope: user, - scope_name: :current_user, - ) + context "and the repo was activated" do + it "returns subscription price in cents" do + repo = create(:repo, private: true) + membership = create(:membership, admin: true, repo: repo) + user = membership.user + serializer = RepoSerializer.new( + repo, + scope: user, + scope_name: :current_user, + ) - expect(serializer.price_in_cents).to eq(user.tier_price * 100) + expect(serializer.price_in_cents).to eq(user.next_plan_price * 100) + end end end end diff --git a/spec/serializers/user_serializer_spec.rb b/spec/serializers/user_serializer_spec.rb index b37bcbd07..1eb859df2 100644 --- a/spec/serializers/user_serializer_spec.rb +++ b/spec/serializers/user_serializer_spec.rb @@ -11,13 +11,13 @@ end end - describe "#tier_allowance" do - it "is the number of subscriptions allowed within the current tier" do - current_tier = instance_double(Pricing, allowance: 4) - user = instance_double(User, current_tier: current_tier) + describe "#plan_max" do + it "returns the number of subscriptions allowed within the current plan" do + subscription = create(:subscription) + user = create(:user, subscriptions: [subscription]) serializer = UserSerializer.new(user) - expect(serializer.tier_allowance).to eq 4 + expect(serializer.plan_max).to eq 4 end end end diff --git a/spec/services/repo_subscriber_spec.rb b/spec/services/repo_subscriber_spec.rb index 36c88d805..65fa457ad 100644 --- a/spec/services/repo_subscriber_spec.rb +++ b/spec/services/repo_subscriber_spec.rb @@ -14,11 +14,11 @@ stub_customer_find_request update_request = stub_customer_update_request subscription_request = stub_subscription_create_request( - plan: user.current_tier.id, + plan: user.current_plan.id, repo_ids: repo.id, ) subscription_update_request = stub_subscription_update_request( - plan: user.next_tier.id, + plan: user.next_plan.id, repo_ids: repo.id, ) @@ -29,7 +29,6 @@ expect(update_request).not_to have_been_requested expect(repo.subscription.stripe_subscription_id). to eq(stripe_subscription_id) - expect(repo.subscription_price).to(eq(Plan::PRICES[:private])) end end @@ -57,7 +56,6 @@ expect(subscription_update_request).to have_been_requested expect(repo.subscription.stripe_subscription_id). to eq(stripe_subscription_id) - expect(repo.subscription_price).to(eq(Plan::PRICES[:private])) end end end @@ -68,11 +66,11 @@ user = create(:user, repos: [repo], stripe_customer_id: "",) customer_request = stub_customer_create_request(user) subscription_request = stub_subscription_create_request( - plan: user.current_tier.id, + plan: user.current_plan.id, repo_ids: repo.id, ) update_request = stub_subscription_update_request( - plan: user.next_tier.id, + plan: user.next_plan.id, repo_ids: repo.id, ) @@ -92,7 +90,7 @@ repo = create(:repo) user = create(:user, repos: [repo]) stub_customer_create_request(user) - stub_failed_subscription_create_request(user.current_tier.id) + stub_failed_subscription_create_request(user.current_plan.id) result = RepoSubscriber.subscribe(repo, user, "cardtoken") @@ -103,7 +101,7 @@ repo = build_stubbed(:repo) user = create(:user) stub_customer_create_request(user) - stub_failed_subscription_create_request(user.current_tier.id) + stub_failed_subscription_create_request(user.current_plan.id) allow(Raven).to receive(:capture_exception) RepoSubscriber.subscribe(repo, user, "cardtoken") @@ -118,11 +116,11 @@ user = create(:user, repos: [repo]) stub_customer_create_request(user) stub_subscription_create_request( - plan: user.current_tier.id, + plan: user.current_plan.id, repo_ids: repo.id, ) stub_subscription_update_request( - plan: user.next_tier.id, + plan: user.next_plan.id, repo_ids: repo.id, ) stripe_delete_request = stub_subscription_delete_request @@ -153,7 +151,7 @@ end describe ".unsubscribe" do - it "updates the Stripe plan" do + it "downgrades the Stripe plan" do subscription = subscription_with_user stub_customer_find_request stub_subscription_find_request(subscription, quantity: 2) @@ -197,12 +195,12 @@ def subscription_with_user user = create(:user, stripe_customer_id: stripe_customer_id) - subscription = create( + repo = create(:repo, :private, users: [user]) + create( :subscription, stripe_subscription_id: stripe_subscription_id, user: user, + repo: repo, ) - user.repos << subscription.repo - subscription end end diff --git a/yarn.lock b/yarn.lock index 4379b7042..4dd627216 100644 --- a/yarn.lock +++ b/yarn.lock @@ -204,10 +204,6 @@ async@^2.1.2, async@^2.1.4: dependencies: lodash "^4.14.0" -async@~0.2.6: - version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -2578,14 +2574,14 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - -inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" @@ -5065,16 +5061,7 @@ ua-parser-js@^0.7.9: version "0.7.12" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" -uglify-js@^2.6: - version "2.7.5" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" - dependencies: - async "~0.2.6" - source-map "~0.5.1" - uglify-to-browserify "~1.0.0" - yargs "~3.10.0" - -uglify-js@^2.8.5: +uglify-js@^2.6, uglify-js@^2.8.5: version "2.8.14" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.14.tgz#25b15d1af39b21752ee33703adbf432e8bc8f77d" dependencies: