stripe-ruby-mock 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rspec_tests.yml +38 -0
  3. data/.rspec +2 -1
  4. data/CHANGELOG.md +62 -15
  5. data/Gemfile +1 -0
  6. data/README.md +5 -3
  7. data/lib/stripe_mock/api/client.rb +1 -1
  8. data/lib/stripe_mock/api/instance.rb +1 -1
  9. data/lib/stripe_mock/api/webhooks.rb +66 -25
  10. data/lib/stripe_mock/client.rb +2 -1
  11. data/lib/stripe_mock/data/list.rb +31 -6
  12. data/lib/stripe_mock/data.rb +201 -30
  13. data/lib/stripe_mock/instance.rb +12 -3
  14. data/lib/stripe_mock/request_handlers/account_links.rb +15 -0
  15. data/lib/stripe_mock/request_handlers/accounts.rb +17 -6
  16. data/lib/stripe_mock/request_handlers/charges.rb +11 -4
  17. data/lib/stripe_mock/request_handlers/checkout_session.rb +179 -0
  18. data/lib/stripe_mock/request_handlers/customers.rb +22 -13
  19. data/lib/stripe_mock/request_handlers/ephemeral_key.rb +1 -1
  20. data/lib/stripe_mock/request_handlers/events.rb +30 -3
  21. data/lib/stripe_mock/request_handlers/express_login_links.rb +15 -0
  22. data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +1 -0
  23. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +36 -12
  24. data/lib/stripe_mock/request_handlers/invoices.rb +10 -4
  25. data/lib/stripe_mock/request_handlers/payment_intents.rb +13 -2
  26. data/lib/stripe_mock/request_handlers/payment_methods.rb +11 -4
  27. data/lib/stripe_mock/request_handlers/prices.rb +62 -0
  28. data/lib/stripe_mock/request_handlers/promotion_codes.rb +43 -0
  29. data/lib/stripe_mock/request_handlers/refunds.rb +13 -2
  30. data/lib/stripe_mock/request_handlers/setup_intents.rb +16 -9
  31. data/lib/stripe_mock/request_handlers/sources.rb +12 -6
  32. data/lib/stripe_mock/request_handlers/subscriptions.rb +120 -21
  33. data/lib/stripe_mock/request_handlers/tokens.rb +6 -4
  34. data/lib/stripe_mock/request_handlers/transfers.rb +12 -1
  35. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +33 -4
  36. data/lib/stripe_mock/server.rb +2 -2
  37. data/lib/stripe_mock/test_strategies/base.rb +62 -10
  38. data/lib/stripe_mock/version.rb +1 -1
  39. data/lib/stripe_mock/webhook_fixtures/account.updated.json +1 -1
  40. data/lib/stripe_mock/webhook_fixtures/balance.available.json +27 -15
  41. data/lib/stripe_mock/webhook_fixtures/charge.captured.json +143 -0
  42. data/lib/stripe_mock/webhook_fixtures/charge.dispute.created.json +63 -16
  43. data/lib/stripe_mock/webhook_fixtures/charge.failed.json +49 -120
  44. data/lib/stripe_mock/webhook_fixtures/charge.refund.updated.json +35 -0
  45. data/lib/stripe_mock/webhook_fixtures/charge.refunded.json +145 -50
  46. data/lib/stripe_mock/webhook_fixtures/charge.succeeded.json +114 -43
  47. data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.json +79 -0
  48. data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.payment_mode.json +53 -0
  49. data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.setup_mode.json +45 -0
  50. data/lib/stripe_mock/webhook_fixtures/customer.created.json +37 -46
  51. data/lib/stripe_mock/webhook_fixtures/customer.deleted.json +36 -32
  52. data/lib/stripe_mock/webhook_fixtures/customer.source.created.json +31 -22
  53. data/lib/stripe_mock/webhook_fixtures/customer.source.updated.json +36 -25
  54. data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +135 -47
  55. data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +134 -45
  56. data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +135 -56
  57. data/lib/stripe_mock/webhook_fixtures/customer.updated.json +38 -47
  58. data/lib/stripe_mock/webhook_fixtures/invoice.created.json +176 -49
  59. data/lib/stripe_mock/webhook_fixtures/invoice.finalized.json +171 -0
  60. data/lib/stripe_mock/webhook_fixtures/invoice.paid.json +171 -0
  61. data/lib/stripe_mock/webhook_fixtures/invoice.payment_action_required.json +171 -0
  62. data/lib/stripe_mock/webhook_fixtures/invoice.payment_failed.json +149 -83
  63. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +149 -90
  64. data/lib/stripe_mock/webhook_fixtures/invoice.upcoming.json +70 -0
  65. data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +178 -50
  66. data/lib/stripe_mock/webhook_fixtures/invoiceitem.created.json +87 -13
  67. data/lib/stripe_mock/webhook_fixtures/invoiceitem.updated.json +88 -14
  68. data/lib/stripe_mock/webhook_fixtures/mandate.updated.json +34 -0
  69. data/lib/stripe_mock/webhook_fixtures/payment_intent.amount_capturable_updated.json +170 -0
  70. data/lib/stripe_mock/webhook_fixtures/payment_intent.canceled.json +73 -0
  71. data/lib/stripe_mock/webhook_fixtures/payment_intent.created.json +86 -0
  72. data/lib/stripe_mock/webhook_fixtures/payment_intent.payment_failed.json +225 -0
  73. data/lib/stripe_mock/webhook_fixtures/payment_intent.processing.json +162 -0
  74. data/lib/stripe_mock/webhook_fixtures/payment_intent.requires_action.json +191 -0
  75. data/lib/stripe_mock/webhook_fixtures/payment_intent.succeeded.json +196 -0
  76. data/lib/stripe_mock/webhook_fixtures/payment_link.created.json +47 -0
  77. data/lib/stripe_mock/webhook_fixtures/payment_link.updated.json +50 -0
  78. data/lib/stripe_mock/webhook_fixtures/payment_method.attached.json +63 -0
  79. data/lib/stripe_mock/webhook_fixtures/payment_method.detached.json +62 -0
  80. data/lib/stripe_mock/webhook_fixtures/payout.created.json +40 -0
  81. data/lib/stripe_mock/webhook_fixtures/payout.paid.json +40 -0
  82. data/lib/stripe_mock/webhook_fixtures/payout.updated.json +46 -0
  83. data/lib/stripe_mock/webhook_fixtures/plan.created.json +30 -13
  84. data/lib/stripe_mock/webhook_fixtures/plan.deleted.json +30 -13
  85. data/lib/stripe_mock/webhook_fixtures/plan.updated.json +34 -14
  86. data/lib/stripe_mock/webhook_fixtures/price.created.json +42 -0
  87. data/lib/stripe_mock/webhook_fixtures/price.deleted.json +42 -0
  88. data/lib/stripe_mock/webhook_fixtures/price.updated.json +48 -0
  89. data/lib/stripe_mock/webhook_fixtures/product.created.json +19 -13
  90. data/lib/stripe_mock/webhook_fixtures/product.deleted.json +20 -14
  91. data/lib/stripe_mock/webhook_fixtures/product.updated.json +24 -15
  92. data/lib/stripe_mock/webhook_fixtures/quote.accepted.json +92 -0
  93. data/lib/stripe_mock/webhook_fixtures/quote.canceled.json +92 -0
  94. data/lib/stripe_mock/webhook_fixtures/quote.created.json +92 -0
  95. data/lib/stripe_mock/webhook_fixtures/quote.finalized.json +92 -0
  96. data/lib/stripe_mock/webhook_fixtures/setup_intent.canceled.json +46 -0
  97. data/lib/stripe_mock/webhook_fixtures/setup_intent.created.json +51 -0
  98. data/lib/stripe_mock/webhook_fixtures/setup_intent.setup_failed.json +100 -0
  99. data/lib/stripe_mock/webhook_fixtures/setup_intent.succeeded.json +46 -0
  100. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.canceled.json +119 -0
  101. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.created.json +114 -0
  102. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.released.json +111 -0
  103. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.updated.json +125 -0
  104. data/lib/stripe_mock/webhook_fixtures/tax_rate.created.json +32 -0
  105. data/lib/stripe_mock/webhook_fixtures/tax_rate.updated.json +37 -0
  106. data/lib/stripe_mock.rb +7 -1
  107. data/spec/instance_spec.rb +7 -7
  108. data/spec/integration_examples/completing_checkout_sessions_example.rb +37 -0
  109. data/spec/list_spec.rb +23 -0
  110. data/spec/readme_spec.rb +1 -1
  111. data/spec/server_spec.rb +4 -2
  112. data/spec/shared_stripe_examples/account_examples.rb +9 -1
  113. data/spec/shared_stripe_examples/account_link_examples.rb +16 -0
  114. data/spec/shared_stripe_examples/balance_examples.rb +6 -0
  115. data/spec/shared_stripe_examples/card_token_examples.rb +17 -21
  116. data/spec/shared_stripe_examples/checkout_session_examples.rb +99 -0
  117. data/spec/shared_stripe_examples/customer_examples.rb +11 -13
  118. data/spec/shared_stripe_examples/express_login_link_examples.rb +12 -0
  119. data/spec/shared_stripe_examples/invoice_examples.rb +29 -8
  120. data/spec/shared_stripe_examples/payment_intent_examples.rb +74 -0
  121. data/spec/shared_stripe_examples/payment_method_examples.rb +336 -67
  122. data/spec/shared_stripe_examples/price_examples.rb +223 -0
  123. data/spec/shared_stripe_examples/product_examples.rb +1 -9
  124. data/spec/shared_stripe_examples/promotion_code_examples.rb +68 -0
  125. data/spec/shared_stripe_examples/refund_examples.rb +13 -0
  126. data/spec/shared_stripe_examples/setup_intent_examples.rb +17 -0
  127. data/spec/shared_stripe_examples/subscription_examples.rb +327 -9
  128. data/spec/shared_stripe_examples/transfer_examples.rb +10 -1
  129. data/spec/shared_stripe_examples/webhook_event_examples.rb +51 -5
  130. data/spec/spec_helper.rb +4 -0
  131. data/spec/stripe_mock_spec.rb +2 -2
  132. data/spec/support/stripe_examples.rb +8 -2
  133. data/stripe-ruby-mock.gemspec +7 -2
  134. metadata +72 -15
  135. data/.travis.yml +0 -28
  136. data/lib/stripe_mock/request_handlers/checkout.rb +0 -15
  137. data/spec/shared_stripe_examples/checkout_examples.rb +0 -19
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'securerandom'
3
3
 
