stripe 1.30.3 → 2.0.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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +4 -0
  3. data/.github/ISSUE_TEMPLATE.md +5 -0
  4. data/.travis.yml +3 -14
  5. data/Gemfile +28 -4
  6. data/History.txt +180 -0
  7. data/README.md +147 -0
  8. data/Rakefile +10 -0
  9. data/VERSION +1 -1
  10. data/bin/stripe-console +12 -5
  11. data/lib/data/ca-certificates.crt +3868 -5114
  12. data/lib/stripe/account.rb +43 -23
  13. data/lib/stripe/alipay_account.rb +20 -0
  14. data/lib/stripe/api_operations/create.rb +2 -2
  15. data/lib/stripe/api_operations/delete.rb +2 -2
  16. data/lib/stripe/api_operations/list.rb +2 -3
  17. data/lib/stripe/api_operations/request.rb +9 -3
  18. data/lib/stripe/api_operations/save.rb +85 -0
  19. data/lib/stripe/api_resource.rb +38 -5
  20. data/lib/stripe/apple_pay_domain.rb +12 -0
  21. data/lib/stripe/application_fee.rb +8 -8
  22. data/lib/stripe/application_fee_refund.rb +7 -3
  23. data/lib/stripe/balance_transaction.rb +1 -1
  24. data/lib/stripe/bank_account.rb +13 -4
  25. data/lib/stripe/bitcoin_receiver.rb +6 -6
  26. data/lib/stripe/bitcoin_transaction.rb +1 -1
  27. data/lib/stripe/card.rb +9 -5
  28. data/lib/stripe/charge.rb +38 -20
  29. data/lib/stripe/country_spec.rb +9 -0
  30. data/lib/stripe/coupon.rb +1 -1
  31. data/lib/stripe/customer.rb +12 -10
  32. data/lib/stripe/dispute.rb +4 -5
  33. data/lib/stripe/errors.rb +92 -0
  34. data/lib/stripe/file_upload.rb +1 -1
  35. data/lib/stripe/invoice.rb +7 -7
  36. data/lib/stripe/invoice_item.rb +1 -1
  37. data/lib/stripe/list_object.rb +8 -7
  38. data/lib/stripe/order.rb +12 -4
  39. data/lib/stripe/order_return.rb +9 -0
  40. data/lib/stripe/plan.rb +1 -1
  41. data/lib/stripe/product.rb +2 -10
  42. data/lib/stripe/recipient.rb +1 -1
  43. data/lib/stripe/refund.rb +1 -1
  44. data/lib/stripe/reversal.rb +7 -3
  45. data/lib/stripe/singleton_api_resource.rb +3 -3
  46. data/lib/stripe/sku.rb +2 -2
  47. data/lib/stripe/source.rb +11 -0
  48. data/lib/stripe/stripe_client.rb +396 -0
  49. data/lib/stripe/stripe_object.rb +167 -91
  50. data/lib/stripe/stripe_response.rb +48 -0
  51. data/lib/stripe/subscription.rb +15 -9
  52. data/lib/stripe/subscription_item.rb +12 -0
  53. data/lib/stripe/three_d_secure.rb +9 -0
  54. data/lib/stripe/transfer.rb +4 -5
  55. data/lib/stripe/util.rb +105 -33
  56. data/lib/stripe/version.rb +1 -1
  57. data/lib/stripe.rb +69 -266
  58. data/spec/fixtures.json +1409 -0
  59. data/spec/fixtures.yaml +1153 -0
  60. data/spec/spec.json +19949 -0
  61. data/spec/spec.yaml +15504 -0
  62. data/stripe.gemspec +5 -18
  63. data/test/api_fixtures.rb +29 -0
  64. data/test/api_stub_helpers.rb +125 -0
  65. data/test/stripe/account_test.rb +163 -211
  66. data/test/stripe/alipay_account_test.rb +19 -0
  67. data/test/stripe/api_operations_test.rb +31 -0
  68. data/test/stripe/api_resource_test.rb +174 -340
  69. data/test/stripe/apple_pay_domain_test.rb +33 -0
  70. data/test/stripe/application_fee_refund_test.rb +22 -31
  71. data/test/stripe/application_fee_test.rb +6 -14
  72. data/test/stripe/balance_test.rb +3 -3
  73. data/test/stripe/bank_account_test.rb +41 -0
  74. data/test/stripe/bitcoin_receiver_test.rb +51 -42
  75. data/test/stripe/bitcoin_transaction_test.rb +11 -19
  76. data/test/stripe/charge_test.rb +39 -98
  77. data/test/stripe/country_spec_test.rb +20 -0
  78. data/test/stripe/coupon_test.rb +35 -11
  79. data/test/stripe/customer_card_test.rb +25 -46
  80. data/test/stripe/customer_test.rb +89 -61
  81. data/test/stripe/dispute_test.rb +28 -31
  82. data/test/stripe/errors_test.rb +18 -0
  83. data/test/stripe/file_upload_test.rb +32 -24
  84. data/test/stripe/invoice_item_test.rb +55 -0
  85. data/test/stripe/invoice_test.rb +50 -24
  86. data/test/stripe/list_object_test.rb +57 -45
  87. data/test/stripe/order_return_test.rb +21 -0
  88. data/test/stripe/order_test.rb +41 -34
  89. data/test/stripe/plan_test.rb +52 -0
  90. data/test/stripe/product_test.rb +31 -25
  91. data/test/stripe/recipient_card_test.rb +23 -40
  92. data/test/stripe/recipient_test.rb +50 -0
  93. data/test/stripe/refund_test.rb +20 -36
  94. data/test/stripe/reversal_test.rb +27 -31
  95. data/test/stripe/sku_test.rb +39 -13
  96. data/test/stripe/source_test.rb +43 -0
  97. data/test/stripe/stripe_client_test.rb +428 -0
  98. data/test/stripe/stripe_object_test.rb +186 -13
  99. data/test/stripe/stripe_response_test.rb +46 -0
  100. data/test/stripe/subscription_item_test.rb +54 -0
  101. data/test/stripe/subscription_test.rb +40 -52
  102. data/test/stripe/three_d_secure_test.rb +23 -0
  103. data/test/stripe/transfer_test.rb +38 -13
  104. data/test/stripe/util_test.rb +48 -16
  105. data/test/stripe_test.rb +25 -0
  106. data/test/test_data.rb +5 -621
  107. data/test/test_helper.rb +24 -24
  108. metadata +60 -139
  109. data/README.rdoc +0 -68
  110. data/gemfiles/default-with-activesupport.gemfile +0 -10
  111. data/gemfiles/json.gemfile +0 -12
  112. data/gemfiles/yajl.gemfile +0 -12
  113. data/lib/stripe/api_operations/update.rb +0 -58
  114. data/lib/stripe/errors/api_connection_error.rb +0 -4
  115. data/lib/stripe/errors/api_error.rb +0 -4
  116. data/lib/stripe/errors/authentication_error.rb +0 -4
  117. data/lib/stripe/errors/card_error.rb +0 -12
  118. data/lib/stripe/errors/invalid_request_error.rb +0 -11
  119. data/lib/stripe/errors/rate_limit_error.rb +0 -4
  120. data/lib/stripe/errors/stripe_error.rb +0 -26
  121. data/test/stripe/charge_refund_test.rb +0 -55
  122. data/test/stripe/metadata_test.rb +0 -129
