stripe-ruby-mock 2.4.0 → 2.4.1

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.env +2 -0
  3. data/.travis.yml +2 -0
  4. data/README.md +1 -1
  5. data/lib/stripe_mock.rb +1 -0
  6. data/lib/stripe_mock/api/conversion_rate.rb +14 -0
  7. data/lib/stripe_mock/client.rb +12 -0
  8. data/lib/stripe_mock/data/list.rb +7 -0
  9. data/lib/stripe_mock/instance.rb +30 -1
  10. data/lib/stripe_mock/request_handlers/balance_transactions.rb +18 -2
  11. data/lib/stripe_mock/request_handlers/charges.rb +12 -3
  12. data/lib/stripe_mock/request_handlers/coupons.rb +2 -2
  13. data/lib/stripe_mock/request_handlers/customers.rb +9 -0
  14. data/lib/stripe_mock/request_handlers/helpers/card_helpers.rb +1 -0
  15. data/lib/stripe_mock/request_handlers/invoices.rb +12 -1
  16. data/lib/stripe_mock/request_handlers/orders.rb +1 -1
  17. data/lib/stripe_mock/request_handlers/refunds.rb +1 -1
  18. data/lib/stripe_mock/request_handlers/subscriptions.rb +16 -10
  19. data/lib/stripe_mock/server.rb +9 -0
  20. data/lib/stripe_mock/test_strategies/live.rb +5 -0
  21. data/lib/stripe_mock/test_strategies/mock.rb +8 -0
  22. data/lib/stripe_mock/version.rb +1 -1
  23. data/spec/instance_spec.rb +5 -0
  24. data/spec/list_spec.rb +16 -3
  25. data/spec/server_spec.rb +4 -0
  26. data/spec/shared_stripe_examples/balance_transaction_examples.rb +28 -0
  27. data/spec/shared_stripe_examples/card_examples.rb +7 -0
  28. data/spec/shared_stripe_examples/charge_examples.rb +32 -2
  29. data/spec/shared_stripe_examples/coupon_examples.rb +2 -2
  30. data/spec/shared_stripe_examples/customer_examples.rb +14 -0
  31. data/spec/shared_stripe_examples/dispute_examples.rb +1 -1
  32. data/spec/shared_stripe_examples/invoice_examples.rb +17 -1
  33. data/spec/shared_stripe_examples/refund_examples.rb +1 -1
  34. data/spec/shared_stripe_examples/subscription_examples.rb +42 -0
  35. data/spec/shared_stripe_examples/transfer_examples.rb +16 -0
  36. data/spec/shared_stripe_examples/webhook_event_examples.rb +2 -2
  37. data/spec/spec_helper.rb +1 -1
  38. data/stripe-ruby-mock.gemspec +1 -1
  39. metadata +14 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2dc4a01998c2f9e1cd85aee1281cf75d5b4aa436
4
- data.tar.gz: 045708a8af619fc7b299055f0822eed79f8cae1f
3
+ metadata.gz: a861480c10df772899ac63e55dbc97d84ff3eb2c
4
+ data.tar.gz: 3d44f183f03df9af022be2b36b49fe45a01ed1e6
5
5
  SHA512:
6
- metadata.gz: 918999885f3cf5e32133f85b535e76ecbe7c482b106b4fe70e9a8de03fcd95132bfd4d43496bc397492da84bfb5eded5c46807e70c2562ee38923e202bf6dd89
7
- data.tar.gz: b9ab01a438f10f7148470641a0b0fddcd32b0fedfc28969a8f52020d483ed64e045e384f1acda6ec422680c54f34c36ace6dcb89b2a01949053e96269e9953a6
6
+ metadata.gz: 38a0c8592b9dc4181fdd8730e9b2d2496f852911a480eddc3621a7061d7cd0e1a6e6268a4f722be98483b58b32dd03eb7664135caaa99a638fce5dc70d20d10c
7
+ data.tar.gz: 44f924ab949f7101b1854f413b7120a0cafc5432c83ae23ab993c4cde6e879445f33ef8fa863a066d24bc06c14d3f9c299a5d6917f58890fd32a76a07ed72be9
data/.env ADDED
@@ -0,0 +1,2 @@
1
+ STRIPE_TEST_SECRET_KEY=sk_test_eFvAvN5rz4GqAbsWxg63Jx79
2
+ STRIPE_TEST_OAUTH_ACCESS_TOKEN=sk_test_WnZmEBIHhMcDltNe98sqWN7z
@@ -1,3 +1,5 @@
1
+ dist: trusty
2
+ sudo: required
1
3
  language: ruby
2
4
  rvm:
3
5
  - 1.9.3
data/README.md CHANGED
@@ -12,7 +12,7 @@ This gem has unexpectedly grown in popularity and I've gotten pretty busy, so I'
12
12
 
13
13
  In your gemfile:
14
14
 
15
- gem 'stripe-ruby-mock', '~> 2.4.0', :require => 'stripe_mock'
15
+ gem 'stripe-ruby-mock', '~> 2.4.1', :require => 'stripe_mock'
16
16
 
17
17
  ## Features
18
18
 
