stripe-ruby-mock 3.1.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec_tests.yml +7 -10
  3. data/CHANGELOG.md +24 -0
  4. data/Gemfile +0 -5
  5. data/README.md +3 -3
  6. data/bin/stripe-mock-server +1 -0
  7. data/lib/stripe_mock/api/client.rb +1 -1
  8. data/lib/stripe_mock/data.rb +53 -9
  9. data/lib/stripe_mock/instance.rb +4 -2
  10. data/lib/stripe_mock/request_handlers/charges.rb +20 -1
  11. data/lib/stripe_mock/request_handlers/checkout_session.rb +12 -11
  12. data/lib/stripe_mock/request_handlers/customers.rb +12 -1
  13. data/lib/stripe_mock/request_handlers/helpers/search_helpers.rb +67 -0
  14. data/lib/stripe_mock/request_handlers/invoices.rb +18 -3
  15. data/lib/stripe_mock/request_handlers/payment_intents.rb +11 -2
  16. data/lib/stripe_mock/request_handlers/payment_methods.rb +5 -1
  17. data/lib/stripe_mock/request_handlers/payouts.rb +10 -3
  18. data/lib/stripe_mock/request_handlers/prices.rb +13 -4
  19. data/lib/stripe_mock/request_handlers/products.rb +14 -5
  20. data/lib/stripe_mock/request_handlers/subscriptions.rb +11 -2
  21. data/lib/stripe_mock/request_handlers/tax_ids.rb +66 -0
  22. data/lib/stripe_mock/server.rb +9 -4
  23. data/lib/stripe_mock/test_strategies/base.rb +0 -1
  24. data/lib/stripe_mock/version.rb +1 -1
  25. data/lib/stripe_mock.rb +2 -0
  26. data/spec/shared_stripe_examples/bank_token_examples.rb +5 -7
  27. data/spec/shared_stripe_examples/charge_examples.rb +97 -0
  28. data/spec/shared_stripe_examples/checkout_session_examples.rb +0 -5
  29. data/spec/shared_stripe_examples/customer_examples.rb +56 -0
  30. data/spec/shared_stripe_examples/invoice_examples.rb +86 -1
  31. data/spec/shared_stripe_examples/payment_intent_examples.rb +75 -13
  32. data/spec/shared_stripe_examples/payment_method_examples.rb +10 -0
  33. data/spec/shared_stripe_examples/payout_examples.rb +26 -6
  34. data/spec/shared_stripe_examples/price_examples.rb +70 -1
  35. data/spec/shared_stripe_examples/product_examples.rb +71 -0
  36. data/spec/shared_stripe_examples/subscription_examples.rb +65 -6
  37. data/spec/spec_helper.rb +1 -1
  38. data/stripe-ruby-mock.gemspec +3 -3
  39. metadata +22 -17
@@ -3,10 +3,11 @@ module StripeMock
3
3
  module Prices
4
4
 
5
5
  def Prices.included(klass)
6
- klass.add_handler 'post /v1/prices', :new_price
7
- klass.add_handler 'post /v1/prices/(.*)', :update_price
8
- klass.add_handler 'get /v1/prices/(.*)', :get_price
9
- klass.add_handler 'get /v1/prices', :list_prices
6
+ klass.add_handler 'post /v1/prices', :new_price
7
+ klass.add_handler 'post /v1/prices/(.*)', :update_price
8
+ klass.add_handler 'get /v1/prices/((?!search).*)', :get_price
9
+ klass.add_handler 'get /v1/prices/search', :search_prices
10
+ klass.add_handler 'get /v1/prices', :list_prices
10
11
  end
11
12
 
12
13
  def new_price(route, method_url, params, headers)
@@ -57,6 +58,14 @@ module StripeMock
57
58
 
58
59
  Data.mock_list_object(price_data.first(limit), params.merge!(limit: limit))
59
60
  end