@@ -3,31 +3,51 @@ require File.expand_path('../../test_helper', __FILE__)
3
3
 
4
4
  module Stripe
5
5
  class ApiResourceTest < Test::Unit::TestCase
6
+ class NestedTestAPIResource < Stripe::APIResource
7
+ save_nested_resource :external_account
8
+ end
9
+
10
+ context ".save_nested_resource" do
11
+ should "can have a scalar set" do
12
+ r = NestedTestAPIResource.new("test_resource")
13
+ r.external_account = "tok_123"
14
+ assert_equal "tok_123", r.external_account
15
+ end
16
+
17
+ should "set a flag if given an object source" do
18
+ r = NestedTestAPIResource.new("test_resource")
19
+ r.external_account = {
20
+ :object => 'card'
21
+ }
22
+ assert_equal true, r.external_account.save_with_parent
23
+ end
24
+ end
25
+
6
26
  should "creating a new APIResource should not fetch over the network" do
7
- @mock.expects(:get).never
8
27
  Stripe::Customer.new("someid")
28
+ assert_not_requested :get, %r{#{Stripe.api_base}/.*}
9
29
  end
10
30
 
11
31
  should "creating a new APIResource from a hash should not fetch over the network" do
12
- @mock.expects(:get).never
13
32
  Stripe::Customer.construct_from({
14
33
  :id => "somecustomer",
15
34
  :card => {:id => "somecard", :object => "card"},
16
35
  :object => "customer"
17
36
  })
37
+ assert_not_requested :get, %r{#{Stripe.api_base}/.*}
18
38
  end
19
39
 
20
40
  should "setting an attribute should not cause a network request" do
21
- @mock.expects(:get).never
22
- @mock.expects(:post).never
23
41
  c = Stripe::Customer.new("test_customer");
24
42
  c.card = {:id => "somecard", :object => "card"}
43
+ assert_not_requested :get, %r{#{Stripe.api_base}/.*}
44
+ assert_not_requested :post, %r{#{Stripe.api_base}/.*}
25
45
  end
26
46
 
27
47
  should "accessing id should not issue a fetch" do
28
- @mock.expects(:get).never
29
48
  c = Stripe::Customer.new("test_customer")
30
49
  c.id
50
+ assert_not_requested :get, %r{#{Stripe.api_base}/.*}
31
51
  end
32
52
 
33
53
  should "not specifying api credentials should raise an exception" do
@@ -53,129 +73,41 @@ module Stripe
53
73
  end
54
74
  end
55
75
 
56
- should "specifying invalid api credentials should raise an exception" do
57
- Stripe.api_key = "invalid"
58
- response = make_response(make_invalid_api_key_error, 401)
59
- assert_raises Stripe::AuthenticationError do
60
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
61
- Stripe::Customer.retrieve("failing_customer")
62
- end
63
- end
64
-
65
- should "AuthenticationErrors should have an http status, http body, and JSON body" do
66
- Stripe.api_key = "invalid"
67
- response = make_response(make_invalid_api_key_error, 401)
68
- begin
69
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
70
- Stripe::Customer.retrieve("failing_customer")
71
- rescue Stripe::AuthenticationError => e
72
- assert_equal(401, e.http_status)
73
- assert_equal(true, !!e.http_body)
74
- assert_equal(true, !!e.json_body[:error][:message])
75
- assert_equal(make_invalid_api_key_error[:error][:message], e.json_body[:error][:message])
76
- end
77
- end
78
-
79
76
  should "send expand on fetch properly" do
80
- @mock.expects(:get).once.
81
- with("#{Stripe.api_base}/v1/charges/ch_test_charge?expand[]=customer", nil, nil).
82
- returns(make_response(make_charge))
77
+ stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_test_charge").
78
+ with(query: { "expand" => ["customer"] }).
79
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:charge)))
83
80
 
84
81
  Stripe::Charge.retrieve({:id => 'ch_test_charge', :expand => [:customer]})
85
82
  end
86
83
 
87
84
  should "preserve expand across refreshes" do
88
- @mock.expects(:get).twice.
89
- with("#{Stripe.api_base}/v1/charges/ch_test_charge?expand[]=customer", nil, nil).
90
- returns(make_response(make_charge))
85
+ stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_test_charge").
86
+ with(query: { "expand" => ["customer"] }).
87
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:charge)))
91
88
 