@@ -26,6 +26,7 @@ require 'stripe_mock/api/client'
26
26
  require 'stripe_mock/api/server'
27
27
 
28
28
  require 'stripe_mock/api/bank_tokens'
29
+ require 'stripe_mock/api/conversion_rate'
29
30
  require 'stripe_mock/api/card_tokens'
30
31
  require 'stripe_mock/api/debug'
31
32
  require 'stripe_mock/api/errors'
@@ -0,0 +1,14 @@
1
+ module StripeMock
2
+
3
+ def self.set_conversion_rate(value)
4
+ case @state
5
+ when 'local'
6
+ instance.conversion_rate = value
7
+ when 'remote'
8
+ client.set_conversion_rate(value)
9
+ else
10
+ raise UnstartedStateError
11
+ end
12
+ end
13
+
14
+ end
@@ -65,6 +65,14 @@ module StripeMock
65
65
  timeout_wrap { Stripe::Util.symbolize_names @pipe.generate_webhook_event(event_data) }
66
66
  end
67
67
 
68
+ def get_conversion_rate
69
+ timeout_wrap { @pipe.get_data(:conversion_rate) }
70
+ end
71
+
72
+ def set_conversion_rate(value)
73
+ timeout_wrap { @pipe.set_conversion_rate(value) }
74
+ end
75
+
68
76
  def destroy_resource(type, id)
69
77
  timeout_wrap { @pipe.destroy_resource(type, id) }
70
78
  end
@@ -73,6 +81,10 @@ module StripeMock
73
81
  timeout_wrap { @pipe.clear_data }
74
82
  end
75
83
 
84
+ def upsert_stripe_object(object, attributes)
85
+ timeout_wrap { @pipe.upsert_stripe_object(object, attributes) }
86
+ end
87
+
76
88
  def close!
77
89
  self.cleanup
78
90
  StripeMock.stop_client(:clear_server_data => false)
@@ -7,6 +7,13 @@ module StripeMock
7
7
  @data = Array(data.clone)
8
8
  @limit = [[options[:limit] || 10, 100].min, 1].max # restrict @limit to 1..100
9
9
  @starting_after = options[:starting_after]
10
+ if @data.first.is_a?(Hash) && @data.first[:created]
11
+ @data.sort_by! { |x| x[:created] }
12
+ @data.reverse!
13
+ elsif @data.first.respond_to?(:created)
14
+ @data.sort_by { |x| x.created }
15
+ @data.reverse!
16
+ end
10
17
  end
11
18
 
12
19
  def url
@@ -45,7 +45,7 @@ module StripeMock
45
45
  :disputes, :events, :invoices, :invoice_items, :orders, :plans, :recipients,
46
46
  :refunds, :transfers, :subscriptions, :country_spec
47
47
 
48
- attr_accessor :error_queue, :debug
48
+ attr_accessor :error_queue, :debug, :conversion_rate
49
49
 
50
50
  def initialize
51
51
  @accounts = {}
@@ -71,6 +71,7 @@ module StripeMock
71
71
  @error_queue = ErrorQueue.new
72
72
  @id_counter = 0
73
73
  @balance_transaction_counter = 0
74
+ @conversion_rate = 1.0
74
75
 
75
76
  # This is basically a cache for ParamValidators
76
77
  @base_strategy = TestStrategies::Base.new
@@ -113,6 +114,33 @@ module StripeMock
113
114
  @events[ event_data[:id] ] = symbolize_names(event_data)
114
115
  end
115
116
 
117
+ def upsert_stripe_object(object, attributes)
118
+ # Most Stripe entities can be created via the API. However, some entities are created when other Stripe entities are
119
+ # created - such as when BalanceTransactions are created when Charges are created. This method provides the ability
120
+ # to create these internal entities.
121
+ # It also provides the ability to modify existing Stripe entities.
122
+ id = attributes[:id]
123
+ if id.nil? || id == ""
124
+ # Insert new Stripe object
125
+ case object
126
+ when :balance_transaction
127
+ id = new_balance_transaction('txn', attributes)
128
+ else
129
+ raise UnsupportedRequestError.new "Unsupported stripe object `#{object}`"
130
+ end
131
+ else
132
+ # Update existing Stripe object
133
+ case object
134
+ when :balance_transaction
135
+ btxn = assert_existence :balance_transaction, id, @balance_transactions[id]
136
+ btxn.merge!(attributes)
137
+ else
138
+ raise UnsupportedRequestError.new "Unsupported stripe object `#{object}`"
139
+ end
140
+ end
141
+ id
142
+ end
143
+
116
144
  private
117
145
 
118
146
  def assert_existence(type, id, obj, message=nil)
@@ -135,6 +163,7 @@ module StripeMock
135
163
  unless amount.nil?
136
164
  # Fee calculation
137
165
  params[:fee] ||= (30 + (amount.abs * 0.029).ceil) * (amount > 0 ? 1 : -1)
166
+ params[:amount] = amount * @conversion_rate
138
167
  end
139
168
  @balance_transactions[id] = Data.mock_balance_transaction(params.merge(id: id))
140
169
  id
@@ -9,11 +9,27 @@ module StripeMock
9
9
 
10
10
  def get_balance_transaction(route, method_url, params, headers)