61
+
62
+ SEARCH_FIELDS = ["active", "currency", "lookup_key", "product", "type"].freeze
63
+ def search_prices(route, method_url, params, headers)
64
+ require_param(:query) unless params[:query]
65
+
66
+ results = search_results(prices.values, params[:query], fields: SEARCH_FIELDS, resource_name: "prices")
67
+ Data.mock_list_object(results, params)
68
+ end
60
69
  end
61
70
  end
62
71
  end
@@ -2,11 +2,12 @@ module StripeMock
2
2
  module RequestHandlers
3
3
  module Products
4
4
  def self.included(base)
5
- base.add_handler 'post /v1/products', :create_product
6
- base.add_handler 'get /v1/products/(.*)', :retrieve_product
7
- base.add_handler 'post /v1/products/(.*)', :update_product
8
- base.add_handler 'get /v1/products', :list_products
9
- base.add_handler 'delete /v1/products/(.*)', :destroy_product
5
+ base.add_handler 'post /v1/products', :create_product
6
+ base.add_handler 'get /v1/products/((?!search).*)', :retrieve_product
7
+ base.add_handler 'get /v1/products/search', :search_products
8
+ base.add_handler 'post /v1/products/(.*)', :update_product
9
+ base.add_handler 'get /v1/products', :list_products
10
+ base.add_handler 'delete /v1/products/(.*)', :destroy_product
10
11
  end
11
12
 
12
13
  def create_product(_route, _method_url, params, _headers)
@@ -32,6 +33,14 @@ module StripeMock
32
33
  Data.mock_list_object(products.values.take(limit), params)
33
34
  end
34
35
 
36
+ SEARCH_FIELDS = ["active", "description", "name", "shippable", "url"].freeze
37
+ def search_products(route, method_url, params, headers)
38
+ require_param(:query) unless params[:query]
39
+
40
+ results = search_results(products.values, params[:query], fields: SEARCH_FIELDS, resource_name: "products")
41
+ Data.mock_list_object(results, params)
42
+ end
43
+
35
44
  def destroy_product(route, method_url, _params, _headers)
36
45
  id = method_url.match(route).captures.first
37
46
  assert_existence :product, id, products[id]
@@ -5,8 +5,9 @@ module StripeMock
5
5
  def Subscriptions.included(klass)
6
6
  klass.add_handler 'get /v1/subscriptions', :retrieve_subscriptions
7
7
  klass.add_handler 'post /v1/subscriptions', :create_subscription
8
- klass.add_handler 'get /v1/subscriptions/(.*)', :retrieve_subscription
8
+ klass.add_handler 'get /v1/subscriptions/((?!search).*)', :retrieve_subscription
9
9
  klass.add_handler 'post /v1/subscriptions/(.*)', :update_subscription
10
+ klass.add_handler 'get /v1/subscriptions/search', :search_subscriptions
10
11
  klass.add_handler 'delete /v1/subscriptions/(.*)', :cancel_subscription
11
12
 
12
13
  klass.add_handler 'post /v1/customers/(.*)/subscription(?:s)?', :create_customer_subscription
@@ -166,7 +167,7 @@ module StripeMock
166
167
  end
167
168
 
168
169
  if params[:transfer_data] && !params[:transfer_data].empty?
169
- throw Stripe::InvalidRequestError.new(missing_param_message("transfer_data[destination]")) unless params[:transfer_data][:destination]
170
+ raise Stripe::InvalidRequestError.new(missing_param_message("transfer_data[destination]")) unless params[:transfer_data][:destination]
170
171
  subscription[:transfer_data] = params[:transfer_data].dup
171
172
  subscription[:transfer_data][:amount_percent] ||= 100
172
173
  end
@@ -343,6 +344,14 @@ module StripeMock
343
344
  subscription
344
345
  end
345
346
 
347
+ SEARCH_FIELDS = ["status"].freeze
348
+ def search_subscriptions(route, method_url, params, headers)
349
+ require_param(:query) unless params[:query]
350
+
351
+ results = search_results(subscriptions.values, params[:query], fields: SEARCH_FIELDS, resource_name: "subscriptions")
352
+ Data.mock_list_object(results, params)
353
+ end
354
+
346
355
  private