4
- shared_examples 'Customer Subscriptions' do
4
+ shared_examples 'Customer Subscriptions with plans' do
5
5
  let(:gen_card_tk) { stripe_helper.generate_card_token }
6
6
 
7
7
  let(:product) { stripe_helper.create_product }
@@ -14,7 +14,7 @@ shared_examples 'Customer Subscriptions' do
14
14
  let(:free_plan) { stripe_helper.create_plan(id: 'free', product: product.id, amount: 0) }
15
15
 
16
16
  context "creating a new subscription" do
17
- it "adds a new subscription to customer with none using items", :live => true do
17
+ it "adds a new subscription to customer with none using items", live: true do
18
18
  plan
19
19
  customer = Stripe::Customer.create(source: gen_card_tk)
20
20
 
@@ -49,7 +49,7 @@ shared_examples 'Customer Subscriptions' do
49
49
  expect(subscriptions.data.first.metadata.example).to eq( "yes" )
50
50
  end
51
51
 
52
- it "adds a new subscription to customer with none", :live => true do
52
+ it "adds a new subscription to customer with none", live: true do
53
53
  plan
54
54
  customer = Stripe::Customer.create(source: gen_card_tk)
55
55
  subscriptions = Stripe::Subscription.list(customer: customer.id)
@@ -117,6 +117,33 @@ shared_examples 'Customer Subscriptions' do
117
117
  expect(subscriptions.data.first.metadata.example).to eq( "yes" )