11
11
  route =~ method_url
12
- assert_existence :balance_transaction, $1, balance_transactions[$1]
12
+ assert_existence :balance_transaction, $1, hide_additional_attributes(balance_transactions[$1])
13
13
  end
14
14
 
15
15
  def list_balance_transactions(route, method_url, params, headers)
16
- Data.mock_list_object(balance_transactions.values, params)
16
+ values = balance_transactions.values
17
+ if params.has_key?(:transfer)
18
+ # If transfer supplied as params, need to filter the btxns returned to only include those with the specified transfer id
19
+ values = values.select{|btxn| btxn[:transfer] == params[:transfer]}
20
+ end
21
+ Data.mock_list_object(values.map{|btxn| hide_additional_attributes(btxn)}, params)
22
+ end
23
+
24
+ private
25
+
26
+ def hide_additional_attributes(btxn)
27
+ # For automatic Stripe transfers, the transfer attribute on balance_transaction stores the transfer which
28
+ # included this balance_transaction. However, it is not exposed as a field returned on a balance_transaction.
29
+ # Therefore, need to not show this attribute if it exists.
30
+ if !btxn.nil?
31
+ btxn.reject{|k,v| k == :transfer }
32
+ end
17
33
  end
18
34
 
19
35
  end
@@ -49,12 +49,13 @@ module StripeMock
49
49
  params.merge :id => id,
50
50
  :balance_transaction => balance_transaction_id)
51
51
 
52
+ charge = charges[id].clone
52
53
  if params[:expand] == ['balance_transaction']
53
- charges[id][:balance_transaction] =
54
+ charge[:balance_transaction] =
54
55
  balance_transactions[balance_transaction_id]
55
56
  end
56
57
 
57
- charges[id]
58
+ charge
58
59
  end
59
60
 
60
61
  def update_charge(route, method_url, params, headers)
@@ -87,7 +88,15 @@ module StripeMock
87
88
  def get_charge(route, method_url, params, headers)
88
89
  route =~ method_url
89
90
  charge_id = $1 || params[:charge]
90
- assert_existence :charge, charge_id, charges[charge_id]
91
+ charge = assert_existence :charge, charge_id, charges[charge_id]
92
+
93
+ charge = charge.clone
94
+ if params[:expand] == ['balance_transaction']
95
+ balance_transaction = balance_transactions[charge[:balance_transaction]]
96
+ charge[:balance_transaction] = balance_transaction
97
+ end
98
+
99
+ charge
91
100
  end
92
101
 
93
102
  def capture_charge(route, method_url, params, headers)
@@ -17,12 +17,12 @@ module StripeMock
17
17
 
18
18
  def get_coupon(route, method_url, params, headers)
19
19
  route =~ method_url
20
- assert_existence :id, $1, coupons[$1]
20
+ assert_existence :coupon, $1, coupons[$1]
21
21
  end
22
22
 
23
23
  def delete_coupon(route, method_url, params, headers)
24
24
  route =~ method_url
25
- assert_existence :id, $1, coupons.delete($1)
25
+ assert_existence :coupon, $1, coupons.delete($1)
26
26
  end
27
27
 
28
28
  def list_coupons(route, method_url, params, headers)
@@ -8,6 +8,7 @@ module StripeMock
8
8
  klass.add_handler 'get /v1/customers/([^/]*)', :get_customer
9
9
  klass.add_handler 'delete /v1/customers/([^/]*)', :delete_customer
10
10
  klass.add_handler 'get /v1/customers', :list_customers
11
+ klass.add_handler 'delete /v1/customers/([^/]*)/discount', :delete_customer_discount
11
12
  end
12
13
 
13
14
  def new_customer(route, method_url, params, headers)
@@ -114,6 +115,14 @@ module StripeMock
114
115
  Data.mock_list_object(customers.values, params)
115
116
  end
116
117
 
118
+ def delete_customer_discount(route, method_url, params, headers)
119
+ route =~ method_url
120
+ cus = assert_existence :customer, $1, customers[$1]
121
+
122
+ cus[:discount] = nil
123
+
124
+ cus
125
+ end
117
126
  end
118
127
  end
119
128
  end
@@ -77,6 +77,7 @@ module StripeMock
77
77
  is_customer = resource.has_key?(:sources)
78
78
  new_default = cards_or_sources[:data].count > 0 ? cards_or_sources[:data].first[:id] : nil
79
79
  resource[:default_card] = new_default unless is_customer
80
+ resource[:sources][:total_count] = cards_or_sources[:data].count if is_customer
80
81
  resource[:default_source] = new_default if is_customer
81
82
  card
82
83
  end
@@ -52,7 +52,8 @@ module StripeMock
52
52
  def pay_invoice(route, method_url, params, headers)
53
53
  route =~ method_url
54
54
  assert_existence :invoice, $1, invoices[$1]
55
- invoices[$1].merge!(:paid => true, :attempted => true, :charge => 'ch_1fD6uiR9FAA2zc')
55
+ charge = invoice_charge(invoices[$1])
56
+ invoices[$1].merge!(:paid => true, :attempted => true, :charge => charge[:id])
56
57
  end
57
58
 