92
89
  ch = Stripe::Charge.retrieve({:id => 'ch_test_charge', :expand => [:customer]})
93
90
  ch.refresh
94
91
  end
95
92
 
96
93
  should "send expand when fetching through ListObject" do
97
- @mock.expects(:get).once.
98
- with("#{Stripe.api_base}/v1/customers/c_test_customer", nil, nil).
99
- returns(make_response(make_customer))
94
+ stub_request(:get, "#{Stripe.api_base}/v1/customers/c_test_customer").
95
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
100
96
 
101
- @mock.expects(:get).once.
102
- with("#{Stripe.api_base}/v1/customers/c_test_customer/sources/cc_test_card?expand[]=customer", nil, nil).
103
- returns(make_response(make_card))
97
+ stub_request(:get, "#{Stripe.api_base}/v1/customers/c_test_customer/sources/cc_test_card").
98
+ with(query: { "expand" => ["customer"] }).
99
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
104
100
 
105
101
  customer = Stripe::Customer.retrieve('c_test_customer')
106
102
  customer.sources.retrieve({:id => 'cc_test_card', :expand => [:customer]})
107
103
  end
108
104
 
109
- should "send stripe account as header when set" do
110
- stripe_account = "acct_0000"
111
- Stripe.expects(:execute_request).with do |opts|
112
- opts[:headers][:stripe_account] == stripe_account
113
- end.returns(make_response(make_charge))
114
-
115
- Stripe::Charge.create({:card => {:number => '4242424242424242'}},
116
- {:stripe_account => stripe_account, :api_key => 'sk_test_local'})
117
- end
118
-
119
- should "not send stripe account as header when not set" do
120
- Stripe.expects(:execute_request).with do |opts|
121
- opts[:headers][:stripe_account].nil?
122
- end.returns(make_response(make_charge))
123
-
124
- Stripe::Charge.create({:card => {:number => '4242424242424242'}},
125
- 'sk_test_local')
126
- end
127
-
128
- should "handle error response with empty body" do
129
- response = make_response('', 500)
130
- @mock.expects(:post).once.raises(RestClient::ExceptionWithResponse.new(response, 500))
131
-
132
- e = assert_raises Stripe::APIError do
133
- Stripe::Charge.create
134
- end
135
-
136
- assert_equal 'Invalid response object from API: "" (HTTP response code was 500)', e.message
137
- end
138
-
139
- should "handle error response with non-object error value" do
140
- response = make_response('{"error": "foo"}', 500)
141
- @mock.expects(:post).once.raises(RestClient::ExceptionWithResponse.new(response, 500))
142
-
143
- e = assert_raises Stripe::APIError do
144
- Stripe::Charge.create
145
- end
146
-
147
- assert_equal 'Invalid response object from API: "{\"error\": \"foo\"}" (HTTP response code was 500)', e.message
148
- end
149
-
150
- should "have default open and read timeouts" do
151
- assert_equal Stripe.open_timeout, 30
152
- assert_equal Stripe.read_timeout, 80
153
- end
154
-
155
- should "allow configurable open and read timeouts" do
156
- original_timeouts = Stripe.open_timeout, Stripe.read_timeout
157
-
158
- begin
159
- Stripe.open_timeout = 999
160
- Stripe.read_timeout = 998
161
-
162
- Stripe.expects(:execute_request).with do |opts|
163
- opts[:open_timeout] == 999 && opts[:timeout] == 998
164
- end.returns(make_response(make_charge))
165
-
166
- Stripe::Charge.create({:card => {:number => '4242424242424242'}},
167
- 'sk_test_local')
168
- ensure
169
- Stripe.open_timeout, Stripe.read_timeout = original_timeouts
170
- end
171
- end
172
-
173
105
  context "when specifying per-object credentials" do
174
106
  context "with no global API key set" do
175
107
  should "use the per-object credential when creating" do
176
- Stripe.expects(:execute_request).with do |opts|
177
- opts[:headers][:authorization] == 'Bearer sk_test_local'
178
- end.returns(make_response(make_charge))
108
+ stub_request(:post, "#{Stripe.api_base}/v1/charges").
109
+ with(headers: {"Authorization" => "Bearer sk_test_local"}).
110
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:charge)))
179
111
 