118
118
  end
119
119
 
120
+ it "adds a new subscription with payment method provided as default" do
121
+ plan
122
+ customer = Stripe::Customer.create(source: gen_card_tk)
123
+ payment_method = Stripe::PaymentMethod.create(
124
+ type: 'card',
125
+ card: {
126
+ number: 4242_4242_4242_4242,
127
+ exp_month: 9,
128
+ exp_year: (Time.now.year + 5),
129
+ cvc: 999
130
+ }
131
+ )
132
+ sub = Stripe::Subscription.create(
133
+ plan: 'silver',
134
+ customer: customer,
135
+ metadata: { foo: "bar", example: "yes" },
136
+ collection_method: 'send_invoice',
137
+ default_payment_method: payment_method.id,
138
+ )
139
+
140
+ subscriptions = Stripe::Subscription.list(customer: customer.id)
141
+ expect(subscriptions.count).to eq(1)
142
+ expect(subscriptions.data.first.id).to eq(sub.id)
143
+ expect(subscriptions.data.first.collection_method).to eq('send_invoice')
144
+ expect(subscriptions.data.first.default_payment_method).to eq(payment_method.id)
145
+ end
146
+
120
147
  it "adds a new subscription to customer (string/symbol agnostic)" do
121
148
  customer = Stripe::Customer.create(source: gen_card_tk)
122
149
  subscriptions = Stripe::Subscription.list(customer: customer.id)
@@ -152,6 +179,7 @@ shared_examples 'Customer Subscriptions' do
152
179
  expect(subscriptions.data).to be_a(Array)
153
180
  expect(subscriptions.data.count).to eq(1)
154
181
  expect(subscriptions.data.first.discount).not_to be_nil
182
+ expect(subscriptions.data.first.discount.id).not_to be_nil
155
183
  expect(subscriptions.data.first.discount).to be_a(Stripe::Discount)
156
184
  expect(subscriptions.data.first.discount.coupon.id).to eq(coupon.id)
157
185
  end
@@ -168,6 +196,28 @@ shared_examples 'Customer Subscriptions' do
168
196
  }
169
197
  end
170
198
 
199
+ it "allows promotion code" do
200
+ customer = Stripe::Customer.create(source: gen_card_tk)
201
+ coupon = stripe_helper.create_coupon
202
+ promotion_code = Stripe::PromotionCode.create(coupon: coupon)
203
+
204
+ expect {
205
+ Stripe::Subscription.create(plan: plan.id, customer: customer.id, promotion_code: promotion_code.id)
206
+ }.not_to raise_error(Stripe::InvalidRequestError)
207
+ end
208
+
209
+ it "does not permit both coupon and promotion code" do
210
+ customer = Stripe::Customer.create(source: gen_card_tk)
211
+
212
+ expect {
213
+ Stripe::Subscription.create(plan: plan.id, customer: customer.id, coupon: "test", promotion_code: "test")
214
+ }.to raise_error { |e|
215
+ expect(e).to be_a Stripe::InvalidRequestError
216
+ expect(e.http_status).to eq(400)
217
+ expect(e.message).to eq("You may only specify one of these parameters: coupon, promotion_code")
218
+ }
219
+ end
220
+
171
221
  it "correctly sets quantity, application_fee_percent and tax_percent" do
172
222
  customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk)
173
223
 
@@ -263,6 +313,27 @@ shared_examples 'Customer Subscriptions' do
263
313
  expect(customer.subscriptions.count).to eq(0)
264
314
  end
265
315
 
316
+ it "creates a subscription when subscription's payment_behavior is default_incomplete" do
317
+ plan = stripe_helper.create_plan(id: 'enterprise', product: product.id, amount: 499)
318
+ customer = Stripe::Customer.create(id: 'cardless')
319
+
320
+ sub = Stripe::Subscription.create({ plan: plan.id, customer: customer.id, payment_behavior: 'default_incomplete' })
321
+ customer = Stripe::Customer.retrieve('cardless')
322
+
323
+ expect(customer.subscriptions.count).to eq(1)
324
+ expect(customer.subscriptions.data.first.id).to eq(sub.id)
325
+ expect(customer.subscriptions.data.first.status).to eq('incomplete')
326
+ end
327
+
328
+ it "allows setting transfer_data" do
329
+ customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk)
330
+
331
+ sub = Stripe::Subscription.create({ customer: customer.id, plan: plan.id, transfer_data: {destination: "acct_0000000000000000", amount_percent: 50} })
332
+
333
+ expect(sub.transfer_data.destination).to eq("acct_0000000000000000")
334
+ expect(sub.transfer_data.amount_percent).to eq(50)
335
+ end
336
+
266
337
  it "throws an error when subscribing a customer with no card" do
267
338
  plan = stripe_helper.create_plan(id: 'enterprise', product: product.id, amount: 499)
268
339
  customer = Stripe::Customer.create(id: 'cardless')