58
59
  def upcoming_invoice(route, method_url, params, headers)
@@ -93,6 +94,16 @@ module StripeMock
93
94
  })
94
95
  end
95
96
 
97
+ ## charge the customer on the invoice, if one does not exist, create
98
+ #anonymous charge
99
+ def invoice_charge(invoice)
100
+ begin
101
+ new_charge(nil, nil, {customer: invoice[:customer]["id"], amount: invoice[:amount_due], currency: 'usd'}, nil)
102
+ rescue Stripe::InvalidRequestError
103
+ new_charge(nil, nil, {source: generate_card_token, amount: invoice[:amount_due], currency: 'usd'}, nil)
104
+ end
105
+ end
106
+
96
107
  end
97
108
  end
98
109
  end
@@ -45,7 +45,7 @@ module StripeMock
45
45
  end
46
46
  end
47
47
 
48
- if [:created, :paid, :canceled, :fulfilled, :returned].includes? params[:status]
48
+ if %w(created paid canceled fulfilled returned).include? params[:status]
49
49
  order[:status] = params[:status]
50
50
  end
51
51
  order
@@ -15,7 +15,7 @@ module StripeMock
15
15
  return refunds[original_refund[:id]] if original_refund
16
16
  end
17
17
 
18
- charge = get_charge(route, method_url, params, headers)
18
+ charge = assert_existence :charge, params[:charge], charges[params[:charge]]
19
19
  params[:amount] ||= charge[:amount]
20
20
  id = new_id('re')
21
21
  bal_trans_params = {
@@ -46,12 +46,12 @@ module StripeMock
46
46
  customer[:default_source] = new_card[:id]
47
47
  end
48
48
 
49
- # Ensure customer has card to charge if plan has no trial and is not free
50
- verify_card_present(customer, plan, params)
51
-
52
49
  subscription = Data.mock_subscription({ id: (params[:id] || new_id('su')) })
53
50
  subscription.merge!(custom_subscription_params(plan, customer, params))
54
51
 
52
+ # Ensure customer has card to charge if plan has no trial and is not free
53
+ verify_card_present(customer, plan, subscription, params)
54
+
55
55
  if params[:coupon]
56
56
  coupon_id = params[:coupon]
57
57
 
@@ -79,7 +79,8 @@ module StripeMock
79
79
  plan_id = params[:plan].to_s
80
80
  plan = assert_existence :plan, plan_id, plans[plan_id]
81
81
 
82
- customer_id = params[:customer].to_s
82
+ customer = params[:customer]
83
+ customer_id = customer.is_a?(Stripe::Customer) ? customer[:id] : customer.to_s
83
84
  customer = assert_existence :customer, customer_id, customers[customer_id]
84
85
 
85
86
  if params[:source]
@@ -88,12 +89,18 @@ module StripeMock
88
89
  customer[:default_source] = new_card[:id]
89
90
  end
90
91
 
91
- # Ensure customer has card to charge if plan has no trial and is not free
92
- verify_card_present(customer, plan, params)
92
+ allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days)
93
+ unknown_params = params.keys - allowed_params.map(&:to_sym)
94
+ if unknown_params.length > 0
95
+ raise Stripe::InvalidRequestError.new("Received unknown parameter: #{unknown_params.join}", unknown_params.first.to_s, 400)
96
+ end
93
97
 
94
98
  subscription = Data.mock_subscription({ id: (params[:id] || new_id('su')) })
95
99
  subscription.merge!(custom_subscription_params(plan, customer, params))
96
100
 
101
+ # Ensure customer has card to charge if plan has no trial and is not free
102
+ verify_card_present(customer, plan, subscription, params)
103
+
97
104
  if params[:coupon]
98
105
  coupon_id = params[:coupon]
99
106
 
@@ -169,7 +176,7 @@ module StripeMock
169
176
 
170
177
  assert_existence :plan, plan_name, plan
171
178
  params[:plan] = plan if params[:plan]
172
- verify_card_present(customer, plan)
179
+ verify_card_present(customer, plan, subscription)
173
180
 
174
181
  if subscription[:cancel_at_period_end]
175
182
  subscription[:cancel_at_period_end] = false
@@ -216,9 +223,8 @@ module StripeMock
216
223
 
217
224
  private
218
225
 
219
- def verify_card_present(customer, plan, params={})
220
- if customer[:default_source].nil? && customer[:trial_end].nil? && plan[:trial_period_days].nil? &&
221
- plan[:amount] != 0 && plan[:trial_end].nil? && params[:trial_end].nil?
226
+ def verify_card_present(customer, plan, subscription, params={})
227
+ if customer[:default_source].nil? && customer[:trial_end].nil? && plan[:trial_period_days].nil? && plan[:amount] != 0 && plan[:trial_end].nil? && params[:trial_end].nil? && (subscription.nil? || subscription[:trial_end].nil? || subscription[:trial_end] == 'now')
222
228
  raise Stripe::InvalidRequestError.new('You must supply a valid card xoxo', nil, 400)
223
229
  end
224
230
  end
@@ -65,6 +65,10 @@ module StripeMock
65
65
  @instance.generate_webhook_event(event_data)
66
66
  end