180
112
  Stripe::Charge.create({:card => {:number => '4242424242424242'}},
181
113
  'sk_test_local')
@@ -192,138 +124,72 @@ module Stripe
192
124
  end
193
125
 
194
126
  should "use the per-object credential when creating" do
195
- Stripe.expects(:execute_request).with do |opts|
196
- opts[:headers][:authorization] == 'Bearer local'
197
- end.returns(make_response(make_charge))
127
+ stub_request(:post, "#{Stripe.api_base}/v1/charges").
128
+ with(headers: {"Authorization" => "Bearer local"}).
129
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:charge)))
198
130
 
199
131
  Stripe::Charge.create({:card => {:number => '4242424242424242'}},
200
132
  'local')
201
133
  end
202
134
 
203
135
  should "use the per-object credential when retrieving and making other calls" do
204
- Stripe.expects(:execute_request).with do |opts|
205
- opts[:url] == "#{Stripe.api_base}/v1/charges/ch_test_charge" &&
206
- opts[:headers][:authorization] == 'Bearer local'
207
- end.returns(make_response(make_charge))
208
- Stripe.expects(:execute_request).with do |opts|
209
- opts[:url] == "#{Stripe.api_base}/v1/charges/ch_test_charge/refund" &&
210
- opts[:headers][:authorization] == 'Bearer local'
211
- end.returns(make_response(make_charge))
136
+ stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_test_charge").
137
+ with(headers: {"Authorization" => "Bearer local"}).
138
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:charge)))
139
+ stub_request(:post, "#{Stripe.api_base}/v1/charges/ch_test_charge/refunds").
140
+ with(headers: {"Authorization" => "Bearer local"}).
141
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:refund)))
212
142
 
213
143
  ch = Stripe::Charge.retrieve('ch_test_charge', 'local')
214
- ch.refund
144
+ ch.refunds.create
215
145
  end
216
146
  end
217
147
  end
218
148
 
219
149
  context "with valid credentials" do
220
- should "send along the idempotency-key header" do
221
- Stripe.expects(:execute_request).with do |opts|
222
- opts[:headers][:idempotency_key] == 'bar'
223
- end.returns(make_response(make_charge))
224
-
225
- Stripe::Charge.create({:card => {:number => '4242424242424242'}}, {
226
- :idempotency_key => 'bar',
227
- :api_key => 'local',
228
- })
229
- end
230
-
231
150
  should "urlencode values in GET params" do
232
- response = make_response(make_charge_array)
233
- @mock.expects(:get).with("#{Stripe.api_base}/v1/charges?customer=test+customer", nil, nil).returns(response)
151
+ stub_request(:get, "#{Stripe.api_base}/v1/charges").
152
+ with(query: { customer: "test customer" }).
153
+ to_return(body: JSON.generate({
154
+ data: [API_FIXTURES.fetch(:charge)]
155
+ }))
234
156
  charges = Stripe::Charge.list(:customer => 'test customer').data
235
157
  assert charges.kind_of? Array
236
158
  end
237
159
 
238
160
  should "construct URL properly with base query parameters" do
239
- response = make_response(make_invoice_customer_array)
240
- @mock.expects(:get).with("#{Stripe.api_base}/v1/invoices?customer=test_customer", nil, nil).returns(response)
161
+ stub_request(:get, "#{Stripe.api_base}/v1/invoices").
162
+ with(query: { customer: "test_customer" }).
163
+ to_return(body: JSON.generate({
164
+ data: [API_FIXTURES.fetch(:invoice)],
165
+ url: "/v1/invoices"
166
+ }))
241
167
  invoices = Stripe::Invoice.list(:customer => 'test_customer')
242
168
 
243
- @mock.expects(:get).with("#{Stripe.api_base}/v1/invoices?customer=test_customer&paid=true", nil, nil).returns(response)
169
+ stub_request(:get, "#{Stripe.api_base}/v1/invoices").
170
+ with(query: { customer: "test_customer", paid: "true" }).
171
+ to_return(body: JSON.generate({
172
+ data: [API_FIXTURES.fetch(:invoice)],
173
+ url: "/v1/invoices"
174
+ }))
244
175
  invoices.list(:paid => true)
245
176
  end
246
177
 
