0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-09 21:45:25 +08:00
discourse/plugins/discourse-subscriptions/spec/requests/subscribe_controller_spec.rb
Isaac Janzen ac2074474f
SECURITY: Subscription contributors expose full user profile fields to anonymous viewers (#40891)
## Summary

Correctly enforce profile visibility restrictions in the subscriptions
contributors endpoint and user serializers. This prevents the exposure
of sensitive profile fields—including bio, location, and website—to
anonymous viewers when public profiles are disabled via site settings.
The fix also hardens the user and user card serializers to omit profile
details for unauthorized scopes as a defense-in-depth measure.

## Source

- Patch Triage: https://patch.discourse.org/patch-triage/1286

Co-authored-by: discourse-patch-triage
<272280883+discourse-patch-triage[bot]@users.noreply.github.com>
2026-06-15 10:24:06 -05:00

924 lines
31 KiB
Ruby
Vendored

# frozen_string_literal: true
RSpec.describe DiscourseSubscriptions::SubscribeController do
let(:user) { Fabricate(:user) }
let(:campaign_user) { Fabricate(:user) }
before do
SiteSetting.discourse_subscriptions_enabled = true
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
end
context "when 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"
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)
.with({ ids: product_ids, active: true }, DiscourseSubscriptions::Stripe.request_opts)
.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(:subscription, external_id: "sub_12345", customer_id: customer.id, status: nil)
::Stripe::Product
.expects(:list)
.with({ ids: product_ids, active: true }, DiscourseSubscriptions::Stripe.request_opts)
.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 }, DiscourseSubscriptions::Stripe.request_opts)
.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")
user.user_stat.update!(post_count: 1)
campaign_user.user_stat.update!(post_count: 1)
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 "when 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 "when showing contributors" do
before { SiteSetting.discourse_subscriptions_campaign_show_contributors = true }
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 = ""
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
Fabricate(:product, external_id: "prod_walterwhite")
::Stripe::Product
.expects(:retrieve)
.with("prod_walterwhite", DiscourseSubscriptions::Stripe.request_opts)
.returns(product)
::Stripe::Price
.expects(:list)
.with(
{ active: true, product: "prod_walterwhite" },
DiscourseSubscriptions::Stripe.request_opts,
)
.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
it "returns 404 for a product outside the allowlist" do
::Stripe::Product.expects(:retrieve).never
::Stripe::Price.expects(:list).never
get "/s/prod_hidden.json"
expect(response.status).to eq(404)
end
end
end
describe "#contributors" do
fab!(:contributor, :user)
fab!(:hidden_contributor, :user)
before do
SiteSetting.discourse_subscriptions_campaign_show_contributors = true
SiteSetting.discourse_subscriptions_campaign_product = ""
SiteSetting.hide_user_profiles_from_public = false
SiteSetting.allow_users_to_hide_profile = true
contributor.user_stat.update!(post_count: 1)
hidden_contributor.user_stat.update!(post_count: 1)
hidden_contributor.user_option.update!(hide_profile: true)
Fabricate(:customer, product_id: "prodct_23456", user_id: contributor.id, customer_id: "x")
Fabricate(
:customer,
product_id: "prod_campaign",
user_id: hidden_contributor.id,
customer_id: "y",
)
end
it "enforces profile visibility for anonymous contributors" do
get "/s/contributors.json"
expect(response).to have_http_status(:ok)
visible_contributor_ids = response.parsed_body.map { |serialized_user| serialized_user["id"] }
SiteSetting.hide_user_profiles_from_public = true
get "/s/contributors.json"
expect(visible_contributor_ids).to contain_exactly(contributor.id)
expect(response).to have_http_status(:forbidden)
expect(response.parsed_body).to include("error_type" => "invalid_access")
end
end
context "when creating subscriptions" do
context "when 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 "when authenticated" do
fab!(:published_product) { Fabricate(:product, external_id: "product_12345") }
before { sign_in(user) }
describe "#create" do
before do
::Stripe::Customer
.stubs(:create)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "cus_1234")
end
it "creates a subscription without automatic_tax param" do
SiteSetting.discourse_subscriptions_enable_automatic_tax = false
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "recurring",
product: "product_12345",
metadata: {
group_name: "awesome",
trial_period_days: 0,
},
)
expected_subscription_params = {
customer: "cus_1234",
items: [{ price: "plan_1234" }],
metadata: {
user_id: user.id,
username: user.username_lower,
},
trial_period_days: 0,
promotion_code: nil,
}
::Stripe::Subscription
.expects(:create)
.with do |params, opts|
params == expected_subscription_params && !params.key?(:automatic_tax) &&
opts == DiscourseSubscriptions::Stripe.request_opts
end
.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 subscription with automatic tax" do
SiteSetting.discourse_subscriptions_enable_automatic_tax = true
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "recurring",
product: "product_12345",
metadata: {
group_name: "awesome",
trial_period_days: 0,
},
)
expected_subscription_params = {
customer: "cus_1234",
items: [{ price: "plan_1234" }],
metadata: {
user_id: user.id,
username: user.username_lower,
},
trial_period_days: 0,
promotion_code: nil,
automatic_tax: {
enabled: true,
},
}
::Stripe::Subscription
.expects(:create)
.with(expected_subscription_params, DiscourseSubscriptions::Stripe.request_opts)
.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 "rejects a plan outside the allowlist" do
::Stripe::Price
.expects(:retrieve)
.with("price_hidden", DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "recurring",
product: "prod_hidden",
metadata: {
group_name: "awesome",
trial_period_days: 0,
},
)
::Stripe::Customer.expects(:create).never
::Stripe::Subscription.expects(:create).never
expect {
post "/s/create.json", params: { plan: "price_hidden", source: "tok_1234" }
}.not_to change { DiscourseSubscriptions::Customer.count }
expect(response.status).to eq(404)
end
it "returns 422 on a one time payment subscription error" do
# It's possible that the invoice item doesn't get attached
# to the invoice. This means the invoice is paid, but for $0.00 with
# a pending invoice item.
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "one_time",
product: "product_12345",
metadata: {
group_name: "awesome",
},
)
::Stripe::InvoiceItem.expects(:create).with(
anything,
DiscourseSubscriptions::Stripe.request_opts,
)
::Stripe::Invoice
.expects(:create)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(status: "open", id: "in_123")
::Stripe::Invoice
.expects(:finalize_invoice)
.with(anything, anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "in_123", status: "paid", payment_intent: "pi_123")
expect {
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
}.not_to change { DiscourseSubscriptions::Customer.count }
expect(response.status).to eq 422
end
it "creates a one time payment subscription without automatic tax" do
SiteSetting.discourse_subscriptions_enable_automatic_tax = false
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "one_time",
product: "product_12345",
metadata: {
group_name: "awesome",
},
)
::Stripe::InvoiceItem.expects(:create).with(
anything,
DiscourseSubscriptions::Stripe.request_opts,
)
expected_one_time_params = { customer: "cus_1234" }
::Stripe::Invoice
.expects(:create)
.with do |params, opts|
params == expected_one_time_params && !params.key?(:automatic_tax) &&
opts == DiscourseSubscriptions::Stripe.request_opts
end
.returns(status: "open", id: "in_123")
::Stripe::Invoice
.expects(:finalize_invoice)
.with(anything, anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "in_123", status: "open", payment_intent: "pi_123")
::Stripe::Invoice
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "in_123", status: "open", payment_intent: "pi_123")
::Stripe::PaymentIntent
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(status: "successful")
::Stripe::Invoice
.expects(:pay)
.with(anything, anything, DiscourseSubscriptions::Stripe.request_opts)
.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 one time payment subscription" do
SiteSetting.discourse_subscriptions_enable_automatic_tax = true
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "one_time",
product: "product_12345",
metadata: {
group_name: "awesome",
},
)
::Stripe::InvoiceItem.expects(:create).with(
anything,
DiscourseSubscriptions::Stripe.request_opts,
)
expected_one_time_params = { customer: "cus_1234", automatic_tax: { enabled: true } }
::Stripe::Invoice
.expects(:create)
.with(expected_one_time_params, DiscourseSubscriptions::Stripe.request_opts)
.returns(status: "open", id: "in_123")
::Stripe::Invoice
.expects(:finalize_invoice)
.with(anything, anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "in_123", status: "open", payment_intent: "pi_123")
::Stripe::Invoice
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "in_123", status: "open", payment_intent: "pi_123")
::Stripe::PaymentIntent
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(status: "successful")
::Stripe::Invoice
.expects(:pay)
.with(anything, anything, DiscourseSubscriptions::Stripe.request_opts)
.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)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(type: "recurring", product: "product_12345", metadata: {})
.twice
::Stripe::Subscription
.expects(:create)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.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",
DiscourseSubscriptions::Stripe.request_opts,
)
expect {
post "/s/create.json", params: { plan: "plan_5678", source: "tok_5678" }
}.not_to change { DiscourseSubscriptions::Customer.count }
end
context "with customer name & address" do
it "creates a customer & subscription when a customer address is provided" do
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(type: "recurring", product: "product_12345", metadata: {})
::Stripe::Subscription
.expects(:create)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(status: "active", customer: "cus_1234")
expect {
post "/s/create.json",
params: {
plan: "plan_1234",
source: "tok_1234",
cardholder_name: "A. Customer",
cardholder_address: {
line1: "123 Main Street",
city: "Anywhere",
state: "VT",
country: "US",
postal_code: "12345",
},
}
}.to change { DiscourseSubscriptions::Customer.count }
end
end
context "with promo code" do
context "with invalid code" do
it "prevents use of invalid coupon codes" do
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "recurring",
product: "product_12345",
metadata: {
group_name: "awesome",
trial_period_days: 0,
},
)
::Stripe::PromotionCode
.expects(:list)
.with({ code: "invalid" }, DiscourseSubscriptions::Stripe.request_opts)
.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 "with valid code" do
before do
::Stripe::PromotionCode
.expects(:list)
.with({ code: "123" }, DiscourseSubscriptions::Stripe.request_opts)
.returns(data: [{ id: "promo123", coupon: { id: "c123" } }])
end
it "applies promo code to recurring subscription" do
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "recurring",
product: "product_12345",
metadata: {
group_name: "awesome",
trial_period_days: 0,
},
)
expected_subscription_params = {
customer: "cus_1234",
items: [price: "plan_1234"],
metadata: {
user_id: user.id,
username: user.username_lower,
},
trial_period_days: 0,
promotion_code: "promo123",
}
::Stripe::Subscription
.expects(:create)
.with(expected_subscription_params, DiscourseSubscriptions::Stripe.request_opts)
.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)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "one_time",
product: "product_12345",
metadata: {
group_name: "awesome",
},
)
::Stripe::Invoice
.expects(:create)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(status: "open", id: "in_123")
::Stripe::InvoiceItem.expects(:create).with(
{
customer: "cus_1234",
price: "plan_1234",
discounts: [{ coupon: "c123" }],
invoice: "in_123",
},
DiscourseSubscriptions::Stripe.request_opts,
)
::Stripe::Invoice
.expects(:finalize_invoice)
.with(anything, anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "in_123", status: "open", payment_intent: "pi_123")
::Stripe::Invoice
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "in_123", status: "open", payment_intent: "pi_123")
::Stripe::PaymentIntent
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(status: "successful")
::Stripe::Invoice
.expects(:pay)
.with(anything, anything, DiscourseSubscriptions::Stripe.request_opts)
.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
server_session["pending_subscription"] = {
transaction_id: "sub_1234",
plan_id: "plan_1234",
}
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "plan_1234", product: "product_12345", metadata: {})
::Stripe::Subscription
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "sub_123", customer: "cus_1234", status: "active")
expect { post "/s/finalize.json" }.to change { DiscourseSubscriptions::Customer.count }
end
end
context "with one-time payment" do
it "finalizes the one-time payment" do
server_session["pending_subscription"] = {
transaction_id: "in_1234",
plan_id: "plan_1234",
}
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "plan_1234", product: "product_12345", metadata: {})
::Stripe::Invoice
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "in_123", customer: "cus_1234", status: "paid")
expect { post "/s/finalize.json" }.to change { DiscourseSubscriptions::Customer.count }
end
end
it "returns 403 with no pending server session" do
post "/s/finalize.json"
expect(response.status).to eq(403)
end
it "prevents replay by rejecting a second finalize" do
server_session["pending_subscription"] = {
transaction_id: "sub_123",
plan_id: "plan_1234",
}
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "plan_1234", product: "product_12345", metadata: {})
::Stripe::Subscription
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "sub_123", customer: "cus_1234", status: "active")
post "/s/finalize.json"
expect(response.status).to eq(200)
post "/s/finalize.json"
expect(response.status).to eq(403)
end
it "rejects a pending plan outside the allowlist" do
server_session["pending_subscription"] = {
transaction_id: "sub_123",
plan_id: "price_hidden",
}
::Stripe::Price
.expects(:retrieve)
.with("price_hidden", DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "price_hidden", product: "prod_hidden", metadata: {})
::Stripe::Subscription.expects(:retrieve).never
expect { post "/s/finalize.json" }.not_to change {
DiscourseSubscriptions::Customer.count
}
expect(response.status).to eq(404)
end
end
describe "user groups" do
let(:group_name) { "group-123" }
let(:group) { Fabricate(:group, name: group_name) }
context "with unauthorized group" do
before do
::Stripe::Customer
.expects(:create)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "cus_1234")
::Stripe::Subscription
.expects(:create)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(status: "active")
end
it "does not add the user to the admins group" do
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "recurring",
product: "product_12345",
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)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "recurring",
product: "product_12345",
metadata: {
group_name: "other",
},
)
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
expect(user.groups).to be_empty
end
end
context "when plan has group in metadata" do
before do
::Stripe::Customer
.expects(:create)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(id: "cus_1234")
::Stripe::Price
.expects(:retrieve)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.returns(
type: "recurring",
product: "product_12345",
metadata: {
group_name: group_name,
},
)
end
it "does not add the user to the group when subscription fails" do
::Stripe::Subscription
.expects(:create)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.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)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.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)
.with(anything, DiscourseSubscriptions::Stripe.request_opts)
.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