67
67
 
68
+ def set_conversion_rate(value)
69
+ @instance.conversion_rate = value
70
+ end
71
+
68
72
  def error_queue
69
73
  @instance.error_queue
70
74
  end
@@ -76,5 +80,10 @@ module StripeMock
76
80
  def ping
77
81
  true
78
82
  end
83
+
84
+ def upsert_stripe_object(object, attributes)
85
+ @instance.upsert_stripe_object(object, attributes)
86
+ end
87
+
79
88
  end
80
89
  end
@@ -30,6 +30,11 @@ module StripeMock
30
30
  # do nothing
31
31
  end
32
32
  end
33
+
34
+ def upsert_stripe_object(object, attributes)
35
+ raise UnsupportedRequestError.new "Updating or inserting Stripe objects in Live mode not supported"
36
+ end
37
+
33
38
  end
34
39
  end
35
40
  end
@@ -14,6 +14,14 @@ module StripeMock
14
14
  end
15
15
  end
16
16
 
17
+ def upsert_stripe_object(object, attributes = {})
18
+ if StripeMock.state == 'remote'
19
+ StripeMock.client.upsert_stripe_object(object, attributes)
20
+ elsif StripeMock.state == 'local'
21
+ StripeMock.instance.upsert_stripe_object(object, attributes)
22
+ end
23
+ end
24
+
17
25
  end
18
26
  end
19
27
  end
@@ -1,4 +1,4 @@
1
1
  module StripeMock
2
2
  # stripe-ruby-mock version
3
- VERSION = "2.4.0"
3
+ VERSION = "2.4.1"
4
4
  end
@@ -47,4 +47,9 @@ describe StripeMock::Instance do
47
47
  StripeMock.start
48
48
  expect(StripeMock.instance.debug).to eq(false)
49
49
  end
50
+
51
+ it "can set a conversion rate" do
52
+ StripeMock.set_conversion_rate(1.25)
53
+ expect(StripeMock.instance.conversion_rate).to eq(1.25)
54
+ end
50
55
  end
@@ -34,6 +34,20 @@ describe StripeMock::Data::List do
34
34
  expect(list.url).to eq("/v1/customers")
35
35
  end
36
36
 
37
+ it "returns in descending order if created available" do
38
+ charge_newer = Stripe::Charge.create(amount: 1, currency: 'usd', source: stripe_helper.generate_card_token, created: 5)
39
+ charge_older = Stripe::Charge.create(amount: 1, currency: 'usd', source: stripe_helper.generate_card_token, created: 4)
40
+ list = StripeMock::Data::List.new([charge_older, charge_newer])
41
+ hash = list.to_h
42
+
43
+ expect(hash).to eq(
44
+ object: "list",
45
+ data: [charge_newer, charge_older],
46
+ url: "/v1/charges",
47
+ has_more: false
48
+ )
49
+ end
50
+
37
51
  it "eventually gets turned into a hash" do
38
52
  charge1 = Stripe::Charge.create(amount: 1, currency: 'usd', source: stripe_helper.generate_card_token)
39
53
  charge2 = Stripe::Charge.create(amount: 1, currency: 'usd', source: stripe_helper.generate_card_token)
@@ -43,7 +57,7 @@ describe StripeMock::Data::List do
43
57
 
44
58
  expect(hash).to eq(
45
59
  object: "list",
46
- data: [charge1, charge2, charge3],
60
+ data: [charge3, charge2, charge1],
47
61
  url: "/v1/charges",
48
62
  has_more: false
49
63
  )
@@ -111,9 +125,8 @@ describe StripeMock::Data::List do
111
125
  data[89] = new_charge
112
126
  list = StripeMock::Data::List.new(data, starting_after: new_charge.id)
113
127
  hash = list.to_h
114
-
115
128
  expect(hash[:data].size).to eq(10)
116
- expect(hash[:data]).to eq(data[90, 10])
129
+ expect(hash[:data]).to eq(data[79, 10].reverse)
117
130
  end
118
131
 
119
132
  it "raises an error if starting_after cursor is not found" do
@@ -132,4 +132,8 @@ describe 'StripeMock Server', :mock_server => true do
132
132
  end
133
133
  end
134
134
 
135
+ it "can set a conversion rate" do
136
+ StripeMock.set_conversion_rate(1.2)
137
+ expect(StripeMock.client.get_conversion_rate).to eq(1.2)
138
+ end
135
139
  end
@@ -2,6 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  shared_examples 'Balance Transaction API' do
4
4
 
5
+ let(:stripe_helper) { StripeMock.create_test_helper }
6
+
5
7
  it "returns an error if balance transaction does not exist" do
6
8
  txn_id = 'txn_xxxxxxxxxxxxxxxxxxxxxxxx'
7
9
 
@@ -32,4 +34,30 @@ shared_examples 'Balance Transaction API' do
32
34
 
33
35
  end
34
36
 