247
- should "a 400 should give an InvalidRequestError with http status, body, and JSON body" do
248
- response = make_response(make_missing_id_error, 400)
249
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
250
- begin
251
- Stripe::Customer.retrieve("foo")
252
- rescue Stripe::InvalidRequestError => e
253
- assert_equal(400, e.http_status)
254
- assert_equal(true, !!e.http_body)
255
- assert_equal(true, e.json_body.kind_of?(Hash))
256
- end
257
- end
258
-
259
- should "a 401 should give an AuthenticationError with http status, body, and JSON body" do
260
- response = make_response(make_missing_id_error, 401)
261
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
262
- begin
263
- Stripe::Customer.retrieve("foo")
264
- rescue Stripe::AuthenticationError => e
265
- assert_equal(401, e.http_status)
266
- assert_equal(true, !!e.http_body)
267
- assert_equal(true, e.json_body.kind_of?(Hash))
268
- end
269
- end
270
-
271
- should "a 402 should give a CardError with http status, body, and JSON body" do
272
- response = make_response(make_missing_id_error, 402)
273
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
274
- begin
275
- Stripe::Customer.retrieve("foo")
276
- rescue Stripe::CardError => e
277
- assert_equal(402, e.http_status)
278
- assert_equal(true, !!e.http_body)
279
- assert_equal(true, e.json_body.kind_of?(Hash))
280
- end
281
- end
282
-
283
- should "a 404 should give an InvalidRequestError with http status, body, and JSON body" do
284
- response = make_response(make_missing_id_error, 404)
285
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
286
- begin
287
- Stripe::Customer.retrieve("foo")
288
- rescue Stripe::InvalidRequestError => e
289
- assert_equal(404, e.http_status)
290
- assert_equal(true, !!e.http_body)
291
- assert_equal(true, e.json_body.kind_of?(Hash))
292
- end
293
- end
294
-
295
- should "a 429 should give a RateLimitError with http status, body, and JSON body" do
296
- response = make_response(make_rate_limit_error, 429)
297
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 429))
298
- begin
299
- Stripe::Customer.retrieve("foo")
300
- rescue Stripe::RateLimitError => e
301
- assert_equal(429, e.http_status)
302
- assert_equal(true, !!e.http_body)
303
- assert_equal(true, e.json_body.kind_of?(Hash))
304
- end
305
- end
306
-
307
178
  should "setting a nil value for a param should exclude that param from the request" do
308
- @mock.expects(:get).with do |url, api_key, params|
309
- uri = URI(url)
310
- query = CGI.parse(uri.query)
311
- (url =~ %r{^#{Stripe.api_base}/v1/charges?} &&
312
- query.keys.sort == ['offset', 'sad'])
313
- end.returns(make_response({ :count => 1, :data => [make_charge] }))
179
+ stub_request(:get, "#{Stripe.api_base}/v1/charges").
180
+ with(query: { offset: 5, sad: false }).
181
+ to_return(body: JSON.generate({ :count => 1, :data => [API_FIXTURES.fetch(:charge)] }))
314
182
  Stripe::Charge.list(:count => nil, :offset => 5, :sad => false)
315
183
 
316
- @mock.expects(:post).with do |url, api_key, params|
317
- url == "#{Stripe.api_base}/v1/charges" &&
318
- api_key.nil? &&
319
- CGI.parse(params) == { 'amount' => ['50'], 'currency' => ['usd'] }
320
- end.returns(make_response({ :count => 1, :data => [make_charge] }))
184
+ stub_request(:post, "#{Stripe.api_base}/v1/charges").
185
+ with(body: { 'amount' => '50', 'currency' => 'usd' }).
186
+ to_return(body: JSON.generate({ :count => 1, :data => [API_FIXTURES.fetch(:charge)] }))
321
187
  Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
322
188
  end
323
189
 
324
190
  should "requesting with a unicode ID should result in a request" do
325
- response = make_response(make_missing_id_error, 404)
326
- @mock.expects(:get).once.with("#{Stripe.api_base}/v1/customers/%E2%98%83", nil, nil).raises(RestClient::ExceptionWithResponse.new(response, 404))
191
+ stub_request(:get, "#{Stripe.api_base}/v1/customers/%E2%98%83").
192
+ to_return(body: JSON.generate(make_missing_id_error), status: 404)
327
193
  c = Stripe::Customer.new("☃")
328
194
  assert_raises(Stripe::InvalidRequestError) { c.refresh }
329
195
  end
@@ -334,28 +200,29 @@ module Stripe
334
200
  end
335
201
 
336
202
  should "making a GET request with parameters should have a query string and no body" do
337
- params = { :limit => 1 }
338
- @mock.expects(:get).once.with("#{Stripe.api_base}/v1/charges?limit=1", nil, nil).
339
- returns(make_response({ :data => [make_charge] }))
340
- Stripe::Charge.list(params)
203
+ stub_request(:get, "#{Stripe.api_base}/v1/charges").
204
+ with(query: { limit: 1 }).
205
+ to_return(body: JSON.generate({ :data => [API_FIXTURES.fetch(:charge)] }))
206
+ Stripe::Charge.list({ :limit => 1 })
341
207
  end
342
208
 
343
209
  should "making a POST request with parameters should have a body and no query string" do
344
- params = { :amount => 100, :currency => 'usd', :card => 'sc_token' }
345
- @mock.expects(:post).once.with do |url, get, post|
346
- get.nil? && CGI.parse(post) == {'amount' => ['100'], 'currency' => ['usd'], 'card' => ['sc_token']}
347
- end.returns(make_response(make_charge))
348
- Stripe::Charge.create(params)
210
+ stub_request(:post, "#{Stripe.api_base}/v1/charges").
211
+ with(body: {'amount' => '100', 'currency' => 'usd', 'card' => 'sc_token'}).
212
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:charge)))
213
+ Stripe::Charge.create({ :amount => 100, :currency => 'usd', :card => 'sc_token' })
349
214
  end
350
215
 
351
216
  should "loading an object should issue a GET request" do
352
- @mock.expects(:get).once.returns(make_response(make_customer))
217
+ stub_request(:get, "#{Stripe.api_base}/v1/customers/test_customer").
218
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
353
219
  c = Stripe::Customer.new("test_customer")