347
356
 
348
357
  def get_subscription_plans_from_params(params)
@@ -0,0 +1,66 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module TaxIds
4
+ def TaxIds.included(klass)
5
+ klass.add_handler 'post /v1/tax_ids', :new_tax_id
6
+ klass.add_handler 'post /v1/customers/(.*)/tax_ids', :new_customer_tax_id
7
+ klass.add_handler 'get /v1/tax_ids/([^/]*)', :get_tax_id
8
+ klass.add_handler 'get /v1/customers/(.*)/tax_ids/([^/]*)', :get_customer_tax_id
9
+ klass.add_handler 'get /v1/tax_ids', :list_tax_ids
10
+ klass.add_handler 'get /v1/customers/(.*)/tax_ids', :list_customer_tax_ids
11
+ klass.add_handler 'delete /v1/tax_ids/([^/]*)', :delete_tax_id
12
+ klass.add_handler 'delete /v1/customers/(.*)/tax_ids/([^/]*)', :delete_customer_tax_id
13
+ end
14
+
15
+ def new_tax_id(route, method_url, params, headers)
16
+ params[:id] ||= new_id('txi')
17
+ tax_ids[ params[:id] ] = Data.mock_tax_id(params)
18
+ tax_ids[ params[:id] ]
19
+ end
20
+ def new_customer_tax_id(route, method_url, params, headers)
21
+ new_tax_id(route, method_url, params.merge(customer: $1))
22
+ end
23
+
24
+ def get_tax_id(route, method_url, params, headers)
25
+ route =~ method_url
26
+ tax_id = assert_existence :tax_id, $1, tax_ids[$1]
27
+ tax_id.clone
28
+ end
29
+ def get_customer_tax_id(route, method_url, params, headers)
30
+ route =~ method_url
31
+ tax_id = tax_ids[$2]
32
+ tax_id = nil if tax_id[:customer] != $1
33
+ tax_id = assert_existence :tax_id, $2, tax_id
34
+ tax_id.clone
35
+ end
36
+
37
+ def list_tax_ids(route, method_url, params, headers)
38
+ Data.mock_list_object(tax_ids.values, params)
39
+ end
40
+ def list_customer_tax_ids(route, method_url, params, headers)
41
+ Data.mock_list_object(tax_ids.values.select { |t| t[:customer] == $1 }, params)
42
+ end
43
+
44
+ def delete_tax_id(route, method_url, params, headers)
45
+ route =~ method_url
46
+ assert_existence :tax_id, $1, tax_ids[$1]
47
+
48
+ tax_ids[$1] = {
49
+ id: tax_ids[$1][:id],
50
+ deleted: true
51
+ }
52
+ end
53
+ def delete_customer_tax_id(route, method_url, params, headers)
54
+ route =~ method_url
55
+ tax_id = tax_ids[$2]
56
+ tax_id = nil if tax_id[:customer] != $1
57
+ tax_id = assert_existence :tax_id, $2, tax_id
58
+
59
+ tax_ids[$2] = {
60
+ id: tax_ids[$2][:id],
61
+ deleted: true
62
+ }
63
+ end
64
+ end
65
+ end
66
+ end
@@ -3,10 +3,16 @@ require 'drb/drb'
3
3
  module StripeMock
4
4
  class Server
5
5
  def self.start_new(opts)
6
- puts "Starting StripeMock server on port #{opts[:port] || 4999}"
6
+ host = opts.fetch(:host, "0.0.0.0")
7
+ port = opts.fetch(:port, 4999)
8
+ extra_requires = opts.fetch(:require, [])
7
9
 
8
- host = opts.fetch :host,'0.0.0.0'
9
- port = opts.fetch :port, 4999
10
+ extra_requires.each do |path|
11
+ puts "Requiring additional path: #{path}"
12
+ require(path)
13
+ end
14
+
15
+ puts "Starting StripeMock server on port #{port}"
10
16
 
11
17
  DRb.start_service "druby://#{host}:#{port}", Server.new