37
+ it 'retrieves balance transactions for an automated transfer' do
38
+ transfer_id = Stripe::Transfer.create({ amount: 2730, currency: "usd" })
39
+
40
+ # verify transfer currently has no balance transactions
41
+ transfer_transactions = Stripe::BalanceTransaction.all({transfer: transfer_id})
42
+ expect(transfer_transactions.count).to eq(0)
43
+
44
+ # verify we can create a new balance transaction associated with the transfer
45
+ new_txn_id = stripe_helper.upsert_stripe_object(:balance_transaction, {amount: 12300, transfer: transfer_id})
46
+ new_txn = Stripe::BalanceTransaction.retrieve(new_txn_id)
47
+ expect(new_txn).to be_a(Stripe::BalanceTransaction)
48
+ expect(new_txn.amount).to eq(12300)
49
+ # although transfer was specified as an attribute on the balance_transaction, it should not be returned in the object
50
+ expect{new_txn.transfer}.to raise_error(NoMethodError)
51
+
52
+ # verify we can update an existing balance transaction to associate with the transfer
53
+ existing_txn_id = 'txn_05RsQX2eZvKYlo2C0FRTGSSA'
54
+ existing_txn = Stripe::BalanceTransaction.retrieve(existing_txn_id)
55
+ stripe_helper.upsert_stripe_object(:balance_transaction, {id: existing_txn_id, transfer: transfer_id})
56
+
57
+ # now verify that only these balance transactions are retrieved with the transfer
58
+ transfer_transactions = Stripe::BalanceTransaction.all({transfer: transfer_id})
59
+ expect(transfer_transactions.count).to eq(2)
60
+ expect(transfer_transactions.map &:id).to include(new_txn_id, existing_txn_id)
61
+ end
62
+
35
63
  end
@@ -166,6 +166,13 @@ shared_examples 'Card API' do
166
166
  expect(retrieved_cus.default_source).to be_nil
167
167
  end
168
168
 
169
+ it 'updates total_count if deleted' do
170
+ card.delete
171
+ sources = Stripe::Customer.retrieve(customer.id).sources
172
+
173
+ expect(sources.total_count).to eq 0
174
+ end
175
+
169
176
  context "deletion when the user has two cards" do
170
177
  let!(:card_token_2) { stripe_helper.generate_card_token(last4: "1123", exp_month: 11, exp_year: 2099) }
171
178
  let!(:card_2) { customer.sources.create(source: card_token_2) }
@@ -174,7 +174,23 @@ shared_examples 'Charge API' do
174
174
  expect(bal_trans.source).to eq(charge.source)
175
175
  end
176
176
 