@@ -311,7 +382,7 @@ shared_examples 'Customer Subscriptions' do
311
382
  expect(sub.object).to eq('subscription')
312
383
  expect(sub.plan.to_hash).to eq(plan_with_trial.to_hash)
313
384
  expect(sub.trial_end - sub.trial_start).to eq(14 * 86400)
314
- expect(sub.billing_cycle_anchor).to be_nil
385
+ expect(sub.billing_cycle_anchor).to eq sub.trial_start
315
386
 
316
387
  customer = Stripe::Customer.retrieve(customer.id)
317
388
  subscriptions = Stripe::Subscription.list(customer: customer.id)
@@ -505,6 +576,45 @@ shared_examples 'Customer Subscriptions' do
505
576
  expect(subscription.items.data[1].plan.id).to eq plan2.id
506
577
  end
507
578
 
579
+ it 'sets current_period_end based on price week interval', live: true do
580
+ price = stripe_helper.create_price(recurring: {interval: 'week'})
581
+
582
+ subscription = Stripe::Subscription.create(
583
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
584
+ items: [
585
+ {price: price.id, quantity: 1}
586
+ ]
587
+ )
588
+
589
+ expect(subscription.current_period_end).to eq (Time.now + (7 * 60 * 60 * 24)).to_i
590
+ end
591
+
592
+ it 'sets current_period_end based on price month interval', live: true do
593
+ price = stripe_helper.create_price(recurring: {interval: 'month'})
594
+
595
+ subscription = Stripe::Subscription.create(
596
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
597
+ items: [
598
+ {price: price.id, quantity: 1}
599
+ ]
600
+ )
601
+
602
+ expect(subscription.current_period_end).to eq (DateTime.now >> 1).to_time.to_i
603
+ end
604
+
605
+ it 'sets current_period_end based on price year interval', live: true do
606
+ price = stripe_helper.create_price(recurring: {interval: 'year'})
607
+
608
+ subscription = Stripe::Subscription.create(
609
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
610
+ items: [
611
+ {price: price.id, quantity: 1}
612
+ ]
613
+ )
614
+
615
+ expect(subscription.current_period_end).to eq (DateTime.now >> 12).to_time.to_i
616
+ end
617
+
508
618
  it 'add a new subscription to bill via an invoice' do
509
619
  product = stripe_helper.create_product(id: 'invoice_billing')
510
620
  plan = stripe_helper.create_plan(id: 'silver', product: product.id,
@@ -550,7 +660,7 @@ shared_examples 'Customer Subscriptions' do
550
660
  expect(sub1).to eq(sub2)
551
661
  end
552
662
 
553
- it "adds a new subscription to customer with different idempotency key", :live => true do
663
+ it "adds a new subscription to customer with different idempotency key", live: true do
554
664
  product = stripe_helper.create_product(name: 'Silver Product')
555
665
  plan = stripe_helper.create_plan(id: 'silver', product: product.id,
556
666
  amount: 4999, currency: 'usd')
@@ -606,6 +716,35 @@ shared_examples 'Customer Subscriptions' do
606
716
  expect(subscription.default_tax_rates.first.id).to eq(tax_rate.id)
607
717
  end
608
718
  end
719
+
720
+ it 'expands latest_invoice.payment_intent' do
721
+ customer = Stripe::Customer.create(source: gen_card_tk)
722
+ subscription = Stripe::Subscription.create({
723
+ customer: customer.id,
724
+ plan: plan.id,
725
+ expand: ['latest_invoice.payment_intent']
726
+ })
727
+
728
+ expect(subscription.latest_invoice.payment_intent.status).to eq('succeeded')
729
+
730
+ subscription = Stripe::Subscription.create({
731
+ customer: customer.id,
732
+ plan: plan.id,
733
+ expand: ['latest_invoice.payment_intent'],
734
+ payment_behavior: 'default_incomplete'
735
+ })
736
+
737
+ expect(subscription.latest_invoice.payment_intent.status).to eq('requires_payment_method')
738
+
739
+ subscription = Stripe::Subscription.create({
740
+ customer: customer.id,
741
+ plan: plan.id,
742
+ expand: ['latest_invoice.payment_intent'],
743
+ trial_period_days: 14
744
+ })
745
+
746
+ expect(subscription.latest_invoice.payment_intent).to be_nil
747
+ end
609
748
  end
610
749
 
611
750
  context "updating a subscription" do
@@ -754,6 +893,43 @@ shared_examples 'Customer Subscriptions' do
754
893
  expect(subscription.pending_invoice_item_interval.interval_count).to eq 3
755
894
  end
756
895
 
896
+ it "updates a subscription's default payment method" do
897
+ plan
898
+ customer = Stripe::Customer.create(source: gen_card_tk)
899
+ payment_method_card = Stripe::PaymentMethod.create(
900
+ type: 'card',
901
+ card: {
902
+ number: 4242_4242_4242_4242,
903
+ exp_month: 9,
904
+ exp_year: (Time.now.year + 5),
905
+ cvc: 999
906
+ }
907
+ )
908
+ payment_method_sepa = Stripe::PaymentMethod.create(
909
+ type: 'sepa_debit',
910
+ sepa_debit: {iban: 'DE89370400440532013000'},
911
+ )
912
+ subscription = Stripe::Subscription.create(
913
+ plan: 'silver',
914
+ customer: customer,
915
+ metadata: { foo: "bar", example: "yes" },
916
+ default_payment_method: payment_method_card.id,
917
+ )
918
+
919
+ subscriptions = Stripe::Subscription.list(customer: customer)
920
+ expect(subscriptions.data.first.default_payment_method).to eq(payment_method_card.id)
921
+
922
+ Stripe::Subscription.update(
923
+ subscription.id,
924
+ default_payment_method: payment_method_sepa.id,
925
+ collection_method: 'send_invoice',
926
+ )
927
+
928
+ subscriptions = Stripe::Subscription.list(customer: customer)
929
+ expect(subscriptions.data.first.collection_method).to eq('send_invoice')
930
+ expect(subscriptions.data.first.default_payment_method).to eq(payment_method_sepa.id)
931
+ end
932
+
757
933
  it 'when adds coupon', live: true do
758
934
  coupon = stripe_helper.create_coupon
759
935
  customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id)
