Files
discourse-subscriptions/spec/requests/hooks_controller_spec.rb
T
Blake Erickson a2c70deeff FIX: Create customer for one off pricing table purchases (#232)
When using the Stripe Pricing Table for one-off purchases
(non-subscription) stripe doesn't automatically create a customer
record. This was causing the pricing table webhook
endpoint to end prematurely and not add users to their appropriate
group after purchase. Now if we detect that there is no customer record
we will make an api call to Stripe to create one.
2024-08-28 11:27:55 -06:00

344 lines
10 KiB
Ruby

# frozen_string_literal: true
require "rails_helper"
RSpec.describe DiscourseSubscriptions::HooksController do
before do
SiteSetting.discourse_subscriptions_webhook_secret = "zascharoo"
SiteSetting.discourse_subscriptions_enabled = true
end
it "constructs a webhook event" do
payload = "we-want-a-shrubbery"
headers = { HTTP_STRIPE_SIGNATURE: "stripe-webhook-signature" }
::Stripe::Webhook
.expects(:construct_event)
.with("we-want-a-shrubbery", "stripe-webhook-signature", "zascharoo")
.returns(type: "something")
post "/s/hooks.json", params: payload, headers: headers
expect(response.status).to eq 200
end
describe "event types" do
let(:user) { Fabricate(:user) }
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
{
object: {
customer: customer.customer_id,
plan: {
product: customer.product_id,
metadata: {
group_name: group.name,
},
},
},
}
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: {
id: "cs_test_a1ENei5A9TGOaEketyV5qweiQR5CyJWHT5j8T3HheQY3uah3RxzKttVUKZ",
object: "checkout.session",
customer: customer.customer_id,
customer_email: user.email,
invoice: "in_1P9b7iEYXaQnncSh81AQtuHD",
metadata: {
},
mode: "subscription",
payment_status: "paid",
status: "complete",
submit_type: nil,
subscription: "sub_1P9b7iEYXaQnncSh3H3G9d2Y",
success_url: "http://localhost:4200/my/billing/subscriptions",
url: nil,
},
}
end
let(:checkout_session_completed_data_one_off) do
{
object: {
id: "cs_test_a1ENei5A9TGOaEketyV5qweiQR5CyJWHT5j8T3HheQY3uah3RxzKttVUKZ",
object: "checkout.session",
customer: nil,
customer_email: user.email,
invoice: nil,
metadata: {
},
mode: "subscription",
payment_status: "paid",
status: "complete",
submit_type: nil,
subscription: nil,
success_url: "http://localhost:4200/my/billing/subscriptions",
url: nil,
},
}
end
let(:checkout_session_completed_bad_data) do
{
object: {
id: "cs_test_a1ENei5A9TGOaEketyV5qweiQR5CyJWHT5j8T3HheQY3uah3RxzKttVUKZ",
object: "checkout.session",
customer: nil,
customer_email: nil,
invoice: "in_1P9b7iEYXaQnncSh81AQtuHD",
metadata: {
},
mode: "subscription",
payment_status: "paid",
status: "complete",
submit_type: nil,
subscription: nil,
success_url: "http://localhost:4200/my/billing/subscriptions",
url: nil,
},
}
end
let(:list_line_items_data) do
{
data: [
{
id: "li_1P9YlFEYXaQnncShFBl7r0na",
object: "item",
description: "Exclusive Access",
price: {
id: "price_1OrmlvEYXaQnncShNahrpKvA",
metadata: {
group_name: group.name,
trial_period_days: "0",
},
nickname: "EA1",
product: "prod_PhB6IpGhEX14Hi",
},
},
],
}
end
describe "checkout.session.completed" do
before do
event = { type: "checkout.session.completed", data: checkout_session_completed_data }
::Stripe::Checkout::Session
.stubs(:list_line_items)
.with(checkout_session_completed_data[:object][:id], { limit: 1 })
.returns(list_line_items_data)
::Stripe::Subscription
.stubs(:update)
.with(
checkout_session_completed_data[:object][:subscription],
{ metadata: { user_id: user.id, username: user.username } },
)
.returns(
{
id: checkout_session_completed_data[:object][:subscription],
object: "subscription",
metadata: {
user_id: user.id.to_s,
username: user.username,
},
},
)
::Stripe::Webhook.stubs(:construct_event).returns(event)
end
it "is successfull" do
post "/s/hooks.json"
expect(response.status).to eq 200
end
describe "completing the subscription" do
it "adds the user to the group when completing the transaction" do
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(1)
expect(response.status).to eq 200
end
end
end
describe "checkout.session.completed with bad data" do
before do
event = { type: "checkout.session.completed", data: checkout_session_completed_bad_data }
::Stripe::Checkout::Session
.stubs(:list_line_items)
.with(checkout_session_completed_data[:object][:id], { limit: 1 })
.returns(list_line_items_data)
::Stripe::Webhook.stubs(:construct_event).returns(event)
::Stripe::Customer.stubs(:create).returns(id: "cus_1234")
end
it "is returns 422" do
post "/s/hooks.json"
expect(response.status).to eq 422
end
end
describe "checkout.session.completed for one-off purchase" do
before do
event = {
type: "checkout.session.completed",
data: checkout_session_completed_data_one_off,
}
::Stripe::Checkout::Session
.stubs(:list_line_items)
.with(checkout_session_completed_data[:object][:id], { limit: 1 })
.returns(list_line_items_data)
::Stripe::Webhook.stubs(:construct_event).returns(event)
::Stripe::Customer.stubs(:create).returns(id: "cus_1234")
end
it "is returns 200" do
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(1)
expect(response.status).to eq 200
end
end
describe "checkout.session.completed with anonymous user" do
before do
checkout_session_completed_bad_data[:object][:customer_email] = "[email protected]"
data = checkout_session_completed_bad_data
event = { type: "checkout.session.completed", data: data }
::Stripe::Checkout::Session
.stubs(:list_line_items)
.with(checkout_session_completed_data[:object][:id], { limit: 1 })
.returns(list_line_items_data)
::Stripe::Webhook.stubs(:construct_event).returns(event)
::Stripe::Customer.stubs(:create).returns(id: "cus_1234")
end
it "is returns 422" do
post "/s/hooks.json"
expect(response.status).to eq 422
end
end
describe "checkout.session.completed with no customer email" do
before do
checkout_session_completed_bad_data[:object][:customer_email] = nil
data = checkout_session_completed_bad_data
event = { type: "checkout.session.completed", data: data }
::Stripe::Checkout::Session
.stubs(:list_line_items)
.with(checkout_session_completed_data[:object][:id], { limit: 1 })
.returns(list_line_items_data)
::Stripe::Webhook.stubs(:construct_event).returns(event)
end
it "is returns 422" do
post "/s/hooks.json"
expect(response.status).to eq 422
end
end
describe "customer.subscription.updated" do
before do
event = { type: "customer.subscription.updated", data: event_data }
::Stripe::Webhook.stubs(:construct_event).returns(event)
end
it "is successfull" do
post "/s/hooks.json"
expect(response.status).to eq 200
end
describe "completing the subscription" do
it "does not add the user to the group" do
event_data[:object][:status] = "incomplete"
event_data[:previous_attributes] = { status: "incomplete" }
expect { post "/s/hooks.json" }.not_to change { user.groups.count }
expect(response.status).to eq 200
end
it "does not add the user to the group" do
event_data[:object][:status] = "incomplete"
event_data[:previous_attributes] = { status: "something-else" }
expect { post "/s/hooks.json" }.not_to change { user.groups.count }
expect(response.status).to eq 200
end
it "adds the user to the group when completing the transaction" do
event_data[:object][:status] = "complete"
event_data[:previous_attributes] = { status: "incomplete" }
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(1)
expect(response.status).to eq 200
end
it "adds the user to the group when status is active" do
event_data[:object][:status] = "active"
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(1)
expect(response.status).to eq 200
end
end
end
describe "customer.subscription.deleted" do
before do
event = { type: "customer.subscription.deleted", data: customer_subscription_deleted_data }
::Stripe::Webhook.stubs(:construct_event).returns(event)
group.add(user)
end
it "deletes the customer" do
expect { post "/s/hooks.json" }.to change {
DiscourseSubscriptions::Subscription.where(status: "canceled").count
}.by(+1)
expect(response.status).to eq 200
end
it "removes the user from the group" do
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(-1)
expect(response.status).to eq 200
end
end
end
end