177
- it "can expand balance transaction" do
177
+ context 'when conversion rate is set' do
178
+ it "balance transaction stores amount converted from charge currency to USD" do
179
+ StripeMock.set_conversion_rate(1.2)
180
+
181
+ charge = Stripe::Charge.create({
182
+ amount: 300,
183
+ currency: 'CAD',
184
+ source: stripe_helper.generate_card_token
185
+ })
186
+ bal_trans = Stripe::BalanceTransaction.retrieve(charge.balance_transaction)
187
+ expect(bal_trans.amount).to eq(charge.amount * 1.2)
188
+ expect(bal_trans.fee).to eq(39)
189
+ expect(bal_trans.currency).to eq('usd')
190
+ end
191
+ end
192
+
193
+ it "can expand balance transaction when creating a charge" do
178
194
  charge = Stripe::Charge.create({
179
195
  amount: 300,
180
196
  currency: 'USD',
@@ -196,6 +212,20 @@ shared_examples 'Charge API' do
196
212
  expect(charge.amount).to eq(original.amount)
197
213
  end
198
214
 
215
+ it "can expand balance transaction when retrieving a charge" do
216
+ original = Stripe::Charge.create({
217
+ amount: 300,
218
+ currency: 'USD',
219
+ source: stripe_helper.generate_card_token
220
+ })
221
+ charge = Stripe::Charge.retrieve(
222
+ id: original.id,
223
+ expand: ['balance_transaction']
224
+ )
225
+
226
+ expect(charge.balance_transaction).to be_a(Stripe::BalanceTransaction)
227
+ end
228
+
199
229
  it "cannot retrieve a charge that doesn't exist" do
200
230
  expect { Stripe::Charge.retrieve('nope') }.to raise_error {|e|
201
231
  expect(e).to be_a Stripe::InvalidRequestError
@@ -310,7 +340,7 @@ shared_examples 'Charge API' do
310
340
  end
311
341
 
312
342
  it "stores all charges in memory" do
313
- expect(Stripe::Charge.all.data.map(&:id)).to eq([@charge.id, @charge2.id])
343
+ expect(Stripe::Charge.all.data.map(&:id).reverse).to eq([@charge.id, @charge2.id])
314
344
  end
315
345
 
316
346
  it "defaults count to 10 charges" do
@@ -56,7 +56,7 @@ shared_examples 'Coupon API' do
56
56
  it "cannot retrieve a stripe coupon that doesn't exist" do
57
57
  expect { Stripe::Coupon.retrieve('nope') }.to raise_error {|e|
58
58
  expect(e).to be_a Stripe::InvalidRequestError
59
- expect(e.param).to eq('id')
59
+ expect(e.param).to eq('coupon')
60
60
  expect(e.http_status).to eq(404)
61
61
  }
62
62
  end
@@ -71,7 +71,7 @@ shared_examples 'Coupon API' do
71
71
 
72
72
  expect { Stripe::Coupon.retrieve(coupon.id) }.to raise_error {|e|
73
73
  expect(e).to be_a Stripe::InvalidRequestError
74
- expect(e.param).to eq('id')
74
+ expect(e.param).to eq('coupon')
75
75
  expect(e.http_status).to eq(404)
76
76
  }
77
77
  end
@@ -387,4 +387,18 @@ shared_examples 'Customer API' do
387
387
  }.not_to raise_error
388
388
  end
389
389
 
390
+ it "deletes a stripe customer discount" do
391
+ original = Stripe::Customer.create(id: 'test_customer_update')
392
+
393
+ coupon = Stripe::Coupon.create(id: "10PERCENT", duration: 'once')
394
+ original.coupon = coupon.id
395
+ original.save
396
+
397
+ expect(original.discount.coupon).to be_a Stripe::Coupon
398
+
399
+ original.delete_discount
400
+
401
+ customer = Stripe::Customer.retrieve("test_customer_update")
402
+ expect(customer.discount).to be nil
403
+ end
390
404
  end
@@ -79,7 +79,7 @@ shared_examples 'Dispute API' do
79
79
  disputes = Stripe::Dispute.all(limit: 3)
80
80
 
81
81
  expect(disputes.count).to eq(3)
82
- expect(disputes.map &:id).to include('dp_05RsQX2eZvKYlo2C0FRTGSSA','dp_15RsQX2eZvKYlo2C0ERTYUIA', 'dp_25RsQX2eZvKYlo2C0ZXCVBNM')
82
+ expect(disputes.map &:id).to include('dp_95RsQX2eZvKYlo2C0EDFRYUI','dp_85RsQX2eZvKYlo2C0UJMCDET', 'dp_75RsQX2eZvKYlo2C0EDCXSWQ')
83
83
  end
84
84
 
85
85
  end
@@ -76,18 +76,34 @@ shared_examples 'Invoice API' do
76
76
  context "paying an invoice" do
77
77
  before do
78
78
  @invoice = Stripe::Invoice.create
79
- @invoice.pay
80
79
  end
81
80
 
82
81
  it 'updates attempted and paid flags' do
82
+ @invoice.pay
83
83
  expect(@invoice.attempted).to eq(true)
84
84
  expect(@invoice.paid).to eq(true)
85
85
  end
86
86
 
87
+ it 'creates a new charge object' do
88
+ expect{ @invoice.pay }.to change { Stripe::Charge.list.data.count }.by 1
89
+ end
90
+
87
91
  it 'sets the charge attribute' do
92
+ @invoice.pay
88
93
  expect(@invoice.charge).to be_a String
89
94
  expect(@invoice.charge.length).to be > 0
90
95
  end
96
+
97
+ it 'charges the invoice customers default card' do
98
+ customer = Stripe::Customer.create({
99
+ source: stripe_helper.generate_card_token
100
+ })
101
+ customer_invoice = Stripe::Invoice.create({customer: customer})
102
+
103
+ customer_invoice.pay
104
+
105
+ expect(Stripe::Charge.list.data.first.customer).to eq customer.id
106
+ end
91
107
  end
92
108
 
93
109
  context "retrieving upcoming invoice" do
@@ -262,7 +262,7 @@ shared_examples 'Refund API' do
262
262
  end
263
263
 
264
264
  it "stores all charges in memory" do
265
- expect(Stripe::Refund.all.data.map(&:id)).to eq([@refund.id, @refund2.id])
265
+ expect(Stripe::Refund.all.data.map(&:id)).to eq([@refund2.id, @refund.id])
266
266
  end
267
267
 
268
268
  it "defaults count to 10 charges" do
@@ -35,6 +35,36 @@ shared_examples 'Customer Subscriptions' do
35
35
  expect(customer.subscriptions.data.first.metadata.example).to eq( "yes" )
36
36
  end
37
37
 
38
+ it 'when customer object provided' do
39
+ plan = stripe_helper.create_plan(id: 'silver', name: 'Silver Plan', amount: 4999, currency: 'usd')
40
+ customer = Stripe::Customer.create(source: gen_card_tk)
41
+
42
+ expect(customer.subscriptions.data).to be_empty
43
+ expect(customer.subscriptions.count).to eq(0)
44
+
45
+ sub = Stripe::Subscription.create({ plan: 'silver', customer: customer, metadata: { foo: "bar", example: "yes" } })
46
+
47
+ expect(sub.object).to eq('subscription')
48
+ expect(sub.plan.to_hash).to eq(plan.to_hash)
49
+ expect(sub.metadata.foo).to eq( "bar" )
50
+ expect(sub.metadata.example).to eq( "yes" )
51
+
52
+ customer = Stripe::Customer.retrieve(customer.id)
53
+ expect(customer.subscriptions.data).to_not be_empty
54
+ expect(customer.subscriptions.count).to eq(1)
55
+ expect(customer.subscriptions.data.length).to eq(1)
56
+ expect(customer.charges.data.length).to eq(1)
57
+ expect(customer.currency).to eq( "usd" )
58
+
59
+ expect(customer.subscriptions.data.first.id).to eq(sub.id)
60
+ expect(customer.subscriptions.data.first.plan.to_hash).to eq(plan.to_hash)
61
+
62
+ expect(customer.subscriptions.data.first.customer).to eq(customer.id)
63
+
64
+ expect(customer.subscriptions.data.first.metadata.foo).to eq( "bar" )
65
+ expect(customer.subscriptions.data.first.metadata.example).to eq( "yes" )
66
+ end
67
+
38
68
  it "adds a new subscription to customer (string/symbol agnostic)" do
39
69
  customer = Stripe::Customer.create(source: gen_card_tk)
40
70
  expect(customer.subscriptions.count).to eq(0)
@@ -185,6 +215,18 @@ shared_examples 'Customer Subscriptions' do
185
215
  }
186
216
  end
187
217
 
218
+ it 'when attempting to create a new subscription with the params trial', focus: true, live: true do
219
+ plan = stripe_helper.create_plan(id: 'trial', amount: 999)
220
+ customer = Stripe::Customer.create(source: gen_card_tk)
221
+
222
+ expect{ Stripe::Subscription.create(plan: plan.id, customer: customer.id, trial: 10) }.to raise_error {|e|
223
+ expect(e).to be_a Stripe::InvalidRequestError
224
+ expect(e.http_status).to eq(400)
225
+ expect(e.param).to eq('trial')
226
+ expect(e.message).to match /Received unknown parameter/
227
+ }
228
+ end
229
+
188
230
  it "subscribes a customer with no card to a plan with a free trial" do
189
231
  plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14)