12
18
  DRb.thread.join
@@ -88,6 +94,5 @@ module StripeMock
88
94
  def upsert_stripe_object(object, attributes)
89
95
  @instance.upsert_stripe_object(object, attributes)
90
96
  end
91
-
92
97
  end
93
98
  end
@@ -121,7 +121,6 @@ module StripeMock
121
121
  amount: 500,
122
122
  currency: 'usd',
123
123
  }],
124
- cancel_url: "https://example.com/cancel",
125
124
  success_url: "https://example.com/success",
126
125
  }.merge(params)
127
126
  end
@@ -1,4 +1,4 @@
1
1
  module StripeMock
2
2
  # stripe-ruby-mock version
3
- VERSION = "3.1.0"
3
+ VERSION = "4.1.0"
4
4
  end
data/lib/stripe_mock.rb CHANGED
@@ -42,6 +42,7 @@ require 'stripe_mock/request_handlers/helpers/external_account_helpers.rb'
42
42
  require 'stripe_mock/request_handlers/helpers/card_helpers.rb'
43
43
  require 'stripe_mock/request_handlers/helpers/charge_helpers.rb'
44
44
  require 'stripe_mock/request_handlers/helpers/coupon_helpers.rb'
45
+ require 'stripe_mock/request_handlers/helpers/search_helpers.rb'
45
46
  require 'stripe_mock/request_handlers/helpers/subscription_helpers.rb'
46
47
  require 'stripe_mock/request_handlers/helpers/token_helpers.rb'
47
48
 
@@ -79,6 +80,7 @@ require 'stripe_mock/request_handlers/tokens.rb'
79
80
  require 'stripe_mock/request_handlers/country_spec.rb'
80
81
  require 'stripe_mock/request_handlers/ephemeral_key.rb'
81
82
  require 'stripe_mock/request_handlers/products.rb'
83
+ require 'stripe_mock/request_handlers/tax_ids.rb'
82
84
  require 'stripe_mock/request_handlers/tax_rates.rb'
83
85
  require 'stripe_mock/request_handlers/checkout_session.rb'
84
86
  require 'stripe_mock/instance'
@@ -28,20 +28,19 @@ shared_examples 'Bank Account Token Mocking' do
28
28
  expect(bank_token).to match /^test_btok/
29
29
  end
30
30
 
31
- it "assigns the generated bank account to a new recipient" do
31
+ it "assigns the generated bank account to a new customer" do
32
32
  bank_token = StripeMock.generate_bank_token(
33
33
  :bank_name => "Bank Token Mocking",
34
34
  :last4 => "7777"
35
35
  )
36
36
 
