discourse-subscriptions/spec/requests/subscribe_controller_spec.rb

401 lines
15 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
module DiscourseSubscriptions
RSpec.describe SubscribeController do
let (:user) { Fabricate(:user) }
let (:campaign_user) { Fabricate(:user) }
context "showing products" do
let(:product) do
{
id: "prodct_23456",
name: "Very Special Product",
metadata: {
description: "Many people listened to my phone call with the Ukrainian President while it was being made",
repurchaseable: false
},
otherstuff: true,
}
end
let(:prices) do
{
data: [
{ id: 'plan_id123', unit_amount: 1220, currency: 'aud', recurring: { interval: 'year' }, metadata: {} },
{ id: 'plan_id234', unit_amount: 1399, currency: 'usd', recurring: { interval: 'year' }, metadata: {} },
{ id: 'plan_id678', unit_amount: 1000, currency: 'aud', recurring: { interval: 'week' }, metadata: {} }
]
}
end
let(:product_ids) { ["prodct_23456"] }
before do
sign_in(user)
Fabricate(:product, external_id: "prodct_23456")
SiteSetting.discourse_subscriptions_public_key = "public-key"
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
end
describe "#index" do
it "gets products" do
::Stripe::Product.expects(:list).with(ids: product_ids, active: true).returns(data: [product])
get "/s.json"
expect(response.parsed_body).to eq([{
"id" => "prodct_23456",
"name" => "Very Special Product",
"description" => PrettyText.cook("Many people listened to my phone call with the Ukrainian President while it was being made"),
"subscribed" => false,
"repurchaseable" => false,
}])
end
it "is subscribed" do
Fabricate(:customer, product_id: product[:id], user_id: user.id, customer_id: 'x')
::Stripe::Product.expects(:list).with(ids: product_ids, active: true).returns(data: [product])
get "/s.json"
data = response.parsed_body
expect(data.first["subscribed"]).to eq true
end
it "is not subscribed" do
::DiscourseSubscriptions::Customer.delete_all
::Stripe::Product.expects(:list).with(ids: product_ids, active: true).returns(data: [product])
get "/s.json"
data = response.parsed_body
expect(data.first["subscribed"]).to eq false
end
end
describe "#get_contributors" do
before do
Fabricate(:product, external_id: "prod_campaign")
Fabricate(:customer, product_id: "prodct_23456", user_id: user.id, customer_id: 'x')
Fabricate(:customer, product_id: "prod_campaign", user_id: campaign_user.id, customer_id: 'y')
end
context 'not showing contributors' do
it 'returns nothing if not set to show contributors' do
SiteSetting.discourse_subscriptions_campaign_show_contributors = false
get "/s/contributors.json"
data = response.parsed_body
expect(data).to be_empty
end
end
context 'showing contributors' do
before do
SiteSetting.discourse_subscriptions_campaign_show_contributors = true
end
it 'filters users by campaign product if set' do
SiteSetting.discourse_subscriptions_campaign_product = "prod_campaign"
get "/s/contributors.json"
data = response.parsed_body
expect(data.first["id"]).to eq campaign_user.id
expect(data.length).to eq 1
end
it 'shows all purchases if campaign product not set' do
SiteSetting.discourse_subscriptions_campaign_product = nil
get "/s/contributors.json"
data = response.parsed_body
expect(data.length).to eq 2
end
end
end
describe "#show" do
it 'retrieves the product' do
::Stripe::Product.expects(:retrieve).with('prod_walterwhite').returns(product)
::Stripe::Price.expects(:list).with(active: true, product: 'prod_walterwhite').returns(prices)
get "/s/prod_walterwhite.json"
expect(response.parsed_body).to eq({
"product" => {
"id" => "prodct_23456",
"name" => "Very Special Product",
"description" => PrettyText.cook("Many people listened to my phone call with the Ukrainian President while it was being made"),
"subscribed" => false,
"repurchaseable" => false
},
"plans" => [
{ "currency" => "aud", "id" => "plan_id123", "recurring" => { "interval" => "year" }, "unit_amount" => 1220 },
{ "currency" => "usd", "id" => "plan_id234", "recurring" => { "interval" => "year" }, "unit_amount" => 1399 },
{ "currency" => "aud", "id" => "plan_id678", "recurring" => { "interval" => "week" }, "unit_amount" => 1000 }
]
})
end
end
end
context "creating subscriptions" do
context "unauthenticated" do
it "does not create a subscription" do
::Stripe::Customer.expects(:create).never
::Stripe::Price.expects(:retrieve).never
::Stripe::Subscription.expects(:create).never
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
end
end
context "authenticated" do
before do
sign_in(user)
end
describe "#create" do
before do
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
end
it "creates a subscription" do
::Stripe::Price.expects(:retrieve).returns(
type: 'recurring',
product: 'product_12345',
metadata: {
group_name: 'awesome',
trial_period_days: 0
}
)
::Stripe::Subscription.expects(:create).with(
customer: 'cus_1234',
items: [ price: 'plan_1234' ],
metadata: { user_id: user.id, username: user.username_lower },
trial_period_days: 0,
promotion_code: nil
).returns(status: 'active', customer: 'cus_1234')
expect {
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
}.to change { DiscourseSubscriptions::Customer.count }
end
it "creates a one time payment subscription" do
::Stripe::Price.expects(:retrieve).returns(
type: 'one_time',
product: 'product_12345',
metadata: {
group_name: 'awesome'
}
)
::Stripe::InvoiceItem.expects(:create)
::Stripe::Invoice.expects(:create).returns(status: 'open', id: 'in_123')
::Stripe::Invoice.expects(:finalize_invoice).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
::Stripe::Invoice.expects(:retrieve).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
::Stripe::PaymentIntent.expects(:retrieve).returns(status: 'successful')
::Stripe::Invoice.expects(:pay).returns(status: 'paid', customer: 'cus_1234')
expect {
post '/s/create.json', params: { plan: 'plan_1234', source: 'tok_1234' }
}.to change { DiscourseSubscriptions::Customer.count }
end
it "creates a customer model" do
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: {}).twice
::Stripe::Subscription.expects(:create).returns(status: 'active', customer: 'cus_1234')
expect {
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
}.to change { DiscourseSubscriptions::Customer.count }
::Stripe::Customer.expects(:retrieve).with('cus_1234')
expect {
post "/s/create.json", params: { plan: 'plan_5678', source: 'tok_5678' }
}.not_to change { DiscourseSubscriptions::Customer.count }
end
context "with promo code" do
context "invalid code" do
it "prevents use of invalid coupon codes" do
::Stripe::Price.expects(:retrieve).returns(
type: 'recurring',
product: 'product_12345',
metadata: {
group_name: 'awesome',
trial_period_days: 0
}
)
::Stripe::PromotionCode.expects(:list).with({ code: 'invalid' }).returns(
data: []
)
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: 'invalid' }
data = response.parsed_body
expect(data["errors"]).not_to be_blank
end
end
context "valid code" do
before do
::Stripe::PromotionCode.expects(:list).with({ code: '123' }).returns(
data: [{
id: 'promo123',
coupon: { id: 'c123' }
}]
)
end
it "applies promo code to recurring subscription" do
::Stripe::Price.expects(:retrieve).returns(
type: 'recurring',
product: 'product_12345',
metadata: {
group_name: 'awesome',
trial_period_days: 0
}
)
::Stripe::Subscription.expects(:create).with(
customer: 'cus_1234',
items: [ price: 'plan_1234' ],
metadata: { user_id: user.id, username: user.username_lower },
trial_period_days: 0,
promotion_code: 'promo123'
).returns(status: 'active', customer: 'cus_1234')
expect {
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' }
}.to change { DiscourseSubscriptions::Customer.count }
end
it "applies promo code to one time purchase" do
::Stripe::Price.expects(:retrieve).returns(
type: 'one_time',
product: 'product_12345',
metadata: {
group_name: 'awesome'
}
)
::Stripe::InvoiceItem.expects(:create).with(customer: 'cus_1234', price: 'plan_1234', discounts: [{ coupon: 'c123' }])
::Stripe::Invoice.expects(:create).returns(status: 'open', id: 'in_123')
::Stripe::Invoice.expects(:finalize_invoice).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
::Stripe::Invoice.expects(:retrieve).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
::Stripe::PaymentIntent.expects(:retrieve).returns(status: 'successful')
::Stripe::Invoice.expects(:pay).returns(status: 'paid', customer: 'cus_1234')
expect {
post '/s/create.json', params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' }
}.to change { DiscourseSubscriptions::Customer.count }
end
end
end
end
describe "#finalize strong customer authenticated transaction" do
context "with subscription" do
it "finalizes the subscription" do
::Stripe::Price.expects(:retrieve).returns(id: "plan_1234", product: "prod_1234", metadata: {})
::Stripe::Subscription.expects(:retrieve).returns(id: "sub_123", customer: 'cus_1234', status: "active")
expect {
post "/s/finalize.json", params: { plan: 'plan_1234', transaction: 'sub_1234' }
}.to change { DiscourseSubscriptions::Customer.count }
end
end
context "with one-time payment" do
it "finalizes the one-time payment" do
::Stripe::Price.expects(:retrieve).returns(id: "plan_1234", product: "prod_1234", metadata: {})
::Stripe::Invoice.expects(:retrieve).returns(id: "in_123", customer: 'cus_1234', status: "paid")
expect {
post "/s/finalize.json", params: { plan: 'plan_1234', transaction: 'in_1234' }
}.to change { DiscourseSubscriptions::Customer.count }
end
end
end
describe "user groups" do
let(:group_name) { 'group-123' }
let(:group) { Fabricate(:group, name: group_name) }
context "unauthorized group" do
before do
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
::Stripe::Subscription.expects(:create).returns(status: 'active')
end
it "does not add the user to the admins group" do
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'admins' })
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
expect(user.admin).to eq false
end
it "does not add the user to other group" do
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'other' })
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
expect(user.groups).to be_empty
end
end
context "plan has group in metadata" do
before do
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: group_name })
end
it "does not add the user to the group when subscription fails" do
::Stripe::Subscription.expects(:create).returns(status: 'failed')
expect {
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
}.not_to change { group.users.count }
expect(user.groups).to be_empty
end
it "adds the user to the group when the subscription is active" do
::Stripe::Subscription.expects(:create).returns(status: 'active')
expect {
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
}.to change { group.users.count }
expect(user.groups).not_to be_empty
end
it "adds the user to the group when the subscription is trialing" do
::Stripe::Subscription.expects(:create).returns(status: 'trialing')
expect {
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
}.to change { group.users.count }
expect(user.groups).not_to be_empty
end
end
end
end
end
end
end