stripe 1.30.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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