190
232
  customer = Stripe::Customer.create(id: 'cardless')
@@ -78,4 +78,20 @@ shared_examples 'Transfer API' do
78
78
  expect(e.http_status).to eq(400)
79
79
  }
80
80
  end
81
+
82
+ it 'when amount is negative', focus: true, live: true do
83
+ rec = Stripe::Recipient.create({
84
+ type: 'individual',
85
+ name: 'Alex Smith',
86
+ })
87
+ expect { Stripe::Transfer.create(amount: '-400',
88
+ currency: 'usd',
89
+ recipient: rec.id,
90
+ description: 'Transfer for test@example.com') }.to raise_error { |e|
91
+ expect(e).to be_a Stripe::InvalidRequestError
92
+ expect(e.param).to eq('amount')
93
+ expect(e.message).to match(/^Invalid.*integer/)
94
+ expect(e.http_status).to eq(400)
95
+ }
96
+ end
81
97
  end
@@ -183,8 +183,8 @@ shared_examples 'Webhook Events API' do
183
183
  events = Stripe::Event.all(limit: 3)
184
184
 
185
185
  expect(events.count).to eq(3)
186
- expect(events.map &:id).to include(customer_created_event.id, plan_created_event.id, coupon_created_event.id)
187
- expect(events.map &:type).to include('customer.created', 'plan.created', 'coupon.created')
186
+ expect(events.map &:id).to include(invoice_item_created_event.id, invoice_created_event.id, coupon_created_event.id)
187
+ expect(events.map &:type).to include('invoiceitem.created', 'invoice.created', 'coupon.created')
188
188
  end
189
189
 
190
190
  end
@@ -46,7 +46,7 @@ RSpec.configure do |c|
46
46
  StripeMock.stub(:stop).and_return(nil)
47
47
  Stripe.api_key = api_key
48
48
  end
49
- c.after(:each) { sleep 1 }
49
+ c.after(:each) { sleep 0.01 }
50
50
  else
51
51
  c.filter_run_excluding :oauth => true
52
52
  Stripe.api_key ||= ''
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ['lib']
19
19
 
20
- gem.add_dependency 'stripe', '~> 1.31'
20
+ gem.add_dependency 'stripe', ['>= 1.31.0', '<= 1.58.0']
21
21
  gem.add_dependency 'multi_json', '~> 1.0'
22
22
  gem.add_dependency 'dante', '>= 0.2.0'
23
23
 
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stripe-ruby-mock
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gilbert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-10 00:00:00.000000000 Z
11
+ date: 2017-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: stripe
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.31.0
20
+ - - <=
18
21
  - !ruby/object:Gem::Version
19
- version: '1.31'
22
+ version: 1.58.0
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - ~>
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.31.0
30
+ - - <=
25
31
  - !ruby/object:Gem::Version
26
- version: '1.31'
32
+ version: 1.58.0
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: multi_json
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -101,6 +107,7 @@ executables:
101
107
  extensions: []
102
108
  extra_rdoc_files: []
103
109
  files:
110
+ - .env
104
111
  - .gitignore
105
112
  - .rspec
106
113
  - .travis.yml
@@ -114,6 +121,7 @@ files:
114
121
  - lib/stripe_mock/api/bank_tokens.rb
115
122
  - lib/stripe_mock/api/card_tokens.rb
116
123
  - lib/stripe_mock/api/client.rb
124
+ - lib/stripe_mock/api/conversion_rate.rb
117
125
  - lib/stripe_mock/api/debug.rb
118
126
  - lib/stripe_mock/api/errors.rb
119
127
  - lib/stripe_mock/api/global_id_prefix.rb