sage_pay 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,609 @@
1
+ require 'spec_helper'
2
+
3
+ include SagePay::Server
4
+
5
+ describe Registration do
6
+
7
+ it "should work straight from the factory" do
8
+ lambda {
9
+ registration_factory.should be_valid
10
+ }.should_not raise_error
11
+ end
12
+
13
+ it "should report protocol version 2.23" do
14
+ registration = Registration.new
15
+ registration.vps_protocol.should == "2.23"
16
+ end
17
+
18
+ describe "conversions" do
19
+ it "should accept a float for the amount and convert it to a BigDecimal interally" do
20
+ registration = registration_factory(:amount => 12.34)
21
+ registration.should be_valid
22
+ registration.amount.should == BigDecimal.new("12.34")
23
+ end
24
+
25
+ it "should accept an integer for the amount and convert it to a BigDecimal interally" do
26
+ registration = registration_factory(:amount => 12)
27
+ registration.should be_valid
28
+ registration.amount.should == BigDecimal.new("12")
29
+ end
30
+
31
+ it "should accept a string for the amount and convert it to a BigDecimal interally" do
32
+ registration = registration_factory(:amount => "12")
33
+ registration.should be_valid
34
+ registration.amount.should == BigDecimal.new("12")
35
+ end
36
+ end
37
+
38
+ describe "validations" do
39
+ it { validates_the_presence_of(:registration, :mode) }
40
+ it { validates_the_presence_of(:registration, :tx_type) }
41
+ it { validates_the_presence_of(:registration, :vendor) }
42
+ it { validates_the_presence_of(:registration, :vendor_tx_code) }
43
+ it { validates_the_presence_of(:registration, :amount) }
44
+ it { validates_the_presence_of(:registration, :currency) }
45
+ it { validates_the_presence_of(:registration, :description) }
46
+ it { validates_the_presence_of(:registration, :notification_url) }
47
+ it { validates_the_presence_of(:registration, :billing_address) }
48
+ it { validates_the_presence_of(:registration, :delivery_address) }
49
+
50
+ it { does_not_require_the_presence_of(:registration, :customer_email) }
51
+ it { does_not_require_the_presence_of(:registration, :basket) }
52
+ it { does_not_require_the_presence_of(:registration, :allow_gift_aid) }
53
+ it { does_not_require_the_presence_of(:registration, :apply_avs_cv2) }
54
+ it { does_not_require_the_presence_of(:registration, :apply_3d_secure) }
55
+ it { does_not_require_the_presence_of(:registration, :profile) }
56
+ it { does_not_require_the_presence_of(:registration, :billing_agreement) }
57
+ it { does_not_require_the_presence_of(:registration, :account_type) }
58
+
59
+ it { validates_the_length_of(:registration, :vendor, :max => 15) }
60
+ it { validates_the_length_of(:registration, :vendor_tx_code, :max => 40) }
61
+ it { validates_the_length_of(:registration, :currency, :exactly => 3) }
62
+ it { validates_the_length_of(:registration, :description, :max => 100) }
63
+ it { validates_the_length_of(:registration, :notification_url, :max => 255) }
64
+ it { validates_the_length_of(:registration, :notification_url, :max => 255) }
65
+ it { validates_the_length_of(:registration, :customer_email, :max => 255) }
66
+ it { validates_the_length_of(:registration, :basket, :max => 7500) }
67
+
68
+ it "should allow the amount to be a minimum of 0.01" do
69
+ registration = registration_factory(:amount => "0.01")
70
+ registration.should be_valid
71
+
72
+ registration = registration_factory(:amount => "0.00")
73
+ registration.should_not be_valid
74
+ registration.errors.on(:amount).should include("is less than the minimum value (0.01)")
75
+
76
+ registration = registration_factory(:amount => "-23")
77
+ registration.should_not be_valid
78
+ registration.errors.on(:amount).should include("is less than the minimum value (0.01)")
79
+ end
80
+
81
+ it "should allow the amount to be a maximum of 100,000.00" do
82
+ registration = registration_factory(:amount => "100000")
83
+ registration.should be_valid
84
+
85
+ registration = registration_factory(:amount => "100000.01")
86
+ registration.should_not be_valid
87
+ registration.errors.on(:amount).should include("is greater than the maximum value (100,000.00)")
88
+
89
+ registration = registration_factory(:amount => "123456")
90
+ registration.should_not be_valid
91
+ registration.errors.on(:amount).should include("is greater than the maximum value (100,000.00)")
92
+ end
93
+
94
+ it "should allow the transaction type to be one of :payment, :deferred or :authenticate" do
95
+ registration = registration_factory(:tx_type => :payment)
96
+ registration.should be_valid
97
+
98
+ registration = registration_factory(:tx_type => :deferred)
99
+ registration.should be_valid
100
+
101
+ registration = registration_factory(:tx_type => :authenticate)
102
+ registration.should be_valid
103
+
104
+ registration = registration_factory(:tx_type => :chickens)
105
+ registration.should_not be_valid
106
+ registration.errors.on(:tx_type).should include("is not in the list")
107
+ end
108
+
109
+ it "should allow the mode to be one of :simulator, :test or :live" do
110
+ registration = registration_factory(:mode => :simulator)
111
+ registration.should be_valid
112
+
113
+ registration = registration_factory(:mode => :test)
114
+ registration.should be_valid
115
+
116
+ registration = registration_factory(:mode => :live)
117
+ registration.should be_valid
118
+
119
+ registration = registration_factory(:mode => :chickens)
120
+ registration.should_not be_valid
121
+ registration.errors.on(:mode).should include("is not in the list")
122
+ end
123
+
124
+ it "should allow the gift aid setting to be true or false" do
125
+ registration = registration_factory(:allow_gift_aid => true)
126
+ registration.should be_valid
127
+
128
+ registration = registration_factory(:allow_gift_aid => false)
129
+ registration.should be_valid
130
+
131
+ registration = registration_factory(:allow_gift_aid => "chickens")
132
+ registration.should_not be_valid
133
+ registration.errors.on(:allow_gift_aid).should include("is not in the list")
134
+ end
135
+
136
+ it "should allow apply_avs_cv2 to be 0 through 3 (see docs for what that means)" do
137
+ registration = registration_factory(:apply_avs_cv2 => 0)
138
+ registration.should be_valid
139
+
140
+ registration = registration_factory(:apply_avs_cv2 => 1)
141
+ registration.should be_valid
142
+
143
+ registration = registration_factory(:apply_avs_cv2 => 2)
144
+ registration.should be_valid
145
+
146
+ registration = registration_factory(:apply_avs_cv2 => 3)
147
+ registration.should be_valid
148
+
149
+ registration = registration_factory(:apply_avs_cv2 => 4)
150
+ registration.should_not be_valid
151
+ registration.errors.on(:apply_avs_cv2).should include("is not in the list")
152
+ end
153
+
154
+ it "should allow apply_3d_secure to be 0 through 3 (see docs for what that means)" do
155
+ registration = registration_factory(:apply_3d_secure => 0)
156
+ registration.should be_valid
157
+
158
+ registration = registration_factory(:apply_3d_secure => 1)
159
+ registration.should be_valid
160
+
161
+ registration = registration_factory(:apply_3d_secure => 2)
162
+ registration.should be_valid
163
+
164
+ registration = registration_factory(:apply_3d_secure => 3)
165
+ registration.should be_valid
166
+
167
+ registration = registration_factory(:apply_3d_secure => 4)
168
+ registration.should_not be_valid
169
+ registration.errors.on(:apply_3d_secure).should include("is not in the list")
170
+ end
171
+
172
+ it "should allow profile to be normal or low" do
173
+ registration = registration_factory(:profile => :normal)
174
+ registration.should be_valid
175
+
176
+ registration = registration_factory(:profile => :low)
177
+ registration.should be_valid
178
+
179
+ registration = registration_factory(:profile => :chickens)
180
+ registration.should_not be_valid
181
+ registration.errors.on(:profile).should include("is not in the list")
182
+ end
183
+
184
+ it "should allow billing_agreement to be true or false" do
185
+ registration = registration_factory(:billing_agreement => true)
186
+ registration.should be_valid
187
+
188
+ registration = registration_factory(:billing_agreement => false)
189
+ registration.should be_valid
190
+
191
+ registration = registration_factory(:billing_agreement => "chickens")
192
+ registration.should_not be_valid
193
+ registration.errors.on(:billing_agreement).should include("is not in the list")
194
+ end
195
+
196
+ it "should allow the account type to be one of ecommerce, continuous authority or mail order" do
197
+ registration = registration_factory(:account_type => :ecommerce)
198
+ registration.should be_valid
199
+
200
+ registration = registration_factory(:account_type => :continuous_authority)
201
+ registration.should be_valid
202
+
203
+ registration = registration_factory(:account_type => :mail_order)
204
+ registration.should be_valid
205
+
206
+ registration = registration_factory(:account_type => :chickens)
207
+ registration.should_not be_valid
208
+ registration.errors.on(:account_type).should include("is not in the list")
209
+ end
210
+ end
211
+
212
+ describe "url generation" do
213
+ it "should pick the correct url for the simulator mode" do
214
+ registration = registration_factory(:mode => :simulator)
215
+ registration.url.should == "https://test.sagepay.com/simulator/VSPServerGateway.asp?Service=VendorRegisterTx"
216
+ end
217
+
218
+ it "should pick the correct url for the test mode" do
219
+ registration = registration_factory(:mode => :test)
220
+ registration.url.should == "https://test.sagepay.com/gateway/service/vspserver-register.vsp"
221
+ end
222
+
223
+ it "should pick the correct url for the live mode" do
224
+ registration = registration_factory(:mode => :live)
225
+ registration.url.should == "https://live.sagepay.com/gateway/service/vspserver-register.vsp"
226
+ end
227
+
228
+ it "should raise an error if the mode has been set to something dodgy" do
229
+ lambda {
230
+ registration = registration_factory(:mode => :dead_chickens)
231
+ registration.url
232
+ }.should raise_error(ArgumentError, "Invalid transaction mode")
233
+ end
234
+ end
235
+
236
+ describe "post params generation" do
237
+ context "given one or more invalid parameters" do
238
+ it "should raise an error when trying to generate the URL" do
239
+ registration = registration_factory(:tx_type => :invalid)
240
+ lambda { registration.post_params }.should raise_error(ArgumentError, "Invalid transaction registration options (see errors hash for details)")
241
+ end
242
+ end
243
+
244
+ context "given the minimum set of required parameters" do
245
+ before(:each) do
246
+ billing_address = address_factory(
247
+ :first_names => "Billing First",
248
+ :surname => "Billing Surname",
249
+ :address_1 => "Billing Address 1",
250
+ :city => "Billing City",
251
+ :post_code => "BI11 1NG",
252
+ :country => "GB"
253
+ )
254
+
255
+ delivery_address = address_factory(
256
+ :first_names => "Delivery First",
257
+ :surname => "Delivery Surname",
258
+ :address_1 => "Delivery Address 1",
259
+ :city => "Delivery City",
260
+ :post_code => "DE11 3RY",
261
+ :country => "GB"
262
+ )
263
+
264
+ @registration = registration_factory(
265
+ :mode => :simulator,
266
+ :tx_type => :payment,
267
+ :vendor => "vendorname",
268
+ :vendor_tx_code => "unique-tx-code",
269
+ :amount => 57.93,
270
+ :currency => "GBP",
271
+ :description => "A sample transaction",
272
+ :notification_url => "http://test.host/sample/notification",
273
+ :billing_address => billing_address,
274
+ :delivery_address => delivery_address
275
+ )
276
+ end
277
+
278
+ describe "the posted params" do
279
+ it "should contain the transaction type" do
280
+ @registration.post_params["TxType"].should == "PAYMENT"
281
+ end
282
+
283
+ it "should contain the vendor" do
284
+ @registration.post_params["Vendor"].should == "vendorname"
285
+ end
286
+
287
+ it "should contain the vendor tx code" do
288
+ @registration.post_params["VendorTxCode"].should == "unique-tx-code"
289
+ end
290
+
291
+ it "should contain the amount" do
292
+ @registration.post_params["Amount"].should == "57.93"
293
+ end
294
+
295
+ it "should contain the currency" do
296
+ @registration.post_params["Currency"].should == "GBP"
297
+ end
298
+
299
+ it "should contain the description" do
300
+ @registration.post_params["Description"].should == "A sample transaction"
301
+ end
302
+
303
+ it "should contain the notification URL" do
304
+ @registration.post_params["NotificationURL"].should == "http://test.host/sample/notification"
305
+ end
306
+
307
+ it "should contain the billing surname" do
308
+ @registration.post_params["BillingSurname"].should == "Billing Surname"
309
+ end
310
+
311
+ it "should contain the billing first names" do
312
+ @registration.post_params["BillingFirstnames"].should == "Billing First"
313
+ end
314
+
315
+ it "should contain the billing address 1" do
316
+ @registration.post_params["BillingAddress1"].should == "Billing Address 1"
317
+ end
318
+
319
+ it "should contain the billing city" do
320
+ @registration.post_params["BillingCity"].should == "Billing City"
321
+ end
322
+
323
+ it "should contain the billing post code" do
324
+ @registration.post_params["BillingPostCode"].should == "BI11 1NG"
325
+ end
326
+
327
+ it "should contain the billing country" do
328
+ @registration.post_params["BillingCountry"].should == "GB"
329
+ end
330
+
331
+ it "should contain the delivery surname" do
332
+ @registration.post_params["DeliverySurname"].should == "Delivery Surname"
333
+ end
334
+
335
+ it "should contain the delivery first names" do
336
+ @registration.post_params["DeliveryFirstnames"].should == "Delivery First"
337
+ end
338
+
339
+ it "should contain the delivery address 1" do
340
+ @registration.post_params["DeliveryAddress1"].should == "Delivery Address 1"
341
+ end
342
+
343
+ it "should contain the delivery city" do
344
+ @registration.post_params["DeliveryCity"].should == "Delivery City"
345
+ end
346
+
347
+ it "should contain the delivery post code" do
348
+ @registration.post_params["DeliveryPostCode"].should == "DE11 3RY"
349
+ end
350
+
351
+ it "should contain the delivery country" do
352
+ @registration.post_params["DeliveryCountry"].should == "GB"
353
+ end
354
+ end
355
+
356
+ context "with each of the optional parameters" do
357
+ it "should contain the billing address 2 only if supplied" do
358
+ registration = registration_factory
359
+ registration.post_params.keys.should_not include('BillingAddress2')
360
+
361
+ registration.billing_address.address_2 = "Some Area"
362
+ registration.post_params['BillingAddress2'].should == "Some Area"
363
+ end
364
+
365
+ it "should contain the billing state only if supplied" do
366
+ registration = registration_factory
367
+ registration.post_params.keys.should_not include('BillingState')
368
+
369
+ registration.billing_address.state = "KY"
370
+ registration.post_params['BillingState'].should == "KY"
371
+ end
372
+
373
+ it "should contain the billing phone only if supplied" do
374
+ registration = registration_factory
375
+ registration.post_params.keys.should_not include('BillingPhone')
376
+
377
+ registration.billing_address.phone = "0123456789"
378
+ registration.post_params['BillingPhone'].should == "0123456789"
379
+ end
380
+
381
+ it "should contain the delivery address 2 only if supplied" do
382
+ registration = registration_factory
383
+ registration.post_params.keys.should_not include('DeliveryAddress2')
384
+
385
+ registration.delivery_address.address_2 = "Some Area"
386
+ registration.post_params['DeliveryAddress2'].should == "Some Area"
387
+ end
388
+
389
+ it "should contain the delivery state only if supplied" do
390
+ registration = registration_factory
391
+ registration.post_params.keys.should_not include('DeliveryState')
392
+
393
+ registration.delivery_address.state = "KY"
394
+ registration.post_params['DeliveryState'].should == "KY"
395
+ end
396
+
397
+ it "should contain the delivery phone only if supplied" do
398
+ registration = registration_factory
399
+ registration.post_params.keys.should_not include('DeliveryPhone')
400
+
401
+ registration.delivery_address.phone = "0123456789"
402
+ registration.post_params['DeliveryPhone'].should == "0123456789"
403
+ end
404
+
405
+ it "should contain the customer email only if supplied" do
406
+ registration = registration_factory
407
+ registration.post_params.keys.should_not include('CustomerEmail')
408
+
409
+ registration.customer_email = "jimbob@example.com"
410
+ registration.post_params['CustomerEmail'].should == "jimbob@example.com"
411
+ end
412
+
413
+ it "should contain the basket only if supplied" do
414
+ registration = registration_factory
415
+ registration.post_params.keys.should_not include('Basket')
416
+
417
+ registration.basket = "Sample basket"
418
+ registration.post_params['Basket'].should == "Sample basket"
419
+ end
420
+
421
+ it "should contain allow_gift_aid only if supplied" do
422
+ registration = registration_factory
423
+ registration.post_params.keys.should_not include('AllowGiftAid')
424
+
425
+ registration.allow_gift_aid = true
426
+ registration.post_params['AllowGiftAid'].should == "1"
427
+
428
+ registration.allow_gift_aid = false
429
+ registration.post_params['AllowGiftAid'].should == "0"
430
+ end
431
+
432
+ it "should contain apply_avs_cv2 only if supplied" do
433
+ registration = registration_factory
434
+ registration.post_params.keys.should_not include('ApplyAVSCV2')
435
+
436
+ registration.apply_avs_cv2 = 0
437
+ registration.post_params['ApplyAVSCV2'].should == "0"
438
+
439
+ registration.apply_avs_cv2 = 1
440
+ registration.post_params['ApplyAVSCV2'].should == "1"
441
+
442
+ registration.apply_avs_cv2 = 2
443
+ registration.post_params['ApplyAVSCV2'].should == "2"
444
+
445
+ registration.apply_avs_cv2 = 3
446
+ registration.post_params['ApplyAVSCV2'].should == "3"
447
+ end
448
+
449
+ it "should contain apply_3d_secure only if supplied" do
450
+ registration = registration_factory
451
+ registration.post_params.keys.should_not include('ApplyAVSCV2')
452
+
453
+ registration.apply_3d_secure = 0
454
+ registration.post_params['Apply3DSecure'].should == "0"
455
+
456
+ registration.apply_3d_secure = 1
457
+ registration.post_params['Apply3DSecure'].should == "1"
458
+
459
+ registration.apply_3d_secure = 2
460
+ registration.post_params['Apply3DSecure'].should == "2"
461
+
462
+ registration.apply_3d_secure = 3
463
+ registration.post_params['Apply3DSecure'].should == "3"
464
+ end
465
+
466
+ it "should contain profile only if supplied" do
467
+ registration = registration_factory
468
+ registration.post_params.keys.should_not include('Profile')
469
+
470
+ registration.profile = :normal
471
+ registration.post_params['Profile'].should == "NORMAL"
472
+
473
+ registration.profile = :low
474
+ registration.post_params['Profile'].should == "LOW"
475
+ end
476
+
477
+ it "should contain billing_agreement only if supplied" do
478
+ registration = registration_factory
479
+ registration.post_params.keys.should_not include('BillingAgreement')
480
+
481
+ registration.billing_agreement = true
482
+ registration.post_params['BillingAgreement'].should == "1"
483
+
484
+ registration.billing_agreement = false
485
+ registration.post_params['BillingAgreement'].should == "0"
486
+ end
487
+
488
+ it "should contain account type only if supplied" do
489
+ registration = registration_factory
490
+ registration.post_params.keys.should_not include('AccountType')
491
+
492
+ registration.account_type = :ecommerce
493
+ registration.post_params['AccountType'].should == "E"
494
+
495
+ registration.account_type = :continuous_authority
496
+ registration.post_params['AccountType'].should == "C"
497
+
498
+ registration.account_type = :mail_order
499
+ registration.post_params['AccountType'].should == "M"
500
+ end
501
+ end
502
+ end
503
+ end
504
+
505
+ describe "#run!" do
506
+ context "if SagePay is having a bad day" do
507
+ before(:each) do
508
+ @registration = registration_factory
509
+ @registration.stub(:post).and_return(mock("HTTP Response", :code => "500"))
510
+ end
511
+
512
+ it "should raise an exception to say that we couldn't talk to SagePay" do
513
+ lambda {
514
+ @registration.run!
515
+ }.should raise_error RuntimeError, "I guess SagePay doesn't like us today."
516
+ end
517
+ end
518
+
519
+ context "when SagePay can return a useful response" do
520
+ before(:each) do
521
+ @mock_http_response = mock("HTTP response", :code => "200", :body => "mock response body")
522
+ @mock_response = mock("Transaction registration response")
523
+ @registration = registration_factory
524
+ @registration.stub(:post).and_return(@mock_http_response)
525
+ RegistrationResponse.stub(:from_response_body).and_return @mock_response
526
+ end
527
+
528
+ it "should return a newly created RegistrationResponse with the response" do
529
+ response = @registration.run!
530
+ response.should == @mock_response
531
+ end
532
+
533
+ it "should pass the response body to RegistrationResponse.from_response_body to let it parse and initialize" do
534
+ RegistrationResponse.should_receive(:from_response_body).with("mock response body")
535
+ @registration.run!
536
+ end
537
+
538
+ it "should post the request to SagePay" do
539
+ @registration.should_receive(:post)
540
+ @registration.run!
541
+ end
542
+
543
+ it "should not allow us to attempt to register twice with the same vendor transaction code" do
544
+ @registration.run!
545
+ lambda {
546
+ @registration.run!
547
+ }.should raise_error(RuntimeError, "This vendor transaction code has already been registered")
548
+ end
549
+
550
+ it "should allow us to register twice if we change the vendor transaction code in between times" do
551
+ @registration.run!
552
+ lambda {
553
+ @registration.vendor_tx_code = TransactionCode.random
554
+ @registration.run!.should == @mock_response
555
+ }.should_not raise_error(RuntimeError, "This vendor transaction code has already been registered")
556
+ end
557
+ end
558
+ end
559
+
560
+ describe "#signature_verification_details" do
561
+ before(:each) do
562
+ mock_response = mock("Transaction registration response", :vps_tx_id => "sage pay transaction id", :security_key => 'security key')
563
+
564
+ @registration = registration_factory :vendor_tx_code => "vendor transaction id", :vendor => "vendor"
565
+ @registration.stub(:handle_response).and_return(mock_response)
566
+ @registration.stub(:post)
567
+ end
568
+
569
+ context "before registering a transaction" do
570
+ it "should raise an error" do
571
+ lambda {
572
+ @registration.signature_verification_details
573
+ }.should raise_error(RuntimeError, "Not yet registered")
574
+ end
575
+ end
576
+
577
+ context "with a transaction which failed" do
578
+ before(:each) do
579
+ mock_response = mock("Transaction registration response", :failed? => true)
580
+ @registration.stub(:handle_response).and_return(mock_response)
581
+ @registration.run!
582
+ end
583
+
584
+ it "should raise an error" do
585
+ lambda {
586
+ @registration.signature_verification_details
587
+ }.should raise_error(RuntimeError, "Registration failed")
588
+ end
589
+ end
590
+
591
+ context "with a good transaction" do
592
+ before(:each) do
593
+ mock_response = mock("Transaction registration response", :failed? => false, :vps_tx_id => "sage pay transaction id", :security_key => 'security key')
594
+ @registration.stub(:handle_response).and_return(mock_response)
595
+ @registration.run!
596
+ end
597
+
598
+ it "should know the vendor" do
599
+ sig_details = @registration.signature_verification_details
600
+ sig_details.vendor.should == "vendor"
601
+ end
602
+
603
+ it "should know the security key" do
604
+ sig_details = @registration.signature_verification_details
605
+ sig_details.security_key.should == "security key"
606
+ end
607
+ end
608
+ end
609
+ end