@@ -794,6 +970,23 @@ shared_examples 'Customer Subscriptions' do
794
970
  expect(subscription.discount).to be_nil
795
971
  end
796
972
 
973
+ it "throws an error when promotion code has an amount restriction" do
974
+ coupon = stripe_helper.create_coupon
975
+ promotion_code = Stripe::PromotionCode.create(
976
+ coupon: coupon, restrictions: {minimum_amount: 100, minimum_amount_currency: "USD"}
977
+ )
978
+ customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id)
979
+ subscription = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id)
980
+
981
+ subscription.promotion_code = promotion_code.id
982
+
983
+ expect { subscription.save }.to raise_error { |e|
984
+ expect(e).to be_a Stripe::InvalidRequestError
985
+ expect(e.http_status).to eq(400)
986
+ expect(e.message).to_not be_nil
987
+ }
988
+ end
989
+
797
990
  it "throws an error when plan does not exist" do
798
991
  customer = Stripe::Customer.create(id: 'cardless', plan: free_plan.id)
799
992
 
@@ -966,12 +1159,24 @@ shared_examples 'Customer Subscriptions' do
966
1159
  expect(e.message).to eq("Invalid timestamp: must be an integer")
967
1160
  }
968
1161
  end
1162
+
1163
+ it "converts billing_cycle_anchor=now to a timestamp" do
1164
+ customer = Stripe::Customer.create(id: 'test_billing_anchor', plan: plan.id, source: gen_card_tk)
1165
+
1166
+ sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id)
1167
+ sub.billing_cycle_anchor = 'now'
1168
+ sub.save
1169
+
1170
+ expect(sub.billing_cycle_anchor).to be_a(Integer)
1171
+ end
1172
+
1173
+
969
1174
  end
970
1175
 
971
1176
  context "cancelling a subscription" do
972
1177
  let(:customer) { Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: plan.id) }
973
1178
 
974
- it "cancels a stripe customer's subscription", :live => true do
1179
+ it "cancels a stripe customer's subscription", live: true do
975
1180
  customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id)
976
1181
 
977
1182
  sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id)
@@ -1051,7 +1256,7 @@ shared_examples 'Customer Subscriptions' do
1051
1256
  expect(customer.subscriptions.data.first.status).to eq('trialing')
1052
1257
  end
1053
1258
 
