braintree 2.90.0 → 2.91.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/braintree.gemspec +5 -0
  3. data/lib/braintree/configuration.rb +39 -1
  4. data/lib/braintree/credit_card.rb +1 -0
  5. data/lib/braintree/error_codes.rb +8 -0
  6. data/lib/braintree/graphql_client.rb +28 -0
  7. data/lib/braintree/http.rb +21 -9
  8. data/lib/braintree/local_payment_completed.rb +20 -0
  9. data/lib/braintree/test/credit_card.rb +2 -0
  10. data/lib/braintree/transaction.rb +8 -0
  11. data/lib/braintree/transaction_gateway.rb +4 -0
  12. data/lib/braintree/util.rb +44 -3
  13. data/lib/braintree/validation_error.rb +10 -2
  14. data/lib/braintree/validation_error_collection.rb +2 -1
  15. data/lib/braintree/version.rb +1 -1
  16. data/lib/braintree/webhook_notification.rb +5 -1
  17. data/lib/braintree/webhook_testing_gateway.rb +34 -3
  18. data/lib/braintree.rb +3 -1
  19. data/spec/integration/braintree/credit_card_spec.rb +14 -0
  20. data/spec/integration/braintree/dispute_spec.rb +3 -0
  21. data/spec/integration/braintree/graphql_client_spec.rb +74 -0
  22. data/spec/integration/braintree/http_spec.rb +1 -1
  23. data/spec/integration/braintree/transaction_search_spec.rb +19 -0
  24. data/spec/integration/braintree/transaction_spec.rb +203 -2
  25. data/spec/spec_helper.rb +1 -0
  26. data/spec/unit/braintree/configuration_spec.rb +37 -0
  27. data/spec/unit/braintree/http_spec.rb +65 -0
  28. data/spec/unit/braintree/local_payment_completed_spec.rb +24 -0
  29. data/spec/unit/braintree/transaction_spec.rb +8 -0
  30. data/spec/unit/braintree/util_spec.rb +109 -0
  31. data/spec/unit/braintree/validation_error_collection_spec.rb +335 -132
  32. data/spec/unit/braintree/webhook_notification_spec.rb +31 -0
  33. metadata +10 -3
@@ -18,7 +18,7 @@ describe Braintree::Http do
18
18
  it "raises an AuthorizationError if authorization fails" do
19
19
  expect do
20
20
  config = Braintree::Configuration.instantiate
21
- config.http.get("#{config.base_merchant_path}/downloads")
21
+ config.http.get("#{config.base_merchant_path}/home")
22
22
  end.to raise_error(Braintree::AuthorizationError)
23
23
  end
24
24
  end
@@ -293,6 +293,25 @@ describe Braintree::Transaction, "search" do
293
293
  collection.maximum_size.should == 0
294
294
  end
295
295
 
296
+ it "searches for an Elo card" do
297
+ transaction = Braintree::Transaction.sale!(
298
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
299
+ :merchant_account_id => SpecHelper::AdyenMerchantAccountId,
300
+ :credit_card => {
301
+ :number => Braintree::Test::CreditCardNumbers::Elo,
302
+ :cvv => "737",
303
+ :expiration_date => "10/2020"
304
+ }
305
+ )
306
+
307
+ collection = Braintree::Transaction.search do |search|
308
+ search.id.is transaction.id
309
+ search.credit_card_card_type.is Braintree::CreditCard::CardType::Elo
310
+ end
311
+
312
+ collection.maximum_size.should == 1
313
+ end
314
+
296
315
  it "searches by payment instrument type CreditCardDetail" do