354
220
  c.refresh
355
221
  end
356
222
 
357
223
  should "using array accessors should be the same as the method interface" do
358
- @mock.expects(:get).once.returns(make_response(make_customer))
224
+ stub_request(:get, "#{Stripe.api_base}/v1/customers/test_customer").
225
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
359
226
  c = Stripe::Customer.new("test_customer")
360
227
  c.refresh
361
228
  assert_equal c.created, c[:created]
@@ -365,138 +232,86 @@ module Stripe
365
232
  end
366
233
 
367
234
  should "accessing a property other than id or parent on an unfetched object should fetch it" do
368
- @mock.expects(:get).once.returns(make_response(make_customer))
235
+ stub_request(:get, "#{Stripe.api_base}/v1/charges").
236
+ with(query: { customer: "test_customer" }).
237
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
369
238
  c = Stripe::Customer.new("test_customer")
370
239
  c.charges
371
240
  end
372
241
 
373
242
  should "updating an object should issue a POST request with only the changed properties" do
374
- @mock.expects(:post).with do |url, api_key, params|
375
- url == "#{Stripe.api_base}/v1/customers/c_test_customer" && api_key.nil? && CGI.parse(params) == {'description' => ['another_mn']}
376
- end.once.returns(make_response(make_customer))
377
- c = Stripe::Customer.construct_from(make_customer)
243
+ stub_request(:post, "#{Stripe.api_base}/v1/customers/c_test_customer").
244
+ with(body: { 'description' => 'another_mn' }).
245
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
246
+ c = Stripe::Customer.construct_from(API_FIXTURES.fetch(:customer))
378
247
  c.description = "another_mn"
379
248
  c.save
380
249
  end
381
250
 
382
251
  should "updating should merge in returned properties" do
383
- @mock.expects(:post).once.returns(make_response(make_customer))
252
+ stub_request(:post, "#{Stripe.api_base}/v1/customers/c_test_customer").
253
+ with(body: { 'description' => 'another_mn' }).
254
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
384
255
  c = Stripe::Customer.new("c_test_customer")
385
256
  c.description = "another_mn"
386
257
  c.save
387
258
  assert_equal false, c.livemode
388
259
  end
389
260
 
390
- should "deleting should send no props and result in an object that has no props other deleted" do
391
- @mock.expects(:get).never
392
- @mock.expects(:post).never
393
- @mock.expects(:delete).with("#{Stripe.api_base}/v1/customers/c_test_customer", nil, nil).once.returns(make_response({ "id" => "test_customer", "deleted" => true }))
394
- c = Stripe::Customer.construct_from(make_customer)
395
- c.delete
396
- assert_equal true, c.deleted
397
-
398
- assert_raises NoMethodError do
399
- c.livemode
261
+ should "updating should fail if api_key is overwritten with nil" do
262
+ c = Stripe::Customer.new
263
+ assert_raises TypeError do
264
+ c.save({}, { :api_key => nil })
400
265
  end
401
266
  end
402
267
 
403
- should "loading an object with properties that have specific types should instantiate those classes" do
404
- @mock.expects(:get).once.returns(make_response(make_charge))
405
- c = Stripe::Charge.retrieve("test_charge")
406
- assert c.card.kind_of?(Stripe::StripeObject) && c.card.object == 'card'
268
+ should "updating should use the supplied api_key" do
269
+ stub_request(:post, "#{Stripe.api_base}/v1/customers").
270
+ with(headers: {"Authorization" => "Bearer sk_test_local"}).
271
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
272
+ c = Stripe::Customer.new
273
+ c.save({}, { :api_key => 'sk_test_local' })
274
+ assert_equal false, c.livemode
275
+ end
276
+
277
+ should "deleting should send no props and result in an object that has no props other deleted" do
278
+ stub_request(:delete, "#{Stripe.api_base}/v1/customers/c_test_customer").
279
+ to_return(body: JSON.generate({ "id" => "test_customer", "deleted" => true }))
280
+ c = Stripe::Customer.construct_from(API_FIXTURES.fetch(:customer))
281
+ c.delete
407
282
  end
408
283
 
409
284
  should "loading all of an APIResource should return an array of recursively instantiated objects" do
410
- @mock.expects(:get).once.returns(make_response(make_charge_array))
411
- c = Stripe::Charge.list.data
412
- assert c.kind_of? Array
413
- assert c[0].kind_of? Stripe::Charge
414
- assert c[0].card.kind_of?(Stripe::StripeObject) && c[0].card.object == 'card'
285
+ stub_request(:get, "#{Stripe.api_base}/v1/charges").
286
+ to_return(body: JSON.generate({
287
+ data: [API_FIXTURES.fetch(:charge)]
288
+ }))
289
+ charges = Stripe::Charge.list.data
290
+ assert charges.kind_of? Array
291
+ assert charges[0].kind_of? Stripe::Charge
292
+ assert charges[0].card.kind_of?(Stripe::StripeObject)
415
293
  end
416
294
 
417
295
  should "passing in a stripe_account header should pass it through on call" do