1054
- it "doesn't require a card when trial_end is present", :live => true do
1259
+ it "doesn't require a card when trial_end is present", live: true do
1055
1260
  plan = stripe_helper.create_plan(
1056
1261
  :amount => 2000,
1057
1262
  :product => product.id,
@@ -1083,7 +1288,7 @@ shared_examples 'Customer Subscriptions' do
1083
1288
  expect(subscription.items.object).to eq('list')
1084
1289
  expect(subscription.items.data.class).to eq(Array)
1085
1290
  expect(subscription.items.data.count).to eq(1)
1086
- expect(subscription.items.data.first.id).to eq('test_txn_default')
1291
+ expect(subscription.items.data.first.id).to include('test_si_')
1087
1292
  expect(subscription.items.data.first.created).to eq(1504716183)
1088
1293
  expect(subscription.items.data.first.object).to eq('subscription_item')
1089
1294
  expect(subscription.items.data.first.plan.amount).to eq(0)
@@ -1091,6 +1296,10 @@ shared_examples 'Customer Subscriptions' do
1091
1296
  expect(subscription.items.data.first.plan.currency).to eq('usd')
1092
1297
  expect(subscription.items.data.first.quantity).to eq(2)
1093
1298
  end
1299
+
1300
+ it "has a start_date attribute" do
1301
+ expect(subscription).to respond_to(:start_date)
1302
+ end
1094
1303
  end
1095
1304
 
1096
1305
  context "retrieve multiple subscriptions" do
@@ -1118,11 +1327,55 @@ shared_examples 'Customer Subscriptions' do
1118
1327
  expect(list.count).to eq(0)
1119
1328
  expect(list.data.length).to eq(0)
1120
1329
  end
1330
+
1331
+ it "does not include canceled subscriptions by default" do
1332
+ customer = Stripe::Customer.create(source: gen_card_tk)
1333
+ subscription = Stripe::Subscription.create({ plan: plan.id, customer: customer.id })
1334
+ subscription.delete
1335
+
1336
+ list = Stripe::Subscription.list({customer: customer.id})
1337
+
1338
+ expect(list.object).to eq("list")
1339
+ expect(list.data).to be_empty
1340
+ expect(list.data.length).to eq(0)
1341
+ end
1342
+
1343
+ it "filters out subscriptions based on their current_period", live: true do
1344
+ price = stripe_helper.create_price(recurring: { interval: 'month' })
1345
+ price2 = stripe_helper.create_price(recurring: { interval: 'year' })
1346
+
1347
+ subscription1 = Stripe::Subscription.create(
1348
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
1349
+ items: [{ price: price.id, quantity: 1 }]
1350
+ )
1351
+ subscription2 = Stripe::Subscription.create(
1352
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
1353
+ items: [{ price: price2.id, quantity: 1 }]
1354
+ )
1355
+
1356
+ list = Stripe::Subscription.list({ current_period_end: { gt: subscription1.current_period_end }})
1357
+ expect(list.data).to contain_exactly(subscription2)
1358
+
1359
+ list = Stripe::Subscription.list({ current_period_end: { gte: subscription1.current_period_end }})
1360
+ expect(list.data).to contain_exactly(subscription1, subscription2)
1361
+
1362
+ list = Stripe::Subscription.list({ current_period_end: { lt: subscription1.current_period_end }})
1363
+ expect(list.data).to be_empty
1364
+
1365
+ list = Stripe::Subscription.list({ current_period_end: { lte: subscription1.current_period_end }})
1366
+ expect(list.data).to contain_exactly(subscription1)
1367
+
1368
+ list = Stripe::Subscription.list({ current_period_start: subscription1.current_period_start })
1369
+ expect(list.data).to contain_exactly(subscription1, subscription2)
1370
+
1371
+ list = Stripe::Subscription.list({ current_period_end: subscription2.current_period_end })
1372
+ expect(list.data).to contain_exactly(subscription2)
1373
+ end
1121
1374
  end
1122
1375
 
1123
1376
  describe "metadata" do
1124
1377
 
1125
- it "creates a stripe customer and subscribes them to a plan with meta data", :live => true do
1378
+ it "creates a stripe customer and subscribes them to a plan with meta data", live: true do
1126
1379
 
1127
1380
  stripe_helper.
1128
1381
  create_plan(
@@ -1148,6 +1401,71 @@ shared_examples 'Customer Subscriptions' do
1148
1401
  expect(customer.subscriptions.first.plan.id).to eq('Sample5')
1149
1402
  expect(customer.subscriptions.first.metadata['foo']).to eq('bar')
1150
1403
  end
1404
+
1405
+ it "saves subscription item metadata" do
1406
+ stripe_helper.
1407
+ create_plan(
1408
+ :amount => 500,
1409
+ :interval => 'month',
1410
+ :product => product.id,
1411
+ :currency => 'usd',
1412
+ :id => 'Sample5'
1413
+ )
1414
+ customer = Stripe::Customer.create({
1415
+ email: 'johnny@appleseed.com',
1416
+ source: gen_card_tk
1417
+ })
1418
+
1419
+ subscription = Stripe::Subscription.create(
1420
+ customer: customer.id,
1421
+ items: [{plan: "Sample5", metadata: {foo: 'bar'}}],
1422
+ )
1423
+ expect(subscription.items.data[0].metadata.to_h).to eq(foo: 'bar')
1424
+ end
1151
1425
  end
1426
+ end
1427
+
1428
+ shared_examples 'Customer Subscriptions with prices' do
1429
+ let(:gen_card_tk) { stripe_helper.generate_card_token }
1430
+
1431
+ let(:product) { stripe_helper.create_product }
1432
+ let(:price) { stripe_helper.create_price(product: product.id, amount: 4999, currency: 'usd') }
1433
+
1434
+ context "creating a new subscription" do
1435
+ it "adds a new subscription to customer with none using items", live: true do
1436
+ customer = Stripe::Customer.create(source: gen_card_tk)
1437
+
1438
+ expect(customer.subscriptions.data).to be_empty
1439
+ expect(customer.subscriptions.count).to eq(0)
1440
+
1441
+ subscription = Stripe::Subscription.create({
1442
+ customer: customer.id,
1443
+ items: [{ price: price.id }],
1444
+ metadata: { foo: "bar", example: "yes" }
1445
+ })
1446
+
1447
+ expect(subscription.object).to eq('subscription')
1448
+ expect(subscription.plan.to_hash).to eq(price.to_hash)
1449
+ expect(subscription.items.first.price.to_hash).to eq(price.to_hash)
1450
+ expect(subscription.metadata.foo).to eq("bar")
1451
+ expect(subscription.metadata.example).to eq("yes")
1452
+
1453
+ customer = Stripe::Customer.retrieve(customer.id)
1454
+ subscriptions = Stripe::Subscription.list(customer: customer.id)
1455
+ charges = Stripe::Charge.list(customer: customer.id)
1152
1456
 
1457
+ expect(subscriptions.data).to_not be_empty
1458
+ expect(subscriptions.count).to eq(1)
1459
+ expect(subscriptions.data.length).to eq(1)
1460
+ expect(charges.data.length).to eq(1)
1461
+ expect(customer.currency).to eq("usd")
1462
+
1463
+ expect(subscriptions.data.first.id).to eq(subscription.id)
1464
+ expect(subscriptions.data.first.plan.to_hash).to eq(price.to_hash)
1465
+ expect(subscriptions.data.first.items.first.price.to_hash).to eq(price.to_hash)
1466
+ expect(subscriptions.data.first.customer).to eq(customer.id)
1467
+ expect(subscriptions.data.first.metadata.foo).to eq( "bar" )
1468
+ expect(subscriptions.data.first.metadata.example).to eq( "yes" )
1469
+ end
1470
+ end
1153
1471
  end
@@ -9,7 +9,7 @@ shared_examples 'Transfer API' do
9
9
  expect(transfer.id).to match /^test_tr/
10
10
  expect(transfer.amount).to eq(100)
11
11
  expect(transfer.amount_reversed).to eq(0)
12
- expect(transfer.balance_transaction).to eq('txn_2dyYXXP90MN26R')
12
+ expect(transfer.balance_transaction).to eq('test_txn_1')
13
13
  expect(transfer.created).to eq(1304114826)
14
14
  expect(transfer.currency).to eq('usd')
15
15
  expect(transfer.description).to eq('Transfer description')
@@ -30,6 +30,15 @@ shared_examples 'Transfer API' do
30
30
  expect(transfer.transfer_group).to eq("group_ch_164xRv2eZvKYlo2Clu1sIJWB")
31
31
  end
32
32
 
33
+ it "creates a balance transaction" do
34
+ destination = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", id: "acct_12345", requested_capabilities: ['card_payments', 'platform_payments'])
35
+ transfer = Stripe::Transfer.create(amount: 100, currency: "usd", destination: destination.id)
36
+
37
+ bal_trans = Stripe::BalanceTransaction.retrieve(transfer.balance_transaction)
38
+ expect(bal_trans.amount).to eq(100)
39
+ expect(bal_trans.source).to eq(transfer.id)
40
+ end
41
+
33
42
  describe "listing transfers" do
34
43
  let(:destination) { Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", business_name: "MyCo") }
35
44
 
@@ -203,6 +203,52 @@ shared_examples 'Webhook Events API' do
203
203
  expect(events.map &:type).to include('invoiceitem.created', 'invoice.created', 'coupon.created')
204
204
  end
205
205
 
206
+ it "retrieves events with a created timestamp" do
207
+ timestamp = Time.now.to_i - 7200
208
+ customer_created_event = StripeMock.mock_webhook_event('customer.created', created: Time.now.to_i - 14_400)
209
+ plan_created_event = StripeMock.mock_webhook_event('plan.created', created: Time.now.to_i - 10_800)
210
+ coupon_created_event = StripeMock.mock_webhook_event('coupon.created', created: timestamp)
211
+ invoice_created_event = StripeMock.mock_webhook_event('invoice.created', created: Time.now.to_i - 3600)
212
+ invoice_item_created_event = StripeMock.mock_webhook_event('invoiceitem.created')
213
+
214
+ events = Stripe::Event.list(created: timestamp)
215
+ expect(events.count).to eq(1)
216
+ expect(events.map &:id).to match_array([coupon_created_event.id])
217
+ expect(events.map &:type).to match_array(['coupon.created'])
218
+
219
+ events = Stripe::Event.list(created: timestamp.to_s)
220
+ expect(events.count).to eq(1)
221
+ expect(events.map &:id).to match_array([coupon_created_event.id])
222
+ expect(events.map &:type).to match_array(['coupon.created'])
223
+ end
224
+
225
+ it "retrieves events with a created filter" do
226
+ timestamp1 = Time.now.to_i - 3600
227
+ timestamp2 = Time.now.to_i - 7200
228
+ timestamp3 = Time.now.to_i - 10_800
229
+ timestamp4 = Time.now.to_i - 14_400
230
+ customer_created_event = StripeMock.mock_webhook_event('customer.created', created: timestamp4)
231
+ plan_created_event = StripeMock.mock_webhook_event('plan.created', created: timestamp3)
232
+ coupon_created_event = StripeMock.mock_webhook_event('coupon.created', created: timestamp2)
233
+ invoice_created_event = StripeMock.mock_webhook_event('invoice.created', created: timestamp1)
234
+ invoice_item_created_event = StripeMock.mock_webhook_event('invoiceitem.created')
235
+
236
+ events = Stripe::Event.list(created: {gte: timestamp2, lte: timestamp1})
237
+ expect(events.count).to eq(2)
238
+ expect(events.map &:id).to match_array([coupon_created_event.id, invoice_created_event.id])
239
+ expect(events.map &:type).to match_array(['coupon.created', 'invoice.created'])
240
+
241
+ events = Stripe::Event.list(created: {gt: timestamp3})
242
+ expect(events.count).to eq(3)
243
+ expect(events.map &:id).to match_array([coupon_created_event.id, invoice_created_event.id, invoice_item_created_event.id])
244
+ expect(events.map &:type).to match_array(['coupon.created', 'invoice.created', 'invoiceitem.created'])
245
+
246
+ events = Stripe::Event.list(created: {lt: timestamp3.to_s})
247
+ expect(events.count).to eq(1)
248
+ expect(events.map &:id).to match_array([customer_created_event.id])
249
+ expect(events.map &:type).to match_array(['customer.created'])
250
+ end
251
+
206
252
  end
207
253
 
208
254
  describe 'Subscription events' do
@@ -211,7 +257,7 @@ shared_examples 'Webhook Events API' do
211
257
  expect(subscription_created_event).to be_a(Stripe::Event)
212
258
  expect(subscription_created_event.id).to_not be_nil
213
259
  expect(subscription_created_event.data.object.items.data.class).to be Array
214
- expect(subscription_created_event.data.object.items.data.length).to be 2
260
+ expect(subscription_created_event.data.object.items.data.length).to be 1
215
261
  expect(subscription_created_event.data.object.items.data.first).to respond_to(:plan)
216
262
  expect(subscription_created_event.data.object.items.data.first.id).to eq('si_00000000000000')
217
263
  end
@@ -221,7 +267,7 @@ shared_examples 'Webhook Events API' do
221
267
  expect(subscription_deleted_event).to be_a(Stripe::Event)
222
268
  expect(subscription_deleted_event.id).to_not be_nil
223
269
  expect(subscription_deleted_event.data.object.items.data.class).to be Array
224
- expect(subscription_deleted_event.data.object.items.data.length).to be 2
270
+ expect(subscription_deleted_event.data.object.items.data.length).to be 1
225
271
  expect(subscription_deleted_event.data.object.items.data.first).to respond_to(:plan)
226
272
  expect(subscription_deleted_event.data.object.items.data.first.id).to eq('si_00000000000000')
227
273
  end
@@ -231,7 +277,7 @@ shared_examples 'Webhook Events API' do
231
277
  expect(subscription_updated_event).to be_a(Stripe::Event)
232
278
  expect(subscription_updated_event.id).to_not be_nil
233
279
  expect(subscription_updated_event.data.object.items.data.class).to be Array
234
- expect(subscription_updated_event.data.object.items.data.length).to be 2
280
+ expect(subscription_updated_event.data.object.items.data.length).to be 1
235
281
  expect(subscription_updated_event.data.object.items.data.first).to respond_to(:plan)
236
282
  expect(subscription_updated_event.data.object.items.data.first.id).to eq('si_00000000000000')
237
283
  end
@@ -253,9 +299,9 @@ shared_examples 'Webhook Events API' do
253
299
  expect(invoice_payment_succeeded).to be_a(Stripe::Event)
254
300
  expect(invoice_payment_succeeded.id).to_not be_nil
255
301
  expect(invoice_payment_succeeded.data.object.lines.data.class).to be Array
256
- expect(invoice_payment_succeeded.data.object.lines.data.length).to be 2
302
+ expect(invoice_payment_succeeded.data.object.lines.data.length).to be 1
257
303
  expect(invoice_payment_succeeded.data.object.lines.data.first).to respond_to(:plan)
258
- expect(invoice_payment_succeeded.data.object.lines.data.first.id).to eq('sub_00000000000000')
304
+ expect(invoice_payment_succeeded.data.object.lines.data.first.id).to eq('il_000000000000000000000000')
259
305
  end
260
306
  end
261
307
  end
data/spec/spec_helper.rb CHANGED
@@ -5,6 +5,9 @@ require 'rspec'
5
5
  require 'stripe'
6
6
  require 'stripe_mock'
7
7
  require 'stripe_mock/server'
8
+ require 'dotenv'
9
+
10
+ Dotenv.load('.env')
8
11
 
9
12
  # Requires supporting ruby files with custom matchers and macros, etc,
10
13
  # in spec/support/ and its subdirectories.
@@ -33,6 +36,7 @@ RSpec.configure do |c|
33
36
  when '2.4.6' then ENV['STRIPE_TEST_SECRET_KEY_A']
34
37
  when '2.5.5' then ENV['STRIPE_TEST_SECRET_KEY_B']
35
38
  when '2.6.3' then ENV['STRIPE_TEST_SECRET_KEY_C']
39
+ when '2.7.0' then ENV['STRIPE_TEST_SECRET_KEY_D']
36
40
  end
37
41
  else
38
42
  api_key = ENV['STRIPE_TEST_SECRET_KEY']
@@ -35,8 +35,8 @@ describe StripeMock do
35
35
  StripeMock.stop
36
36
  StripeMock.start
37
37
 
38
- expect(StripeMock.instance.customers[:x]).to be_nil
39
- expect(StripeMock.instance.customers.keys.length).to eq(0)
38
+ expect(StripeMock.instance.customers[''][:x]).to be_nil
39
+ expect(StripeMock.instance.customers[''].keys.length).to eq(0)
40
40
  StripeMock.stop
41
41
  end
42
42
 
@@ -5,6 +5,7 @@ end
5
5
 
6
6
  def it_behaves_like_stripe(&block)
7
7
  it_behaves_like 'Account API', &block
8
+ it_behaves_like 'Account Link API', &block
8
9
  it_behaves_like 'Balance API', &block
9
10
  it_behaves_like 'Balance Transaction API', &block
10
11
  it_behaves_like 'Bank Account Token Mocking', &block
@@ -12,6 +13,7 @@ def it_behaves_like_stripe(&block)
12
13
  it_behaves_like 'Card API', &block
13
14
  it_behaves_like 'Charge API', &block
14
15
  it_behaves_like 'Bank API', &block
16
+ it_behaves_like 'Express Login Link API', &block
15
17
  it_behaves_like 'External Account API', &block
16
18
  it_behaves_like 'Coupon API', &block
17
19
  it_behaves_like 'Customer API', &block
@@ -20,7 +22,9 @@ def it_behaves_like_stripe(&block)
20
22
  it_behaves_like 'Invoice API', &block
21
23
  it_behaves_like 'Invoice Item API', &block
22
24
  it_behaves_like 'Plan API', &block
25
+ it_behaves_like 'Price API', &block
23
26
  it_behaves_like 'Product API', &block
27
+ it_behaves_like 'PromotionCode API', &block
24
28
  it_behaves_like 'Recipient API', &block
25
29
  it_behaves_like 'Refund API', &block
26
30
  it_behaves_like 'Transfer API', &block
@@ -29,16 +33,18 @@ def it_behaves_like_stripe(&block)
29
33
  it_behaves_like 'PaymentMethod API', &block
30
34
  it_behaves_like 'SetupIntent API', &block
31
35
  it_behaves_like 'Stripe Error Mocking', &block
32
- it_behaves_like 'Customer Subscriptions', &block
36
+ it_behaves_like 'Customer Subscriptions with plans', &block
37
+ it_behaves_like 'Customer Subscriptions with prices', &block
33
38
  it_behaves_like 'Subscription Items API', &block
34
39
  it_behaves_like 'Webhook Events API', &block
35
40
  it_behaves_like 'Country Spec API', &block
36
41
  it_behaves_like 'EphemeralKey API', &block
37
42
  it_behaves_like 'TaxRate API', &block
38
- it_behaves_like 'Checkout API', &block
43
+ it_behaves_like 'Checkout Session API', &block
39
44
 
40
45
  # Integration tests
41
46
  it_behaves_like 'Multiple Customer Cards'
42
47
  it_behaves_like 'Charging with Tokens'
43
48
  it_behaves_like 'Card Error Prep'
49
+ it_behaves_like 'Completing Checkout Sessions'
44
50
  end