297
316
  transaction = Braintree::Transaction.sale!(
298
317
  :amount => Braintree::Test::TransactionAmounts::Authorize,
@@ -248,6 +248,31 @@ describe Braintree::Transaction do
248
248
  end
249
249
  end
250
250
 
251
+ context "elo" do
252
+ it "returns a successful result if successful" do
253
+ result = Braintree::Transaction.create(
254
+ :type => "sale",
255
+ :merchant_account_id => SpecHelper::AdyenMerchantAccountId,
256
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
257
+ :credit_card => {
258
+ :number => Braintree::Test::CreditCardNumbers::Elo,
259
+ :cvv => "737",
260
+ :expiration_date => "10/2020"
261
+ }
262
+ )
263
+ result.success?.should == true
264
+ result.transaction.id.should =~ /^\w{6,}$/
265
+ result.transaction.type.should == "sale"
266
+ result.transaction.amount.should == BigDecimal.new(Braintree::Test::TransactionAmounts::Authorize)
267
+ result.transaction.processor_authorization_code.should_not be_nil
268
+ result.transaction.voice_referral_number.should be_nil
269
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Elo[0, 6]
270
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Elo[-4..-1]
271
+ result.transaction.credit_card_details.expiration_date.should == "10/2020"
272
+ result.transaction.credit_card_details.customer_location.should == "US"
273
+ end
274
+ end
275
+
251
276
  it "returns a successful result if successful" do
252
277
  result = Braintree::Transaction.create(
253
278
  :type => "sale",
@@ -3617,6 +3642,182 @@ describe Braintree::Transaction do
3617
3642
  result.errors.for(:transaction).on(:ships_from_postal_code)[0].code.should == Braintree::ErrorCodes::Transaction::ShipsFromPostalCodeInvalidCharacters
3618
3643
  end
3619
3644
  end
3645
+
3646
+ context "network_transaction_id" do
3647
+ it "receives network_transaction_id for visa transaction" do
3648
+ result = Braintree::Transaction.create(
3649
+ :type => "sale",
3650
+ :credit_card => {
3651
+ :number => Braintree::Test::CreditCardNumbers::Visa,
3652
+ :expiration_date => "05/2009"
3653
+ },
3654
+ :amount => "10.00",
3655
+ )
3656
+ result.success?.should == true
3657
+ result.transaction.network_transaction_id.should_not be_nil
3658
+ end
3659
+ end
3660
+
3661
+ context "external vault" do
3662
+ it "returns a validation error if used with an unsupported instrument type" do
3663
+ customer = Braintree::Customer.create!
3664
+ result = Braintree::PaymentMethod.create(
3665
+ :payment_method_nonce => Braintree::Test::Nonce::PayPalFuturePayment,
3666
+ :customer_id => customer.id
3667
+ )
3668
+ payment_method_token = result.payment_method.token
3669
+
3670
+ result = Braintree::Transaction.create(
3671
+ :type => "sale",
3672
+ :customer_id => customer.id,
3673
+ :payment_method_token => payment_method_token,
3674
+ :external_vault => {
3675
+ :status => Braintree::Transaction::ExternalVault::Status::WillVault,
3676
+ },
3677
+ :amount => "10.00",
3678
+ )
3679
+ result.success?.should == false
3680
+ result.errors.for(:transaction)[0].code.should == Braintree::ErrorCodes::Transaction::PaymentInstrumentWithExternalVaultIsInvalid
3681
+ end
3682
+
3683
+ it "reject invalid status" do
3684
+ result = Braintree::Transaction.create(
3685
+ :type => "sale",
3686
+ :credit_card => {
3687
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
3688
+ :expiration_date => "05/2009"
3689
+ },
3690
+ :external_vault => {
3691
+ :status => "not_valid",
3692
+ },
3693
+ :amount => "10.00",
3694
+ )
3695
+ result.success?.should == false
3696
+ result.errors.for(:transaction).for(:external_vault).on(:status)[0].code.should == Braintree::ErrorCodes::Transaction::ExternalVault::StatusIsInvalid
3697
+ end
3698
+
3699
+ context "Visa" do
3700
+ it "accepts status" do
3701
+ result = Braintree::Transaction.create(
3702
+ :type => "sale",
3703
+ :credit_card => {
3704
+ :number => Braintree::Test::CreditCardNumbers::Visa,
3705
+ :expiration_date => "05/2009"
3706
+ },
3707
+ :external_vault => {
3708
+ :status => Braintree::Transaction::ExternalVault::Status::WillVault,
3709
+ },
3710
+ :amount => "10.00",
3711
+ )
3712
+ result.success?.should == true
3713
+ result.transaction.network_transaction_id.should_not be_nil
3714
+ end
3715
+
3716
+ it "accepts previous_network_transaction_id" do
3717
+ result = Braintree::Transaction.create(
3718
+ :type => "sale",
3719
+ :credit_card => {
3720
+ :number => Braintree::Test::CreditCardNumbers::Visa,
3721
+ :expiration_date => "05/2009"
3722
+ },
3723
+ :external_vault => {
3724
+ :status => Braintree::Transaction::ExternalVault::Status::Vaulted,
3725
+ :previous_network_transaction_id => "123456789012345",
3726
+ },
3727
+ :amount => "10.00",
3728
+ )
3729
+ result.success?.should == true
3730
+ result.transaction.network_transaction_id.should_not be_nil
3731
+ end
3732
+
3733
+ it "rejects non-vaulted status with previous_network_transaction_id" do
3734
+ result = Braintree::Transaction.create(
3735
+ :type => "sale",
3736
+ :credit_card => {
3737
+ :number => Braintree::Test::CreditCardNumbers::Visa,
3738
+ :expiration_date => "05/2009"
3739
+ },
3740
+ :external_vault => {
3741
+ :status => Braintree::Transaction::ExternalVault::Status::WillVault,
3742
+ :previous_network_transaction_id => "123456789012345",
3743
+ },
3744
+ :amount => "10.00",
3745
+ )
3746
+ result.success?.should == false
3747
+ result.errors.for(:transaction).for(:external_vault).on(:status)[0].code.should == Braintree::ErrorCodes::Transaction::ExternalVault::StatusWithPreviousNetworkTransactionIdIsInvalid
3748
+ end
3749
+
3750
+ it "rejects invalid previous_network_transaction_id" do
3751
+ result = Braintree::Transaction.create(
3752
+ :type => "sale",
3753
+ :credit_card => {
3754
+ :number => Braintree::Test::CreditCardNumbers::Visa,
3755
+ :expiration_date => "05/2009"
3756
+ },
3757
+ :external_vault => {
3758
+ :status => Braintree::Transaction::ExternalVault::Status::Vaulted,
3759
+ :previous_network_transaction_id => "not_and_valid_id",
3760
+ },
3761
+ :amount => "10.00",
3762
+ )
3763
+ result.success?.should == false
3764
+ result.errors.for(:transaction).for(:external_vault).on(:previous_network_transaction_id)[0].code.should == Braintree::ErrorCodes::Transaction::ExternalVault::PreviousNetworkTransactionIdIsInvalid
3765
+ end
3766
+ end
3767
+
3768
+ context "Non-Visa" do
3769
+ it "accepts status" do
3770
+ result = Braintree::Transaction.create(
3771
+ :type => "sale",
3772
+ :credit_card => {
3773
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
3774
+ :expiration_date => "05/2009"
3775
+ },
3776
+ :external_vault => {
3777
+ :status => Braintree::Transaction::ExternalVault::Status::WillVault,
3778
+ },
3779
+ :amount => "10.00",
3780
+ )
3781
+ result.success?.should == true
3782
+ result.transaction.network_transaction_id.should be_nil
3783
+ end
3784
+
3785
+ it "accepts blank previous_network_transaction_id" do
3786
+ result = Braintree::Transaction.create(
3787
+ :type => "sale",
3788
+ :credit_card => {
3789
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
3790
+ :expiration_date => "05/2009"
3791
+ },
3792
+ :external_vault => {
3793
+ :status => Braintree::Transaction::ExternalVault::Status::Vaulted,
3794
+ :previous_network_transaction_id => "",
3795
+ },
3796
+ :amount => "10.00",
3797
+ )
3798
+ result.success?.should == true
3799
+ result.transaction.network_transaction_id.should be_nil
3800
+ end
3801
+
3802
+ it "rejects previous_network_transaction_id" do
3803
+ result = Braintree::Transaction.create(
3804
+ :type => "sale",
3805
+ :credit_card => {
3806
+ :number => Braintree::Test::CreditCardNumbers::Discover,
3807
+ :expiration_date => "05/2009"
3808
+ },
3809
+ :external_vault => {
3810
+ :status => Braintree::Transaction::ExternalVault::Status::Vaulted,
3811
+ :previous_network_transaction_id => "123456789012345",
3812
+ },
3813
+ :amount => "10.00",
3814
+ )
3815
+ result.success?.should == false
3816
+ result.errors.for(:transaction).for(:external_vault).on(:previous_network_transaction_id)[0].code.should == Braintree::ErrorCodes::Transaction::ExternalVault::CardTypeIsInvalid
3817
+ end
3818
+ end
3819
+
3820
+ end
3620
3821
  end
3621
3822
 
3622
3823
  describe "self.create!" do
@@ -4808,8 +5009,8 @@ describe Braintree::Transaction do
4808
5009
  it "returns an error with an invalid payment instrument type" do
4809
5010
  authorized_transaction = Braintree::Transaction.sale!(
4810
5011
  :amount => Braintree::Test::TransactionAmounts::Authorize,
4811
- :merchant_account_id => SpecHelper::DefaultMerchantAccountId,
4812
- :payment_method_nonce => Braintree::Test::Nonce::AndroidPayDiscover
5012
+ :merchant_account_id => SpecHelper::FakeVenmoAccountMerchantAccountId,
5013
+ :payment_method_nonce => Braintree::Test::Nonce::VenmoAccount
4813
5014
  )
4814
5015
 
4815
5016
  result = Braintree::Transaction.submit_for_partial_settlement(authorized_transaction.id, 100)
data/spec/spec_helper.rb CHANGED
@@ -42,6 +42,7 @@ unless defined?(SPEC_HELPER_LOADED)
42
42
  UsBankMerchantAccountId = "us_bank_merchant_account"
43
43
  AnotherUsBankMerchantAccountId = "another_us_bank_merchant_account"
44
44
  IdealMerchantAccountId = "ideal_merchant_account"
45
+ AdyenMerchantAccountId = "adyen_ma"
45
46
 
46
47
  TrialPlan = {
47
48
  :description => "Plan for integration tests -- with trial",
@@ -167,6 +167,19 @@ describe Braintree::Configuration do
167
167
  config = Braintree::Configuration.new :logger => nil
168
168
  config.logger.should_not == nil
169
169
  end
170
+
171
+ it "can set logger on gateway instance" do
172
+ gateway = Braintree::Configuration.gateway
173
+ old_logger = Braintree::Configuration.logger
174
+
175
+ new_logger = Logger.new("/dev/null")
176
+
177
+ gateway.config.logger = new_logger
178
+
179
+ expect(gateway.config.logger).to eq(new_logger)
180
+
181
+ gateway.config.logger = old_logger
182
+ end
170
183
  end
171
184
 
172
185
  describe "self.environment" do
@@ -183,6 +196,14 @@ describe Braintree::Configuration do
183
196
  Braintree::Configuration.environment
184
197
  end.to raise_error(Braintree::ConfigurationError, "Braintree::Configuration.environment needs to be set")
185
198
  end
199
+
200
+ it "converts environment to symbol" do
201
+ config = Braintree::Configuration.new({
202
+ :environment => "sandbox"
203
+ })
204
+
205
+ expect(config.environment).to eq(:sandbox)
206
+ end
186
207
  end
187
208
 
188
209
  describe "self.gateway" do
@@ -335,6 +356,22 @@ describe Braintree::Configuration do
335
356
  end
336
357
  end
337
358
 
359
+ describe "graphql_server" do
360
+ it "is localhost or GRAPHQL_HOST environment variable for development" do
361
+ Braintree::Configuration.environment = :development
362
+ old_gateway_url = ENV['GRAPHQL_HOST']
363
+ begin
364
+ ENV['GRAPHQL_HOST'] = nil
365
+ Braintree::Configuration.instantiate.graphql_server.should == "graphql.bt.local"
366
+
367
+ ENV['GRAPHQL_HOST'] = 'gateway'
368
+ Braintree::Configuration.instantiate.graphql_server.should == 'gateway'
369
+ ensure
370
+ ENV['GRAPHQL_HOST'] = old_gateway_url
371
+ end
372
+ end
373
+ end
374
+
338
375
  describe "server" do
339
376
  it "is localhost or GATEWAY_HOST environment variable for development" do
340
377
  Braintree::Configuration.environment = :development
@@ -59,7 +59,9 @@ END
59
59
  END
60
60
  Braintree::Http.new(:config)._format_and_sanitize_body_for_log(input_xml).should == expected_xml
61
61
  end
62
+ end
62
63
 
64
+ describe "self._http_do" do
63
65
  it "connects when proxy address is specified" do
64
66
  config = Braintree::Configuration.new(
65
67
  :proxy_address => "localhost",
@@ -116,6 +118,69 @@ END
116
118
  end
117
119
  end
118
120
 
121
+ describe "_compose_headers" do
122
+ before (:each) do
123
+ config = Braintree::Configuration.new
124
+ @http = Braintree::Http.new(config)
125
+ end
126
+
127
+ it "returns a hash of default headers" do
128
+ default_headers = @http._compose_headers
129
+ expect(default_headers["Accept"]).to eq("application/xml")
130
+ expect(default_headers["Accept-Encoding"]).to eq("gzip")
131
+ expect(default_headers["Content-Type"]).to eq("application/xml")
132
+ expect(default_headers["User-Agent"]).to match(/Braintree Ruby Gem .*/)
133
+ expect(default_headers["X-ApiVersion"]).to eq("5")
134
+ end
135
+
136
+ it "overwrites defaults with override headers" do
137
+ override_headers = {
138
+ "Accept" => "application/pdf",
139
+ "Authorization" => "token"
140
+ }
141
+ headers = @http._compose_headers(override_headers)
142
+ expect(headers["Accept"]).to eq("application/pdf")
143
+ expect(headers["Accept-Encoding"]).to eq("gzip")
144
+ expect(headers["Authorization"]).to eq("token")
145
+ expect(headers["Content-Type"]).to eq("application/xml")
146
+ expect(headers["User-Agent"]).to match(/Braintree Ruby Gem .*/)
147
+ expect(headers["X-ApiVersion"]).to eq("5")
148
+ end
149
+
150
+ it "extends default headers when new headers are specified" do
151
+ override_headers = {
152
+ "New-Header" => "New Value"
153
+ }
154
+ headers = @http._compose_headers(override_headers)
155
+ expect(headers["Accept"]).to eq("application/xml")
156
+ expect(headers["Accept-Encoding"]).to eq("gzip")
157
+ expect(headers["Content-Type"]).to eq("application/xml")
158
+ expect(headers["User-Agent"]).to match(/Braintree Ruby Gem .*/)
159
+ expect(headers["X-ApiVersion"]).to eq("5")
160
+ expect(headers["New-Header"]).to eq("New Value")
161
+ end
162
+ end
163
+
164
+ describe "_setup_connection" do
165
+ it "creates a new Net::HTTP object using default server and port" do
166
+ config = Braintree::Configuration.new
167
+ http = Braintree::Http.new(config)
168
+
169
+ connection = http._setup_connection
170
+ expect(connection.address).to eq(nil)
171
+ expect(connection.port).to eq(80)
172
+ end
173
+
174
+ it "overrides the default server and port when replacements are specified" do
175
+ config = Braintree::Configuration.new
176
+ http = Braintree::Http.new(config)
177
+
178
+ connection = http._setup_connection("localhost", 3443)
179
+ expect(connection.address).to eq("localhost")
180
+ expect(connection.port).to eq(3443)
181
+ end
182
+ end
183
+
119
184
  describe "_build_query_string" do
120
185
  it "returns an empty string for empty query params" do
121
186
  Braintree::Http.new(:config)._build_query_string({}).should == ""
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::LocalPaymentCompleted do
4
+ describe "self.new" do
5
+ it "is protected" do
6
+ expect do
7
+ Braintree::LocalPaymentCompleted.new
8
+ end.to raise_error(NoMethodError, /protected method .new/)
9
+ end
10
+ end
11
+
12
+ describe "self._new" do
13
+ it "initializes the object with the appropriate attributes set" do
14
+ params = {
15
+ payment_id: "a-payment-id",
16
+ payer_id: "a-payer-id",
17
+ }
18
+ local_payment_completed = Braintree::LocalPaymentCompleted._new(params)
19
+
20
+ local_payment_completed.payment_id.should eq("a-payment-id")
21
+ local_payment_completed.payer_id.should eq("a-payer-id")
22
+ end
23
+ end
24
+ end
@@ -255,6 +255,14 @@ describe Braintree::Transaction do
255
255
  )
256
256
  transaction.risk_data.should be_nil
257
257
  end
258
+
259
+ it "accepts network_transaction_id" do
260
+ transaction = Braintree::Transaction._new(
261
+ :gateway,
262
+ :network_transaction_id => "123456789012345"
263
+ )
264
+ transaction.network_transaction_id.should == "123456789012345"
265
+ end
258
266
  end
259
267
 
260
268
  describe "inspect" do
@@ -119,6 +119,58 @@ describe Braintree::Util do
119
119
  end
120
120
  end
121
121
 
122
+ describe "self.keys_valid?" do
123
+ it "returns true for wildcard matches" do
124
+ response = Braintree::Util.keys_valid?(
125
+ [:allowed, {:custom_fields => :_any_key_}],
126
+ :allowed => "ok",
127
+ :custom_fields => {
128
+ :custom_allowed => "ok",
129
+ :custom_allowed2 => "also ok",
130
+ }
131
+ )
132
+ expect(response).to eq(true)
133
+ end
134
+ it "raises an exception if the hash contains an invalid key" do
135
+ response = Braintree::Util.keys_valid?([:allowed], :allowed => "ok", :disallowed => "bad")
136
+ expect(response).to eq(false)
137
+ end
138
+
139
+ it "raises an exception with all keys listed if the hash contains invalid keys" do
140
+ response = Braintree::Util.keys_valid?([:allowed], :allowed => "ok", :disallowed => "bad", "also_invalid" => true)
141
+ expect(response).to eq(false)
142
+ end
143
+
144
+ it "returns false for invalid key inside of array" do
145
+ response = Braintree::Util.keys_valid?(
146
+ [{:add_ons => [{:update => [:amount]}, {:add => [:amount]}]}],
147
+ :add_ons => {
148
+ :update => [{:foo => 10}],
149
+ :add => [{:bar => 5}]
150
+ }
151
+ )
152
+ expect(response).to eq(false)
153
+ end
154
+
155
+ it "returns false if a deeply nested hash contains an invalid key" do
156
+ response = Braintree::Util.keys_valid?(
157
+ [:allowed, {:nested => [:nested_allowed, :nested_allowed2, {:deeply_allowed => [:super_deep_allowed]}]}],
158
+ :allowed => "ok",
159
+ :top_level_invalid => "bad",
160
+ :nested => {
161
+ :nested_allowed => "ok",
162
+ :nested_allowed2 => "also ok",
163
+ :nested_invalid => "bad",
164
+ :deeply_allowed => {
165
+ :super_deep_allowed => "yep",
166
+ :real_deep_invalid => "nope"
167
+ }
168
+ }
169
+ )
170
+ expect(response).to eq(false)
171
+ end
172
+ end
173
+
122
174
  describe "self._flatten_hash_keys" do
123
175
  it "flattens hash keys" do
124
176
  Braintree::Util._flatten_hash_keys(:nested => {
@@ -199,6 +251,63 @@ describe Braintree::Util do
199
251
  end
200
252
  end
201
253
 
254
+ describe "self.raise_exception_for_graphql_error" do
255
+ errors = {
256
+ "AUTHENTICATION" => Braintree::AuthenticationError,
257
+ "AUTHORIZATION" => Braintree::AuthorizationError,
258
+ "NOT_FOUND" => Braintree::NotFoundError,
259
+ "UNSUPPORTED_CLIENT" => Braintree::UpgradeRequiredError,
260
+ "RESOURCE_LIMIT" => Braintree::TooManyRequestsError,
261
+ "INTERNAL" => Braintree::ServerError,
262
+ "SERVICE_AVAILABILITY" => Braintree::DownForMaintenanceError,
263
+ }
264
+
265
+ errors.each do |graphQLError, exception|
266
+ it "raises an #{exception} when GraphQL returns an #{graphQLError} error" do
267
+ response = {
268
+ errors: [{
269
+ extensions: {
270
+ errorClass: graphQLError
271
+ }
272
+ }]
273
+ }
274
+ expect do
275
+ Braintree::Util.raise_exception_for_graphql_error(response)
276
+ end.to raise_error(exception)
277
+ end
278
+ end
279
+
280
+ it "does not raise an exception when GraphQL returns a validation error" do
281
+ response = {
282
+ errors: [{
283
+ extensions: {
284
+ errorClass: "VALIDATION"
285
+ }
286
+ }]
287
+ }
288
+ expect do
289
+ Braintree::Util.raise_exception_for_graphql_error(response)
290
+ end.to_not raise_error()
291
+ end
292
+
293
+ it "raises any non-validation errorClass response" do
294
+ response = {
295
+ errors: [{
296
+ extensions: {
297
+ errorClass: "VALIDATION"
298
+ }
299
+ }, {
300
+ extensions: {
301
+ errorClass: "NOT_FOUND"
302
+ }
303
+ }]
304
+ }
305
+ expect do
306
+ Braintree::Util.raise_exception_for_graphql_error(response)
307
+ end.to raise_error(Braintree::NotFoundError)
308
+ end
309
+ end
310
+
202
311
  describe "self.raise_exception_for_status_code" do
203
312
  it "raises an AuthenticationError if authentication fails" do
204
313
  expect do