418
- Stripe.expects(:execute_request).with do |opts|
419
- opts[:method] == :get &&
420
- opts[:url] == "#{Stripe.api_base}/v1/customers/c_test_customer" &&
421
- opts[:headers][:stripe_account] == 'acct_abc'
422
- end.once.returns(make_response(make_customer))
423
- c = Stripe::Customer.retrieve("c_test_customer", {:stripe_account => 'acct_abc'})
296
+ stub_request(:get, "#{Stripe.api_base}/v1/customers/c_test_customer").
297
+ with(headers: {"Stripe-Account" => "acct_abc"}).
298
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
299
+ Stripe::Customer.retrieve("c_test_customer", {:stripe_account => 'acct_abc'})
424
300
  end
425
301
 
426
302
  should "passing in a stripe_account header should pass it through on save" do
427
- Stripe.expects(:execute_request).with do |opts|
428
- opts[:method] == :get &&
429
- opts[:url] == "#{Stripe.api_base}/v1/customers/c_test_customer" &&
430
- opts[:headers][:stripe_account] == 'acct_abc'
431
- end.once.returns(make_response(make_customer))
303
+ stub_request(:get, "#{Stripe.api_base}/v1/customers/c_test_customer").
304
+ with(headers: {"Stripe-Account" => "acct_abc"}).
305
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
432
306
  c = Stripe::Customer.retrieve("c_test_customer", {:stripe_account => 'acct_abc'})
433
307
 
434
- Stripe.expects(:execute_request).with do |opts|
435
- opts[:method] == :post &&
436
- opts[:url] == "#{Stripe.api_base}/v1/customers/c_test_customer" &&
437
- opts[:headers][:stripe_account] == 'acct_abc' &&
438
- opts[:payload] == 'description=FOO'
439
- end.once.returns(make_response(make_customer))
308
+ stub_request(:post, "#{Stripe.api_base}/v1/customers/c_test_customer").
309
+ with(headers: {"Stripe-Account" => "acct_abc"}).
310
+ to_return(body: JSON.generate(API_FIXTURES.fetch(:customer)))
440
311
  c.description = 'FOO'
441
312
  c.save
442
313
  end
443
314
 
444
- context "error checking" do
445
-
446
- should "404s should raise an InvalidRequestError" do
447
- response = make_response(make_missing_id_error, 404)
448
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
449
-
450
- rescued = false
451
- begin
452
- Stripe::Customer.new("test_customer").refresh
453
- assert false #shouldn't get here either
454
- rescue Stripe::InvalidRequestError => e # we don't use assert_raises because we want to examine e
455
- rescued = true
456
- assert e.kind_of? Stripe::InvalidRequestError
457
- assert_equal "id", e.param
458
- assert_equal "Missing id", e.message
459
- end
460
-
461
- assert_equal true, rescued
462
- end
463
-
464
- should "5XXs should raise an APIError" do
465
- response = make_response(make_api_error, 500)
466
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 500))
467
-
468
- rescued = false
469
- begin
470
- Stripe::Customer.new("test_customer").refresh
471
- assert false #shouldn't get here either
472
- rescue Stripe::APIError => e # we don't use assert_raises because we want to examine e
473
- rescued = true
474
- assert e.kind_of? Stripe::APIError
475
- end
476
-
477
- assert_equal true, rescued
478
- end
479
-
480
- should "402s should raise a CardError" do
481
- response = make_response(make_invalid_exp_year_error, 402)
482
- @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 402))
483
-
484
- rescued = false
485
- begin
486
- Stripe::Customer.new("test_customer").refresh
487
- assert false #shouldn't get here either
488
- rescue Stripe::CardError => e # we don't use assert_raises because we want to examine e
489
- rescued = true
490
- assert e.kind_of? Stripe::CardError
491
- assert_equal "invalid_expiry_year", e.code
492
- assert_equal "exp_year", e.param
493
- assert_equal "Your card's expiration year is invalid", e.message
494
- end
495
-
496
- assert_equal true, rescued
497
- end
498
- end
499
-
500
315
  should 'add key to nested objects' do
501
316
  acct = Stripe::Account.construct_from({
502
317
  :id => 'myid',
@@ -507,7 +322,9 @@ module Stripe
507
322
  }
508
323
  })
509
324
 
510
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts/myid", nil, 'legal_entity[first_name]=Bob').returns(make_response({"id" => "myid"}))
325
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts/myid").
326
+ with(body: { legal_entity: { first_name: "Bob" } }).
327
+ to_return(body: JSON.generate({ "id" => "myid" }))
511
328
 
512
329
  acct.legal_entity.first_name = 'Bob'
513
330
  acct.save
@@ -515,27 +332,31 @@ module Stripe
515
332
 
516
333
  should 'save nothing if nothing changes' do
517
334
  acct = Stripe::Account.construct_from({
518
- :id => 'myid',
335
+ :id => 'acct_id',
519
336
  :metadata => {
520
337
  :key => 'value'
521
338
  }
522
339
  })
523
340
 
524
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts/myid", nil, '').returns(make_response({"id" => "myid"}))
341
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts/acct_id").
342
+ with(body: {}).
343
+ to_return(body: JSON.generate({ "id" => "acct_id" }))
525
344
 
526
345
  acct.save
527
346
  end
528
347
 
529
348
  should 'not save nested API resources' do
530
349
  ch = Stripe::Charge.construct_from({
531
- :id => 'charge_id',
350
+ :id => 'ch_id',
532
351
  :customer => {
533
352
  :object => 'customer',
534
353
  :id => 'customer_id'
535
354
  }
536
355
  })