37
- recipient = Stripe::Recipient.create({
37
+ customer = Stripe::Customer.create({
38
38
  name: "Fred Flinstone",
39
- type: "individual",
40
39
  email: 'blah@domain.co',
41
- bank_account: bank_token
40
+ source: bank_token
42
41
  })
43
- expect(recipient.active_account.last4).to eq("7777")
44
- expect(recipient.active_account.bank_name).to eq("Bank Token Mocking")
42
+ expect(customer.sources.first.last4).to eq("7777")
43
+ expect(customer.sources.first.bank_name).to eq("Bank Token Mocking")
45
44
  end
46
45
 
47
46
  it "retrieves a created token" do
@@ -55,5 +54,4 @@ shared_examples 'Bank Account Token Mocking' do
55
54
  expect(token.bank_account.last4).to eq("3939")
56
55
  expect(token.bank_account.bank_name).to eq("Cha-ching Banking")
57
56
  end
58
-
59
57
  end
@@ -494,4 +494,101 @@ shared_examples 'Charge API' do
494
494
  end
495
495
  end
496
496
 
497
+ context "search" do
498
+ # the Search API requires about a minute between writes and reads, so add sleeps accordingly when running live
499
+ it "searches charges for exact matches", :aggregate_failures do
500
+ response = Stripe::Charge.search({query: 'amount:100'}, stripe_version: '2020-08-27')
501
+ expect(response.data.size).to eq(0)
502
+
503
+ customer = Stripe::Customer.create(email: 'johnny@appleseed.com')
504
+ one = Stripe::Charge.create(
505
+ customer: customer.id,
506
+ amount: 100,
507
+ currency: "usd",
508
+ payment_method_details: {
509
+ card: StripeMock::Data.mock_charge[:payment_method_details][:card].merge(
510
+ brand: "mastercard",
511
+ exp_month: 1,
512
+ exp_year: 2111,
513
+ fingerprint: "un",
514
+ last4: "1111",
515
+ ),
516
+ },
517
+ status: "succeeded",
518
+ metadata: {key: 'uno'},
519
+ )
520
+ two = Stripe::Charge.create(
521
+ customer: customer.id,
522
+ amount: 200,
523
+ currency: "gbp",
524
+ payment_method_details: {
525
+ card: StripeMock::Data.mock_charge[:payment_method_details][:card].merge(
526
+ brand: "visa",
527
+ exp_month: 2,
528
+ exp_year: 2222,
529
+ fingerprint: "deux",
530
+ last4: "2222",
531
+ ),
532
+ },
533
+ status: "pending",
534
+ metadata: {key: 'dos'},
535
+ )
536
+
537
+ response = Stripe::Charge.search({query: 'amount:100'}, stripe_version: '2020-08-27')
538
+ expect(response.data.map(&:id)).to match_array([one.id])
539
+
540
+ response = Stripe::Charge.search({query: 'currency:"gbp"'}, stripe_version: '2020-08-27')
541
+ expect(response.data.map(&:id)).to match_array([two.id])
542
+
543
+ response = Stripe::Charge.search({query: %(customer:"#{customer.id}")}, stripe_version: '2020-08-27')
544
+ expect(response.data.map(&:id)).to match_array([one.id, two.id])
545
+
546
+ response = Stripe::Charge.search({query: 'payment_method_details.card.brand:mastercard'}, stripe_version: '2020-08-27')
547
+ expect(response.data.map(&:id)).to match_array([one.id])
548
+
549
+ response = Stripe::Charge.search({query: 'payment_method_details.card.exp_month:2'}, stripe_version: '2020-08-27')
550
+ expect(response.data.map(&:id)).to match_array([two.id])
551
+
552
+ response = Stripe::Charge.search({query: 'payment_method_details.card.exp_year:2111'}, stripe_version: '2020-08-27')
553
+ expect(response.data.map(&:id)).to match_array([one.id])
554
+
555
+ response = Stripe::Charge.search({query: 'payment_method_details.card.fingerprint:un'}, stripe_version: '2020-08-27')
556
+ expect(response.data.map(&:id)).to match_array([one.id])
557
+
558
+ response = Stripe::Charge.search({query: 'payment_method_details.card.last4:2222'}, stripe_version: '2020-08-27')
559
+ expect(response.data.map(&:id)).to match_array([two.id])
560
+
561
+ response = Stripe::Charge.search({query: 'status:"succeeded"'}, stripe_version: '2020-08-27')
562
+ expect(response.data.map(&:id)).to match_array([one.id])
563
+
564
+ response = Stripe::Charge.search({query: 'metadata["key"]:"uno"'}, stripe_version: '2020-08-27')
565
+ expect(response.data.map(&:id)).to match_array([one.id])
566
+ end
567
+
568
+ it "respects limit", :aggregate_failures do
569
+ customer = Stripe::Customer.create(email: 'johnny@appleseed.com')
570
+ 11.times do
571
+ Stripe::Charge.create(customer: customer.id, amount: 100, currency: "usd")
572
+ end
573
+
574
+ response = Stripe::Charge.search({query: %(customer:"#{customer.id}")}, stripe_version: '2020-08-27')
575
+ expect(response.data.size).to eq(10)
576
+ response = Stripe::Charge.search({query: %(customer:"#{customer.id}"), limit: 1}, stripe_version: '2020-08-27')
577
+ expect(response.data.size).to eq(1)
578
+ end
579
+
580
+ it "reports search errors", :aggregate_failures do
581
+ expect {
582
+ Stripe::Charge.search({limit: 1}, stripe_version: '2020-08-27')
583
+ }.to raise_error(Stripe::InvalidRequestError, /Missing required param: query./)
584
+
585
+ expect {
586
+ Stripe::Charge.search({query: 'asdf'}, stripe_version: '2020-08-27')
587
+ }.to raise_error(Stripe::InvalidRequestError, /We were unable to parse your search query./)
588
+
589
+ expect {
590
+ Stripe::Charge.search({query: 'foo:"bar"'}, stripe_version: '2020-08-27')
591
+ }.to raise_error(Stripe::InvalidRequestError, /Field `foo` is an unsupported search field for resource `charges`./)
592
+ end
593
+ end
497
594
  end
@@ -11,7 +11,6 @@ shared_examples "Checkout Session API" do
11
11
  session = Stripe::Checkout::Session.create(
12
12
  payment_method_types: ["card"],
13
13
  line_items: line_items,
14
- cancel_url: "https://example.com/cancel",
15
14
  success_url: "https://example.com/success"
16
15
  )
17
16
 
@@ -28,7 +27,6 @@ shared_examples "Checkout Session API" do
28
27
  session = Stripe::Checkout::Session.create(
29
28
  customer: "customer_id",
30
29
  success_url: "localhost/nada",
31
- cancel_url: "localhost/nada",
32
30
  payment_method_types: ["card"],
33
31
  )
34
32
  end.to raise_error(Stripe::InvalidRequestError, /line_items/i)
@@ -40,7 +38,6 @@ shared_examples "Checkout Session API" do
40
38
  session = Stripe::Checkout::Session.create(
41
39
  mode: "setup",
42
40
  payment_method_types: ["card"],
43
- cancel_url: "https://example.com/cancel",
44
41
  success_url: "https://example.com/success"
45
42
  )
46
43
 
@@ -55,7 +52,6 @@ shared_examples "Checkout Session API" do
55
52
  session = Stripe::Checkout::Session.create(
56
53
  customer: "customer_id",
57
54
  success_url: "localhost/nada",
58
- cancel_url: "localhost/nada",
59
55
  payment_method_types: ["card"],
60
56
  mode: "subscription",
61
57
  )
@@ -86,7 +82,6 @@ shared_examples "Checkout Session API" do
86
82
  it "can expand setup_intent" do
87
83
  initial_session = Stripe::Checkout::Session.create(
88
84
  mode: "setup",
89
- cancel_url: "https://example.com",
90
85
  success_url: "https://example.com",
91
86
  payment_method_types: ["card"]
92
87
  )
@@ -349,6 +349,62 @@ shared_examples 'Customer API' do
349
349
  expect(all.data.map &:email).to include('one@one.com', 'two@two.com')
350
350
  end
351
351
 
352
+ context "search" do
353
+ # the Search API requires about a minute between writes and reads, so add sleeps accordingly when running live
354
+ it "searches customers for exact matches", :aggregate_failures do
355
+ response = Stripe::Customer.search({query: 'email:"one@one.com"'}, stripe_version: '2020-08-27')
356
+ expect(response.data.size).to eq(0)
357
+
358
+ one = Stripe::Customer.create(email: 'one@one.com', name: 'one', phone: '1111111111', metadata: {key: 'uno'})
359
+ two = Stripe::Customer.create(email: 'two@two.com', name: 'two', phone: '2222222222', metadata: {key: 'dos'})
360
+
361
+ response = Stripe::Customer.search({query: 'email:"one@one.com"'}, stripe_version: '2020-08-27')
362
+ expect(response.data.map(&:id)).to match_array([one.id])
363
+
364
+ response = Stripe::Customer.search({query: 'name:"two"'}, stripe_version: '2020-08-27')
365
+ expect(response.data.map(&:id)).to match_array([two.id])
366
+
367
+ response = Stripe::Customer.search({query: 'phone:"2222222222"'}, stripe_version: '2020-08-27')
368
+ expect(response.data.map(&:id)).to match_array([two.id])
369
+
370
+ response = Stripe::Customer.search({query: 'metadata["key"]:"uno"'}, stripe_version: '2020-08-27')
371
+ expect(response.data.map(&:id)).to match_array([one.id])
372
+ end
373
+
374
+ it "respects limit", :aggregate_failures do
375
+ one = Stripe::Customer.create(email: 'one@one.com', name: 'one')
376
+ two = Stripe::Customer.create(email: 'two@two.com', name: 'one')
377
+ three = Stripe::Customer.create(email: 'three@three.com', name: 'one')
378
+ four = Stripe::Customer.create(email: 'four@four.com', name: 'one')
379
+ five = Stripe::Customer.create(email: 'five@five.com', name: 'one')
380
+ six = Stripe::Customer.create(email: 'six@six.com', name: 'one')
381
+ seven = Stripe::Customer.create(email: 'seven@seven.com', name: 'one')
382
+ eight = Stripe::Customer.create(email: 'eight@eight.com', name: 'one')
383
+ nine = Stripe::Customer.create(email: 'nine@nine.com', name: 'one')
384
+ ten = Stripe::Customer.create(email: 'ten@ten.com', name: 'one')
385
+ eleven = Stripe::Customer.create(email: 'eleven@eleven.com', name: 'one')
386
+
387
+ response = Stripe::Customer.search({query: 'name:"one"'}, stripe_version: '2020-08-27')
388
+ expect(response.data.size).to eq(10)
389
+ response = Stripe::Customer.search({query: 'name:"one"', limit: 1}, stripe_version: '2020-08-27')
390
+ expect(response.data.size).to eq(1)
391
+ end
392
+
393
+ it "reports search errors", :aggregate_failures do
394
+ expect {
395
+ Stripe::Customer.search({limit: 1}, stripe_version: '2020-08-27')
396
+ }.to raise_error(Stripe::InvalidRequestError, /Missing required param: query./)
397
+
398
+ expect {
399
+ Stripe::Customer.search({query: 'asdf'}, stripe_version: '2020-08-27')
400
+ }.to raise_error(Stripe::InvalidRequestError, /We were unable to parse your search query./)
401
+
402
+ expect {
403
+ Stripe::Customer.search({query: 'foo:"bar"'}, stripe_version: '2020-08-27')
404
+ }.to raise_error(Stripe::InvalidRequestError, /Field `foo` is an unsupported search field for resource `customers`./)
405
+ end
406
+ end
407
+
352
408
  it "updates a stripe customer" do
353
409
  original = Stripe::Customer.create(id: 'test_customer_update')
354
410
  email = original.email
@@ -79,6 +79,88 @@ shared_examples 'Invoice API' do
79
79
  end
80
80
  end
81
81
 
82
+ context "searching invoices" do
83
+ # the Search API requires about a minute between writes and reads, so add sleeps accordingly when running live
84
+ it "searches invoices for exact matches", :aggregate_failures do
85
+ response = Stripe::Invoice.search({query: 'currency:"usd"'}, stripe_version: '2020-08-27')
86
+ expect(response.data.size).to eq(0)
87
+
88
+ product = stripe_helper.create_product
89
+ stripe_helper.create_plan(
90
+ amount: 500,
91
+ interval: 'month',
92
+ product: product.id,
93
+ currency: 'usd',
94
+ id: 'Sample5',
95
+ )
96
+ customer = Stripe::Customer.create(email: 'johnny@appleseed.com', source: stripe_helper.generate_card_token)
97
+ subscription = Stripe::Subscription.create(customer: customer.id, items: [{plan: 'Sample5'}])
98
+ one = Stripe::Invoice.create(
99
+ customer: customer.id,
100
+ currency: 'usd',
101
+ subscription: subscription.id,
102
+ metadata: {key: 'uno'},
103
+ number: 'one-1',
104
+ receipt_number: '111',
105
+ )
106
+ two = Stripe::Invoice.create(
107
+ customer: customer.id,
108
+ currency: 'gbp',
109
+ subscription: subscription.id,
110
+ metadata: {key: 'dos'},
111
+ number: 'two-2',
112
+ receipt_number: '222',
113
+ )
114
+
115
+ response = Stripe::Invoice.search({query: 'currency:"gbp"'}, stripe_version: '2020-08-27')
116
+ expect(response.data.map(&:id)).to match_array([two.id])
117
+
118
+ response = Stripe::Invoice.search({query: %(customer:"#{customer.id}")}, stripe_version: '2020-08-27')
119
+ expect(response.data.map(&:id)).to match_array([one.id, two.id])
120
+
121
+ response = Stripe::Invoice.search({query: 'number:"one-1"'}, stripe_version: '2020-08-27')
122
+ expect(response.data.map(&:id)).to match_array([one.id])
123
+
124
+ response = Stripe::Invoice.search({query: 'receipt_number:"222"'}, stripe_version: '2020-08-27')
125
+ expect(response.data.map(&:id)).to match_array([two.id])
126
+
127
+ response = Stripe::Invoice.search({query: %(subscription:"#{subscription.id}")}, stripe_version: '2020-08-27')
128
+ expect(response.data.map(&:id)).to match_array([one.id, two.id])
129
+
130
+ response = Stripe::Invoice.search({query: 'total:1000'}, stripe_version: '2020-08-27')
131
+ expect(response.data.map(&:id)).to match_array([one.id, two.id])
132
+
133
+ response = Stripe::Invoice.search({query: 'metadata["key"]:"uno"'}, stripe_version: '2020-08-27')
134
+ expect(response.data.map(&:id)).to match_array([one.id])
135
+ end
136
+
137
+ it "respects limit", :aggregate_failures do
138
+ customer = Stripe::Customer.create(email: 'one@one.com', name: 'one', phone: '1111111111', metadata: {key: 'uno'})
139
+ 11.times do
140
+ Stripe::Invoice.create(customer: customer.id, currency: 'usd')
141
+ end
142
+
143
+ response = Stripe::Invoice.search({query: %(customer:"#{customer.id}")}, stripe_version: '2020-08-27')
144
+ expect(response.data.size).to eq(10)
145
+ response = Stripe::Invoice.search({query: %(customer:"#{customer.id}"), limit: 1}, stripe_version: '2020-08-27')
146
+ expect(response.data.size).to eq(1)
147
+ end
148
+
149
+ it "reports search errors", :aggregate_failures do
150
+ expect {
151
+ Stripe::Invoice.search({limit: 1}, stripe_version: '2020-08-27')
152
+ }.to raise_error(Stripe::InvalidRequestError, /Missing required param: query./)
153
+
154
+ expect {
155
+ Stripe::Invoice.search({query: 'asdf'}, stripe_version: '2020-08-27')
156
+ }.to raise_error(Stripe::InvalidRequestError, /We were unable to parse your search query./)
157
+
158
+ expect {
159
+ Stripe::Invoice.search({query: 'foo:"bar"'}, stripe_version: '2020-08-27')
160
+ }.to raise_error(Stripe::InvalidRequestError, /Field `foo` is an unsupported search field for resource `invoices`./)
161
+ end
162
+ end
163
+
82
164
  context "paying an invoice" do
83
165
  before do
84
166
  @invoice = Stripe::Invoice.create
@@ -154,7 +236,10 @@ shared_examples 'Invoice API' do
154
236
  describe 'parameter validation' do
155
237
  it 'fails without parameters' do
156
238
  expect { Stripe::Invoice.upcoming() }.to raise_error {|e|
157
- expect(e).to be_a(ArgumentError) }
239
+ expect(e).to be_a(Stripe::InvalidRequestError)
240
+ expect(e.http_status).to eq(400)
241
+ expect(e.message).to eq('Missing required param: customer if subscription is not provided')
242
+ }
158
243
  end
159
244
 
160
245
  it 'fails without a valid customer' do