From 66e8857c208abc8cb080cef86b2a7b822c508fb8 Mon Sep 17 00:00:00 2001 From: Blake Erickson Date: Thu, 2 May 2024 13:38:30 -0600 Subject: [PATCH] DEV: Stop deleting customers on cancel (#207) Instead of deleting customers on cancel we will now update the subscription status to canceled. This way we can have some visibility on which users have canceled. --- .../admin/subscriptions_controller.rb | 1 + .../hooks_controller.rb | 56 ++++--- .../subscribe_controller.rb | 18 ++- .../user/subscriptions_controller.rb | 16 +- ...40430163338_add_status_to_subscriptions.rb | 7 + spec/fixtures/json/stripe-price-list.json | 67 ++++++++ .../json/stripe-subscription-list.json | 149 ++++++++++++++++++ .../admin/subscriptions_controller_spec.rb | 4 +- spec/requests/hooks_controller_spec.rb | 25 ++- spec/requests/subscribe_controller_spec.rb | 7 +- .../user/subscriptions_controller_spec.rb | 80 ++++------ .../admin_subscription_subscription.rb | 32 ++++ .../page_objects/user_billing_subscription.rb | 32 ++++ spec/system/pricing_table_spec.rb | 10 -- spec/system/subscription_subscription_spec.rb | 92 +++++++++++ 15 files changed, 500 insertions(+), 96 deletions(-) create mode 100644 db/migrate/20240430163338_add_status_to_subscriptions.rb create mode 100644 spec/fixtures/json/stripe-price-list.json create mode 100644 spec/fixtures/json/stripe-subscription-list.json create mode 100644 spec/system/page_objects/admin_subscription_subscription.rb create mode 100644 spec/system/page_objects/user_billing_subscription.rb create mode 100644 spec/system/subscription_subscription_spec.rb diff --git a/app/controllers/discourse_subscriptions/admin/subscriptions_controller.rb b/app/controllers/discourse_subscriptions/admin/subscriptions_controller.rb index 53ba5a5..ffa7592 100644 --- a/app/controllers/discourse_subscriptions/admin/subscriptions_controller.rb +++ b/app/controllers/discourse_subscriptions/admin/subscriptions_controller.rb @@ -83,6 +83,7 @@ module DiscourseSubscriptions expand: ["data.plan.product"], limit: PAGE_LIMIT, starting_after: start, + status: "all", ) end diff --git a/app/controllers/discourse_subscriptions/hooks_controller.rb b/app/controllers/discourse_subscriptions/hooks_controller.rb index 7e3914e..0113577 100644 --- a/app/controllers/discourse_subscriptions/hooks_controller.rb +++ b/app/controllers/discourse_subscriptions/hooks_controller.rb @@ -39,11 +39,7 @@ module DiscourseSubscriptions user = ::User.find_by_username_or_email(email) - discourse_customer = Customer.find_by(user_id: user.id) - - if discourse_customer.nil? - discourse_customer = Customer.create(user_id: user.id, customer_id: customer_id) - end + discourse_customer = Customer.create(user_id: user.id, customer_id: customer_id) Subscription.create( customer_id: discourse_customer.id, @@ -64,48 +60,60 @@ module DiscourseSubscriptions ) when "customer.subscription.created" when "customer.subscription.updated" - status = event[:data][:object][:status] + subscription = event[:data][:object] + status = subscription[:status] return head 200 if !%w[complete active].include?(status) - customer = - Customer.find_by( - customer_id: event[:data][:object][:customer], - product_id: event[:data][:object][:plan][:product], - ) + customer = find_active_customer(subscription[:customer], subscription[:plan][:product]) return render_json_error "customer not found" if !customer + update_status(customer.id, subscription[:id], status) + user = ::User.find_by(id: customer.user_id) return render_json_error "user not found" if !user - if group = plan_group(event[:data][:object][:plan]) + if group = plan_group(subscription[:plan]) group.add(user) end when "customer.subscription.deleted" - customer = - Customer.find_by( - customer_id: event[:data][:object][:customer], - product_id: event[:data][:object][:plan][:product], - ) + subscription = event[:data][:object] + + customer = find_active_customer(subscription[:customer], subscription[:plan][:product]) return render_json_error "customer not found" if !customer - Subscription.find_by( - customer_id: customer.id, - external_id: event[:data][:object][:id], - )&.destroy! + update_status(customer.id, subscription[:id], subscription[:status]) user = ::User.find(customer.user_id) return render_json_error "user not found" if !user - if group = plan_group(event[:data][:object][:plan]) + if group = plan_group(subscription[:plan]) group.remove(user) end - - customer.destroy! end head 200 end + + private + + def update_status(customer_id, subscription_id, status) + discourse_subscription = + Subscription.find_by(customer_id: customer_id, external_id: subscription_id) + discourse_subscription.update(status: status) if discourse_subscription + end + + def find_active_customer(customer_id, product_id) + Customer + .joins(:subscriptions) + .where(customer_id: customer_id, product_id: product_id) + .where( + Subscription.arel_table[:status].eq(nil).or( + Subscription.arel_table[:status].not_eq("canceled"), + ), + ) + .first + end end end diff --git a/app/controllers/discourse_subscriptions/subscribe_controller.rb b/app/controllers/discourse_subscriptions/subscribe_controller.rb index 0670fec..e1aa019 100644 --- a/app/controllers/discourse_subscriptions/subscribe_controller.rb +++ b/app/controllers/discourse_subscriptions/subscribe_controller.rb @@ -150,7 +150,11 @@ module DiscourseSubscriptions ) if transaction[:object] == "subscription" - Subscription.create(customer_id: customer.id, external_id: transaction[:id]) + Subscription.create( + customer_id: customer.id, + external_id: transaction[:id], + status: transaction[:status], + ) end end @@ -169,7 +173,17 @@ module DiscourseSubscriptions def current_user_products return [] if current_user.nil? - Customer.select(:product_id).where(user_id: current_user.id).map { |c| c.product_id }.compact + Customer + .joins(:subscriptions) + .where(user_id: current_user.id) + .where( + Subscription.arel_table[:status].eq(nil).or( + Subscription.arel_table[:status].not_eq("canceled"), + ), + ) + .select(:product_id) + .distinct + .pluck(:product_id) end def serialize_plans(plans) diff --git a/app/controllers/discourse_subscriptions/user/subscriptions_controller.rb b/app/controllers/discourse_subscriptions/user/subscriptions_controller.rb index e992dfa..5d581fe 100644 --- a/app/controllers/discourse_subscriptions/user/subscriptions_controller.rb +++ b/app/controllers/discourse_subscriptions/user/subscriptions_controller.rb @@ -15,6 +15,7 @@ module DiscourseSubscriptions begin customer = Customer.where(user_id: current_user.id) customer_ids = customer.map { |c| c.id } if customer + stripe_customer_ids = customer.map { |c| c.customer_id } if customer subscription_ids = Subscription.where("customer_id in (?)", customer_ids).pluck( :external_id, @@ -24,15 +25,14 @@ module DiscourseSubscriptions if subscription_ids plans = ::Stripe::Price.list(expand: ["data.product"], limit: 100) + all_subscriptions = [] - customers = - ::Stripe::Customer.list(email: current_user.email, expand: ["data.subscriptions"]) - - subscriptions = - customers[:data].map { |sub_customer| sub_customer[:subscriptions][:data] }.flatten(1) - - subscriptions = subscriptions.select { |sub| subscription_ids.include?(sub[:id]) } - + stripe_customer_ids.each do |stripe_customer_id| + customer_subscriptions = + ::Stripe::Subscription.list(customer: stripe_customer_id, status: "all") + all_subscriptions.concat(customer_subscriptions[:data]) + end + subscriptions = all_subscriptions.select { |sub| subscription_ids.include?(sub[:id]) } subscriptions.map! do |subscription| plan = plans[:data].find { |p| p[:id] == subscription[:items][:data][0][:price][:id] } subscription.to_h.except!(:plan) diff --git a/db/migrate/20240430163338_add_status_to_subscriptions.rb b/db/migrate/20240430163338_add_status_to_subscriptions.rb new file mode 100644 index 0000000..38c9bd5 --- /dev/null +++ b/db/migrate/20240430163338_add_status_to_subscriptions.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddStatusToSubscriptions < ActiveRecord::Migration[7.0] + def change + add_column :discourse_subscriptions_subscriptions, :status, :string + end +end diff --git a/spec/fixtures/json/stripe-price-list.json b/spec/fixtures/json/stripe-price-list.json new file mode 100644 index 0000000..fd0076f --- /dev/null +++ b/spec/fixtures/json/stripe-price-list.json @@ -0,0 +1,67 @@ +{ + "object": "list", + "data": [ + { + "id": "price_1OrmlvEYXaQnncShNahrpKvA", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1709840311, + "currency": "usd", + "custom_unit_amount": null, + "livemode": false, + "lookup_key": null, + "metadata": { + "group_name": "subscribers", + "trial_period_days": "0" + }, + "nickname": "EA1", + "product": { + "id": "prod_PhB6IpGhEX14Hi", + "object": "product", + "active": true, + "attributes": [ + + ], + "created": 1709840195, + "default_price": null, + "description": null, + "images": [ + + ], + "livemode": false, + "marketing_features": [ + + ], + "metadata": { + "description": "Sign up and get access to an exclusive group of enthusiasts just like you!" + }, + "name": "Exclusive Access", + "package_dimensions": null, + "shippable": null, + "statement_descriptor": "TESTING", + "tax_code": null, + "type": "service", + "unit_label": null, + "updated": 1709840195, + "url": null + }, + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "meter": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 1000, + "unit_amount_decimal": "1000" + } + ], + "has_more": false, + "url": "/v1/prices" +} \ No newline at end of file diff --git a/spec/fixtures/json/stripe-subscription-list.json b/spec/fixtures/json/stripe-subscription-list.json new file mode 100644 index 0000000..26ea417 --- /dev/null +++ b/spec/fixtures/json/stripe-subscription-list.json @@ -0,0 +1,149 @@ +{ + "has_more": false, + "data": [ + { + "id": "sub_10z", + "object": "subscription", + "created": 1714594277, + "current_period_end": 1717272677, + "current_period_start": 1714594277, + "customer": "cus_Q1n43We0YFjnlc", + "items": { + "object": "list", + "data": [ + { + "id": "si_Q1n45g1Ifcluuu", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1714594277, + "discounts": [], + "metadata": {}, + "plan": { + "id": "price_1OrmlvEYXaQnncShNahrpKvA", + "object": "plan", + "active": true, + "created": 1709840311, + "metadata": { + "group_name": "subscribers", + "trial_period_days": "0" + }, + "nickname": "EA1", + "product": "prod_PhB6IpGhEX14Hi" + }, + "price": { + "id": "price_1OrmlvEYXaQnncShNahrpKvA", + "object": "price", + "metadata": { + "group_name": "subscribers", + "trial_period_days": "0" + }, + "nickname": "EA1", + "product": "prod_PhB6IpGhEX14Hi" + }, + "quantity": 1, + "subscription": "sub_1PBjUnEYXaQnncShE7USquGd", + "tax_rates": [] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_1PBjUnEYXaQnncShE7USquGd" + }, + "latest_invoice": "in_1PBjUnEYXaQnncSh5c7HZ2jG", + "metadata": { "user_id": "108", "username": "f79fc8fde" }, + "plan": { + "id": "price_1OrmlvEYXaQnncShNahrpKvA", + "object": "plan", + "active": true, + "metadata": { "group_name": "subscribers", "trial_period_days": "0" }, + "meter": null, + "nickname": "EA1", + "product": { + "id": "prod_PhB6IpGhEX14Hi", + "object": "product", + "metadata": { + "description": "Sign up and get access to an exclusive group of enthusiasts just like you!" + }, + "name": "Exclusive Access" + } + }, + "quantity": 1, + "schedule": null, + "start_date": 1714594277, + "status": "active" + }, + { + "id": "sub_32b", + "object": "subscription", + "created": 1714594277, + "current_period_end": 1717272677, + "current_period_start": 1714594277, + "customer": "cus_Q1n43We0YFjnlc", + "items": { + "object": "list", + "data": [ + { + "id": "si_Q1n45g1Ifcluuu", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1714594277, + "discounts": [], + "metadata": {}, + "plan": { + "id": "price_1OrmlvEYXaQnncShNahrpKvA", + "object": "plan", + "active": true, + "created": 1709840311, + "metadata": { + "group_name": "subscribers", + "trial_period_days": "0" + }, + "nickname": "EA1", + "product": "prod_PhB6IpGhEX14Hi" + }, + "price": { + "id": "price_1OrmlvEYXaQnncShNahrpKvA", + "object": "price", + "metadata": { + "group_name": "subscribers", + "trial_period_days": "0" + }, + "nickname": "EA1", + "product": "prod_PhB6IpGhEX14Hi" + }, + "quantity": 1, + "subscription": "sub_1PBjUnEYXaQnncShE7USquGd", + "tax_rates": [] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_1PBjUnEYXaQnncShE7USquGd" + }, + "latest_invoice": "in_1PBjUnEYXaQnncSh5c7HZ2jG", + "metadata": { "user_id": "108", "username": "f79fc8fde" }, + "plan": { + "id": "price_1OrmlvEYXaQnncShNahrpKvA", + "object": "plan", + "active": true, + "metadata": { "group_name": "subscribers", "trial_period_days": "0" }, + "meter": null, + "nickname": "EA1", + "product": { + "id": "prod_PhB6IpGhEX14Hi", + "object": "product", + "metadata": { + "description": "Sign up and get access to an exclusive group of enthusiasts just like you!" + }, + "name": "Exclusive Access" + } + }, + "quantity": 1, + "schedule": null, + "start_date": 1714594277, + "status": "canceled" + } + ], + "length": 2, + "last_record": "sub_1P9aohEYXaQnncSh4wf1wzuL" +} \ No newline at end of file diff --git a/spec/requests/admin/subscriptions_controller_spec.rb b/spec/requests/admin/subscriptions_controller_spec.rb index bb47de4..b39e3df 100644 --- a/spec/requests/admin/subscriptions_controller_spec.rb +++ b/spec/requests/admin/subscriptions_controller_spec.rb @@ -48,7 +48,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do it "gets the subscriptions and products" do ::Stripe::Subscription .expects(:list) - .with(expand: ["data.plan.product"], limit: 10, starting_after: nil) + .with(expand: ["data.plan.product"], limit: 10, starting_after: nil, status: "all") .returns(has_more: false, data: [{ id: "sub_12345" }, { id: "sub_nope" }]) get "/s/admin/subscriptions.json" subscriptions = response.parsed_body["data"][0]["id"] @@ -60,7 +60,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do it "handles starting at a different point in the set" do ::Stripe::Subscription .expects(:list) - .with(expand: ["data.plan.product"], limit: 10, starting_after: "sub_nope") + .with(expand: ["data.plan.product"], limit: 10, starting_after: "sub_nope", status: "all") .returns(has_more: false, data: [{ id: "sub_77777" }, { id: "sub_yepnoep" }]) get "/s/admin/subscriptions.json", params: { last_record: "sub_nope" } subscriptions = response.parsed_body["data"][0]["id"] diff --git a/spec/requests/hooks_controller_spec.rb b/spec/requests/hooks_controller_spec.rb index fd6a3b3..e41e55e 100644 --- a/spec/requests/hooks_controller_spec.rb +++ b/spec/requests/hooks_controller_spec.rb @@ -27,6 +27,9 @@ RSpec.describe DiscourseSubscriptions::HooksController do let(:customer) do Fabricate(:customer, customer_id: "c_575768", product_id: "p_8654", user_id: user.id) end + let!(:subscription) do + Fabricate(:subscription, external_id: "sub_12345", customer_id: customer.id, status: nil) + end let(:group) { Fabricate(:group, name: "subscribers-group") } let(:event_data) do @@ -43,6 +46,22 @@ RSpec.describe DiscourseSubscriptions::HooksController do } end + let(:customer_subscription_deleted_data) do + { + object: { + id: subscription.external_id, + customer: customer.customer_id, + plan: { + product: customer.product_id, + metadata: { + group_name: group.name, + }, + }, + status: "canceled", + }, + } + end + let(:checkout_session_completed_data) do { object: { @@ -217,7 +236,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do describe "customer.subscription.deleted" do before do - event = { type: "customer.subscription.deleted", data: event_data } + event = { type: "customer.subscription.deleted", data: customer_subscription_deleted_data } ::Stripe::Webhook.stubs(:construct_event).returns(event) @@ -225,7 +244,9 @@ RSpec.describe DiscourseSubscriptions::HooksController do end it "deletes the customer" do - expect { post "/s/hooks.json" }.to change { DiscourseSubscriptions::Customer.count }.by(-1) + expect { post "/s/hooks.json" }.to change { + DiscourseSubscriptions::Subscription.where(status: "canceled").count + }.by(+1) expect(response.status).to eq 200 end diff --git a/spec/requests/subscribe_controller_spec.rb b/spec/requests/subscribe_controller_spec.rb index 67a93f4..bac3dd0 100644 --- a/spec/requests/subscribe_controller_spec.rb +++ b/spec/requests/subscribe_controller_spec.rb @@ -69,6 +69,10 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do end describe "#index" do + let(:customer) do + Fabricate(:customer, product_id: product[:id], user_id: user.id, customer_id: "x") + end + it "gets products" do ::Stripe::Product .expects(:list) @@ -94,7 +98,8 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do end it "is subscribed" do - Fabricate(:customer, product_id: product[:id], user_id: user.id, customer_id: "x") + Fabricate(:subscription, external_id: "sub_12345", customer_id: customer.id, status: nil) + ::Stripe::Product .expects(:list) .with({ ids: product_ids, active: true }) diff --git a/spec/requests/user/subscriptions_controller_spec.rb b/spec/requests/user/subscriptions_controller_spec.rb index e00f74d..bb707d0 100644 --- a/spec/requests/user/subscriptions_controller_spec.rb +++ b/spec/requests/user/subscriptions_controller_spec.rb @@ -37,62 +37,48 @@ RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do before do sign_in(user) - Fabricate(:subscription, customer_id: customer.id, external_id: "sub_1234") + Fabricate(:subscription, customer_id: customer.id, external_id: "sub_10z") end describe "index" do - let(:plans) do - { - data: [ - { id: "plan_1", product: { name: "ACME Subscriptions" } }, - { id: "plan_2", product: { name: "ACME Other Subscriptions" } }, - ], - } - end - - let(:customers) do - { - data: [ - { - id: "cus_23456", - subscriptions: { - data: [ - { id: "sub_1234", items: { data: [price: { id: "plan_1" }] } }, - { id: "sub_4567", items: { data: [price: { id: "plan_2" }] } }, - ], - }, - }, - ], - } - end + plans_json = + File.read( + Rails.root.join( + "plugins", + "discourse-subscriptions", + "spec", + "fixtures", + "json", + "stripe-price-list.json", + ), + ) it "gets subscriptions" do - ::Stripe::Price.expects(:list).with(expand: ["data.product"], limit: 100).returns(plans) + ::Stripe::Price.stubs(:list).returns(JSON.parse(plans_json, symbolize_names: true)) - ::Stripe::Customer - .expects(:list) - .with(email: user.email, expand: ["data.subscriptions"]) - .returns(customers) + subscriptions_json = + File.read( + Rails.root.join( + "plugins", + "discourse-subscriptions", + "spec", + "fixtures", + "json", + "stripe-subscription-list.json", + ), + ) + + ::Stripe::Subscription.stubs(:list).returns( + JSON.parse(subscriptions_json, symbolize_names: true), + ) get "/s/user/subscriptions.json" - subscription = response.parsed_body.first + subscription = JSON.parse(response.body, symbolize_names: true).first - expect(subscription).to eq( - "id" => "sub_1234", - "items" => { - "data" => [{ "price" => { "id" => "plan_1" } }], - }, - "plan" => { - "id" => "plan_1", - "product" => { - "name" => "ACME Subscriptions", - }, - }, - "product" => { - "name" => "ACME Subscriptions", - }, - ) + expect(subscription[:id]).to eq("sub_10z") + expect(subscription[:items][:data][0][:plan][:id]).to eq("price_1OrmlvEYXaQnncShNahrpKvA") + expect(subscription[:product][:name]).to eq("Exclusive Access") end end @@ -100,7 +86,7 @@ RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do it "updates the payment method for subscription" do ::Stripe::Subscription.expects(:update).once ::Stripe::PaymentMethod.expects(:attach).once - put "/s/user/subscriptions/sub_1234.json", params: { payment_method: "pm_abc123abc" } + put "/s/user/subscriptions/sub_10z.json", params: { payment_method: "pm_abc123abc" } end end end diff --git a/spec/system/page_objects/admin_subscription_subscription.rb b/spec/system/page_objects/admin_subscription_subscription.rb new file mode 100644 index 0000000..0900d85 --- /dev/null +++ b/spec/system/page_objects/admin_subscription_subscription.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module PageObjects + module Pages + class AdminSubscriptionSubscription < PageObjects::Pages::Base + SUBSCRIPTIONS_TABLE_SELECTOR = "table.discourse-patrons-table" + + def visit_subscriptions + visit("/admin/plugins/discourse-subscriptions/subscriptions") + self + end + + def has_subscription?(id) + has_css?("#{SUBSCRIPTIONS_TABLE_SELECTOR} tr", text: id) + self + end + + def subscription_row(id) + find("#{SUBSCRIPTIONS_TABLE_SELECTOR} tr", text: id) + end + + def has_number_of_subscriptions?(count) + has_css?("#{SUBSCRIPTIONS_TABLE_SELECTOR} tr", count:) + self + end + + def click_cancel_nth_row(row) + find("#{SUBSCRIPTIONS_TABLE_SELECTOR} tr:nth-child(#{row}) button.btn-danger").click() + end + end + end +end diff --git a/spec/system/page_objects/user_billing_subscription.rb b/spec/system/page_objects/user_billing_subscription.rb new file mode 100644 index 0000000..89ce4eb --- /dev/null +++ b/spec/system/page_objects/user_billing_subscription.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module PageObjects + module Pages + class UserBillingSubscription < PageObjects::Pages::Base + SUBSCRIPTIONS_TABLE_SELECTOR = "table.discourse-subscriptions-user-table" + + def visit_subscriptions + visit("/my/billing/subscriptions") + self + end + + def has_subscription?(id) + has_css?("#{SUBSCRIPTIONS_TABLE_SELECTOR} tr", text: id) + self + end + + def subscription_row(id) + find("#{SUBSCRIPTIONS_TABLE_SELECTOR} tr", text: id) + end + + def has_number_of_subscriptions?(count) + has_css?("#{SUBSCRIPTIONS_TABLE_SELECTOR} tr", count:) + self + end + + def click_cancel_nth_row(row) + find("#{SUBSCRIPTIONS_TABLE_SELECTOR} tr:nth-child(#{row}) button.btn-danger").click() + end + end + end +end diff --git a/spec/system/pricing_table_spec.rb b/spec/system/pricing_table_spec.rb index 1e2b34a..02241ae 100644 --- a/spec/system/pricing_table_spec.rb +++ b/spec/system/pricing_table_spec.rb @@ -67,14 +67,4 @@ RSpec.describe "Pricing Table", type: :system, js: true do text: "There are currently no products available.", ) end - - # Commenting out for now, not sure how to stub network reqeusts made in the browser to stripe - # it "Shows a pricing table when setup" do - # SiteSetting.discourse_subscriptions_pricing_table = '{"insert-pricing-table-embed-code"}' - - # visit("/") - # find("li.nav-item_subscribe a").click - - # expect(page).to have_selector('stripe-pricing-table') - # end end diff --git a/spec/system/subscription_subscription_spec.rb b/spec/system/subscription_subscription_spec.rb new file mode 100644 index 0000000..0ed380a --- /dev/null +++ b/spec/system/subscription_subscription_spec.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +describe "Subscription products", type: :system do + fab!(:admin) + fab!(:user) + fab!(:product) { Fabricate(:product, external_id: "prod_OiK") } + fab!(:customer) do + Fabricate(:customer, customer_id: "cus_Q1n", product_id: product.external_id, user_id: user.id) + end + fab!(:subscription) do + Fabricate(:subscription, customer_id: customer.id, external_id: "sub_10z", status: "active") + end + fab!(:subscription) do + Fabricate(:subscription, customer_id: customer.id, external_id: "sub_32b", status: "canceled") + end + let(:dialog) { PageObjects::Components::Dialog.new } + let(:product_subscriptions_page) { PageObjects::Pages::AdminSubscriptionProduct.new } + let(:admin_subscriptions_page) { PageObjects::Pages::AdminSubscriptionSubscription.new } + let(:user_billing_subscriptions_page) { PageObjects::Pages::UserBillingSubscription.new } + + before do + SiteSetting.discourse_subscriptions_enabled = true + + SiteSetting.discourse_subscriptions_secret_key = "sk_test_51xuu" + SiteSetting.discourse_subscriptions_public_key = "pk_test_51xuu" + + # # this needs to be stubbed or it will try to make a request to stripe + one_product = { + id: "prod_OiK", + active: true, + name: "Tomtom", + metadata: { + description: "Photos of tomtom", + repurchaseable: true, + }, + } + + plans_json = + File.read( + Rails.root.join( + "plugins", + "discourse-subscriptions", + "spec", + "fixtures", + "json", + "stripe-price-list.json", + ), + ) + + subscriptions_json = + File.read( + Rails.root.join( + "plugins", + "discourse-subscriptions", + "spec", + "fixtures", + "json", + "stripe-subscription-list.json", + ), + ) + + ::Stripe::Product.stubs(:list).returns({ data: [one_product] }) + ::Stripe::Product.stubs(:delete).returns({ id: "prod_OiK" }) + ::Stripe::Product.stubs(:retrieve).returns(one_product) + ::Stripe::Price.stubs(:list).returns(JSON.parse(plans_json, symbolize_names: true)) + ::Stripe::Subscription.stubs(:list).returns( + JSON.parse(subscriptions_json, symbolize_names: true), + ) + end + + it "shows active and canceled subscriptions for admins" do + sign_in(admin) + + active_subscription_row = + admin_subscriptions_page.visit_subscriptions.subscription_row("sub_10z") + expect(active_subscription_row).to have_text("active") + canceled_subscription_row = + admin_subscriptions_page.visit_subscriptions.subscription_row("sub_32b") + expect(canceled_subscription_row).to have_text("canceled") + end + + it "shows active and canceled subscriptions for users" do + sign_in(user) + + active_subscription_row = + user_billing_subscriptions_page.visit_subscriptions.subscription_row("sub_10z") + expect(active_subscription_row).to have_text("active") + canceled_subscription_row = + user_billing_subscriptions_page.visit_subscriptions.subscription_row("sub_32b") + expect(canceled_subscription_row).to have_text("canceled") + end +end