537
356
 
538
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/charges/charge_id", nil, '').returns(make_response({"id" => "charge_id"}))
357
+ stub_request(:post, "#{Stripe.api_base}/v1/charges/ch_id").
358
+ with(body: {}).
359
+ to_return(body: JSON.generate({ "id" => "ch_id" }))
539
360
 
540
361
  ch.customer.description = 'Bob'
541
362
  ch.save
@@ -553,14 +374,9 @@ module Stripe
553
374
  }
554
375
  })
555
376
 
556
- @mock.expects(:post).once.with(
557
- "#{Stripe.api_base}/v1/accounts/myid",
558
- nil,
559
- any_of(
560
- 'legal_entity[address][line1]=Test2&legal_entity[address][city]=',
561
- 'legal_entity[address][city]=&legal_entity[address][line1]=Test2'
562
- )
563
- ).returns(make_response({"id" => "myid"}))
377
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts/myid").
378
+ with(body: { legal_entity: { address: { line1: "Test2", city: "" } } }).
379
+ to_return(body: JSON.generate({ "id" => "my_id" }))
564
380
 
565
381
  acct.legal_entity.address = {:line1 => 'Test2'}
566
382
  acct.save
@@ -572,7 +388,9 @@ module Stripe
572
388
  :legal_entity => {}
573
389
  })
574
390
 
575
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts/myid", nil, 'legal_entity[additional_owners][0][first_name]=Bob').returns(make_response({"id" => "myid"}))
391
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts/myid").
392
+ with(body: { legal_entity: { additional_owners: [{ first_name: "Bob" }] } }).
393
+ to_return(body: JSON.generate({ "id" => "myid" }))
576
394
 
577
395
  acct.legal_entity.additional_owners = [{:first_name => 'Bob'}]
578
396
  acct.save
@@ -586,7 +404,12 @@ module Stripe
586
404
  }
587
405
  })
588
406
 
589
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts/myid", nil, 'legal_entity[additional_owners][0][first_name]=Bob').returns(make_response({"id" => "myid"}))
407
+ # Note that this isn't a perfect check because we're using webmock's
408
+ # data decoding, which isn't aware of the Stripe array encoding that we
409
+ # use here.
410
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts/myid").
411
+ with(body: { legal_entity: { additional_owners: [{ first_name: "Bob" }] } }).
412
+ to_return(body: JSON.generate({ "id" => "myid" }))
590
413
 
591
414
  acct.legal_entity.additional_owners << {:first_name => 'Bob'}
592
415
  acct.save
@@ -600,7 +423,12 @@ module Stripe
600
423
  }
601
424
  })
602
425
 
603
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts/myid", nil, 'legal_entity[additional_owners][1][first_name]=Janet').returns(make_response({"id" => "myid"}))
426
+ # Note that this isn't a perfect check because we're using webmock's
427
+ # data decoding, which isn't aware of the Stripe array encoding that we
428
+ # use here.
429
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts/myid").
430
+ with(body: { legal_entity: { additional_owners: [{ first_name: "Janet" }] } }).
431
+ to_return(body: JSON.generate({ "id" => "myid" }))
604
432
 
605
433
  acct.legal_entity.additional_owners[1].first_name = 'Janet'
606
434
  acct.save
@@ -615,7 +443,9 @@ module Stripe
615
443
  :currencies_supported => ['usd', 'cad']
616
444
  })
617
445
 
618
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts/myid", nil, '').returns(make_response({"id" => "myid"}))
446
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts/myid").
447
+ with(body: {}).
448
+ to_return(body: JSON.generate({ "id" => "myid" }))
619
449
 
620
450
  acct.save
621
451
  end
@@ -628,7 +458,9 @@ module Stripe
628
458
  }
629
459
  })
630
460
 
631
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts/myid", nil, '').returns(make_response({"id" => "myid"}))
461
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts/myid").
462
+ with(body: {}).
463
+ to_return(body: JSON.generate({ "id" => "myid" }))
632
464
 
633
465
  acct.save
634
466
  end
@@ -639,8 +471,9 @@ module Stripe
639
471
  :display_name => nil,
640
472
  })
641
473
 
642
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts", nil, 'display_name=stripe').
643
- returns(make_response({"id" => "charge_id"}))
474
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts").
475
+ with(body: { display_name: "stripe" }).
476
+ to_return(body: JSON.generate({ "id" => "acct_123" }))
644
477
 
645
478
  account.display_name = 'stripe'
646
479
  account.save
@@ -652,10 +485,11 @@ module Stripe
652
485
  :display_name => nil,
653
486
  })
654
487
 
655
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts", nil, 'display_name=stripe').
656
- returns(make_response({"id" => "charge_id"}))
488
+ stub_request(:post, "#{Stripe.api_base}/v1/accounts").
489
+ with(body: { display_name: "stripe", metadata: { key: "value" } }).
490
+ to_return(body: JSON.generate({ "id" => "acct_123" }))
657
491
 
658
- account.save(:display_name => 'stripe')
492
+ account.save(:display_name => 'stripe', :metadata => {:key => 'value' })
659
493
  end
660
494
  end
661
495
  end