defra_ruby_mocks 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,9 +24,9 @@ module DefraRubyMocks
24
24
  let(:data) { File.read("spec/fixtures/payment_request_valid.xml") }
25
25
 
26
26
  it "returns an XML response with a 200 code" do
27
- get path, {}, "RAW_POST_DATA" => data
27
+ get path, headers: { "RAW_POST_DATA" => data }
28
28
 
29
- expect(response.content_type).to eq("application/xml")
29
+ expect(response.media_type).to eq("application/xml")
30
30
  expect(response.code).to eq("200")
31
31
  expect(response.body).to be_xml
32
32
  end
@@ -36,7 +36,7 @@ module DefraRubyMocks
36
36
  let(:data) { File.read("spec/fixtures/payment_request_invalid.xml") }
37
37
 
38
38
  it "returns a response with a 500 code" do
39
- get path, {}, "RAW_POST_DATA" => data
39
+ get path, headers: { "RAW_POST_DATA" => data }
40
40
 
41
41
  expect(response.code).to eq("500")
42
42
  end
@@ -48,9 +48,9 @@ module DefraRubyMocks
48
48
  let(:data) { File.read("spec/fixtures/refund_request_valid.xml") }
49
49
 
50
50
  it "returns an XML response with a 200 code" do
51
- get path, {}, "RAW_POST_DATA" => data
51
+ get path, headers: { "RAW_POST_DATA" => data }
52
52
 
53
- expect(response.content_type).to eq("application/xml")
53
+ expect(response.media_type).to eq("application/xml")
54
54
  expect(response.code).to eq("200")
55
55
  expect(response.body).to be_xml
56
56
  end
@@ -59,30 +59,74 @@ module DefraRubyMocks
59
59
  end
60
60
 
61
61
  context "#dispatcher" do
62
- let(:relation) { double(:relation, first: registration) }
63
- let(:registration) { double(:registration, finance_details: finance_details) }
64
- let(:finance_details) { double(:finance_details, orders: orders) }
65
- let(:orders) { double(:orders, order_by: sorted_orders) }
66
- let(:sorted_orders) { double(:sorted_orders, first: order) }
67
- let(:order) { double(:order, order_code: "987654", total_amount: 105_00) }
68
-
69
- let(:path) { "/defra_ruby_mocks/worldpay/dispatcher?successURL=#{CGI.escape(success_url)}" }
62
+ let(:success_url) { "http://example.com/fo/12345/worldpay/success" }
63
+ let(:failure_url) { "http://example.com/fo/12345/worldpay/failure" }
64
+ let(:pending_url) { "http://example.com/fo/12345/worldpay/pending" }
65
+ let(:cancel_url) { "http://example.com/fo/12345/worldpay/cancel" }
66
+ let(:error_url) { "http://example.com/fo/12345/worldpay/error" }
67
+ let(:response_url) { "#{success_url}?orderKey=admincode1^^987654&paymentStatus=#{status}&paymentAmount=10500&paymentCurrency=GBP&mac=0ba5271e1ed1b26f9bb428ef7fb536a4&source=WP" }
68
+ let(:path) do
69
+ root = "/defra_ruby_mocks/worldpay/dispatcher"
70
+ escaped_success = CGI.escape(success_url)
71
+ escaped_failure = CGI.escape(failure_url)
72
+ escaped_pending = CGI.escape(pending_url)
73
+ escaped_cancel = CGI.escape(cancel_url)
74
+ escaped_error = CGI.escape(error_url)
75
+
76
+ "#{root}?successURL=#{escaped_success}&failureURL=#{escaped_failure}&pendingURL=#{escaped_pending}&cancelURL=#{escaped_cancel}&errorURL=#{escaped_error}"
77
+ end
78
+ let(:service_response) do
79
+ double(
80
+ :response,
81
+ supplied_url: success_url,
82
+ url: response_url,
83
+ status: status,
84
+ separator: "?",
85
+ order_key: "admincode1",
86
+ mac: "e5bc7ce5dfe44d2000771ac2b157f0e9",
87
+ value: 154_00,
88
+ reference: "12345"
89
+ )
90
+ end
70
91
 
71
92
  context "and the request is valid" do
72
- let(:response_params) { "orderKey=admincode1^^987654&paymentStatus=AUTHORISED&paymentAmount=10500&paymentCurrency=GBP&mac=0ba5271e1ed1b26f9bb428ef7fb536a4&source=WP" }
73
- let(:success_url) { "http://example.com/fo/12345/worldpay/success" }
93
+ before(:each) do
94
+ allow(WorldpayResponseService).to receive(:run)
95
+ .with(
96
+ success_url: success_url,
97
+ failure_url: failure_url,
98
+ pending_url: pending_url,
99
+ cancel_url: cancel_url,
100
+ error_url: error_url
101
+ ) { service_response }
102
+ end
103
+
104
+ context "and a response is expected" do
105
+ let(:status) { "AUTHORISED" }
106
+
107
+ it "redirects the user with a 300 code" do
108
+ get path
74
109
 
75
- it "redirects the user with a 300 code" do
76
- expect(::WasteCarriersEngine::TransientRegistration).to receive(:where) { relation }
110
+ expect(response).to redirect_to(response_url)
111
+ expect(response.code).to eq("302")
112
+ end
113
+ end
77
114
 
78
- get path
115
+ context "and a response is not expected" do
116
+ let(:status) { :STUCK }
117
+
118
+ it "renders the Worldpay stuck page" do
119
+ get path
79
120
 
80
- expect(response).to redirect_to("#{success_url}?#{response_params}")
81
- expect(response.code).to eq("302")
121
+ expect(response).to render_template(:stuck)
122
+ expect(response.code).to eq("200")
123
+ end
82
124
  end
83
125
  end
84
126
 
85
127
  context "and the request is invalid" do
128
+ before(:each) { allow(WorldpayResponseService).to receive(:run).and_raise(MissingResourceError.new("foo")) }
129
+
86
130
  context "because the success url is not in a recognised format" do
87
131
  let(:success_url) { "http://example.com/forthewin" }
88
132
 
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails_helper"
4
+
5
+ module DefraRubyMocks
6
+ RSpec.describe WorldpayResourceService do
7
+ before(:each) do
8
+ allow(::WasteCarriersEngine::TransientRegistration).to receive(:where) { transient_relation }
9
+ allow(::WasteCarriersEngine::Registration).to receive(:where) { registration_relation }
10
+ end
11
+
12
+ let(:reference) { "12345" }
13
+ let(:company_name) { "Pay for the thing" }
14
+
15
+ let(:resource) { double(:resource, finance_details: finance_details, company_name: company_name) }
16
+ let(:finance_details) { double(:finance_details, orders: orders) }
17
+ let(:orders) { double(:orders, order_by: sorted_orders) }
18
+ let(:sorted_orders) { double(:sorted_orders, first: order) }
19
+ let(:order) { double(:order) }
20
+
21
+ let(:args) { { reference: reference } }
22
+
23
+ describe ".run" do
24
+
25
+ context "when the resource is a TransientRegistration" do
26
+ let(:transient_relation) { double(:relation, first: resource) }
27
+
28
+ it "will only search transient registrations" do
29
+ described_class.run(args)
30
+
31
+ expect(::WasteCarriersEngine::TransientRegistration).to have_received(:where).with(token: reference)
32
+
33
+ expect(::WasteCarriersEngine::Registration).not_to have_received(:where).with(reg_uuid: reference)
34
+ end
35
+
36
+ it "returns an object with the matching resource" do
37
+ expect(described_class.run(args).resource).to eq(resource)
38
+ end
39
+
40
+ it "returns an object with the expected order" do
41
+ expect(described_class.run(args).order).to eq(order)
42
+ end
43
+
44
+ it "returns an object with the expected company name" do
45
+ expect(described_class.run(args).company_name).to eq(company_name.downcase)
46
+ end
47
+ end
48
+
49
+ context "when the resource is a Registration" do
50
+ let(:transient_relation) { double(:relation, first: nil) }
51
+ let(:registration_relation) { double(:relation, first: resource) }
52
+
53
+ it "will search transient registrations first, then registrations" do
54
+ described_class.run(args)
55
+
56
+ expect(::WasteCarriersEngine::TransientRegistration).to have_received(:where).with(token: reference)
57
+
58
+ expect(::WasteCarriersEngine::Registration).to have_received(:where).with(reg_uuid: reference)
59
+ end
60
+
61
+ it "returns an object with the matching resource" do
62
+ expect(described_class.run(args).resource).to eq(resource)
63
+ end
64
+
65
+ it "returns an object with the expected order" do
66
+ expect(described_class.run(args).order).to eq(order)
67
+ end
68
+
69
+ it "returns an object with the expected company name" do
70
+ expect(described_class.run(args).company_name).to eq(company_name.downcase)
71
+ end
72
+ end
73
+
74
+ context "when the resource is a OrderCopyCardsRegistration" do
75
+ before do
76
+ # Because we do not copy the company name to
77
+ # `OrderCopyCardsRegistration` instances when we create them in WCR
78
+ # we need to locate the orignal registration they are based on. We
79
+ # determine in the class if the 'resource' is an instance of one by
80
+ # comparing the result of resource.class.to_s to
81
+ # "WasteCarriersEngine::OrderCopyCardsRegistration". The problem is
82
+ # when testing 'resource' is actually an instance of
83
+ # `RSpec::Mocks::Double`! So we subvert the call to class on
84
+ # RSpec::Mocks::Double to return "WasteCarriersEngine::OrderCopyCardsRegistration"
85
+ # just in this spec. We can then test that the service does indeed
86
+ # locate the original registration for a company name
87
+ allow_any_instance_of(RSpec::Mocks::Double).to receive(:class)
88
+ .and_return("WasteCarriersEngine::OrderCopyCardsRegistration")
89
+ end
90
+
91
+ let(:copy_card_resource) { double(:resource, finance_details: finance_details, reg_identifier: "CBDU123") }
92
+ let(:transient_relation) { double(:relation, first: copy_card_resource) }
93
+ let(:registration_relation) { double(:relation, first: resource) }
94
+
95
+ it "locates the original registration to grab the company name" do
96
+ expect(described_class.run(args).company_name).to eq(company_name.downcase)
97
+
98
+ expect(::WasteCarriersEngine::Registration).to have_received(:where).with(reg_identifier: "CBDU123")
99
+ end
100
+ end
101
+
102
+ context "when the resource does not exist" do
103
+ let(:transient_relation) { double(:relation, first: nil) }
104
+ let(:registration_relation) { double(:relation, first: nil) }
105
+
106
+ it "causes an error" do
107
+ expect { described_class.run(args) }.to raise_error MissingResourceError
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -3,6 +3,7 @@
3
3
  require "rails_helper"
4
4
 
5
5
  module DefraRubyMocks
6
+
6
7
  RSpec.describe WorldpayResponseService do
7
8
  before(:each) do
8
9
  Helpers::Configuration.prep_for_tests
@@ -12,10 +13,11 @@ module DefraRubyMocks
12
13
  config.worldpay_mac_secret = mac_secret
13
14
  end
14
15
 
15
- allow(::WasteCarriersEngine::TransientRegistration).to receive(:where) { relation }
16
- allow(::WasteCarriersEngine::Registration).to receive(:where) { relation }
16
+ allow(WorldpayResourceService).to receive(:run) { resource }
17
17
  end
18
18
 
19
+ let(:resource) { double(:resource, order: order, company_name: company_name.downcase) }
20
+
19
21
  let(:admin_code) { "admincode1" }
20
22
  let(:merchant_code) { "merchantcode1" }
21
23
  let(:mac_secret) { "mac1" }
@@ -23,29 +25,17 @@ module DefraRubyMocks
23
25
  let(:order_code) { "54321" }
24
26
  let(:order_key) { "#{admin_code}^#{merchant_code}^#{order_code}" }
25
27
  let(:order_value) { 105_00 }
28
+ let(:payment_status) { :AUTHORISED }
29
+ let(:company_name) { "Pay for the thing" }
26
30
 
27
- let(:registration) { double(:registration, finance_details: finance_details) }
28
- let(:finance_details) { double(:finance_details, orders: orders) }
29
- let(:orders) { double(:orders, order_by: sorted_orders) }
30
- let(:sorted_orders) { double(:sorted_orders, first: order) }
31
31
  let(:order) { double(:order, order_code: order_code, total_amount: order_value) }
32
32
 
33
- let(:mac) do
34
- data = [
35
- order_key,
36
- order_value,
37
- "GBP",
38
- "AUTHORISED",
39
- mac_secret
40
- ]
41
-
42
- Digest::MD5.hexdigest(data.join).to_s
43
- end
33
+ let(:mac) { Digest::MD5.hexdigest(mac_data.join).to_s }
44
34
 
45
35
  let(:query_string) do
46
36
  [
47
37
  "orderKey=#{order_key}",
48
- "paymentStatus=AUTHORISED",
38
+ "paymentStatus=#{payment_status}",
49
39
  "paymentAmount=#{order_value}",
50
40
  "paymentCurrency=GBP",
51
41
  "mac=#{mac}",
@@ -53,91 +43,228 @@ module DefraRubyMocks
53
43
  ].join("&")
54
44
  end
55
45
 
46
+ let(:args) do
47
+ {
48
+ success_url: success_url,
49
+ failure_url: failure_url,
50
+ pending_url: pending_url,
51
+ cancel_url: cancel_url,
52
+ error_url: error_url
53
+ }
54
+ end
55
+
56
56
  describe ".run" do
57
57
  context "when the request comes from the waste-carriers-front-office" do
58
58
  let(:success_url) { "http://example.com/fo/#{reference}/worldpay/success" }
59
+ let(:failure_url) { "http://example.com/fo/#{reference}/worldpay/failure" }
60
+ let(:pending_url) { "http://example.com/fo/#{reference}/worldpay/pending" }
61
+ let(:cancel_url) { "http://example.com/fo/#{reference}/worldpay/cancel" }
62
+ let(:error_url) { "http://example.com/fo/#{reference}/worldpay/error" }
59
63
 
60
64
  context "and is valid" do
61
65
  let(:relation) { double(:relation, first: registration) }
66
+ let(:mac_data) { [order_key, order_value, "GBP", payment_status, mac_secret] }
62
67
 
63
68
  it "can extract the reference from the `success_url`" do
64
- described_class.run(success_url)
65
-
66
- expect(::WasteCarriersEngine::TransientRegistration).to have_received(:where).with(token: reference)
69
+ expect(described_class.run(args).reference).to eq(reference)
67
70
  end
68
71
 
69
72
  it "can generate a valid order key" do
70
- params = parse_for_params(described_class.run(success_url))
73
+ expect(described_class.run(args).order_key).to eq(order_key)
74
+ end
75
+
76
+ context "and is for a successful payment" do
77
+ it "can generate a valid mac" do
78
+ puts "Test data #{mac_data.join}"
79
+ expect(described_class.run(args).mac).to eq(mac)
80
+ end
81
+
82
+ it "returns a url in the expected format" do
83
+ expected_response_url = "#{success_url}?#{query_string}"
84
+
85
+ expect(described_class.run(args).url).to eq(expected_response_url)
86
+ end
87
+ end
71
88
 
72
- expect(params["orderKey"]).to eq(order_key)
89
+ context "and is for a rejected payment" do
90
+ let(:payment_status) { :REFUSED }
91
+ let(:company_name) { "Reject for the thing" }
92
+
93
+ it "can generate a valid mac" do
94
+ expect(described_class.run(args).mac).to eq(mac)
95
+ end
96
+
97
+ it "returns a url in the expected format" do
98
+ expected_response_url = "#{failure_url}?#{query_string}"
99
+
100
+ expect(described_class.run(args).url).to eq(expected_response_url)
101
+ end
102
+ end
103
+
104
+ context "and is for a stuck payment" do
105
+ let(:payment_status) { :STUCK }
106
+ let(:company_name) { "Give me a stuck thing" }
107
+
108
+ it "can generate a valid mac" do
109
+ expect(described_class.run(args).mac).to eq(mac)
110
+ end
111
+
112
+ it "returns a status of :STUCK" do
113
+ expect(described_class.run(args).status).to eq(:STUCK)
114
+ end
73
115
  end
74
116
 
75
- it "can generate a valid mac" do
76
- params = parse_for_params(described_class.run(success_url))
117
+ context "and is for a pending payment" do
118
+ let(:payment_status) { :SENT_FOR_AUTHORISATION }
119
+ let(:company_name) { "Pending for the thing" }
120
+
121
+ it "can generate a valid mac" do
122
+ expect(described_class.run(args).mac).to eq(mac)
123
+ end
124
+
125
+ it "returns a url in the expected format" do
126
+ expected_response_url = "#{pending_url}?#{query_string}"
77
127
 
78
- expect(params["mac"]).to eq(mac)
128
+ expect(described_class.run(args).url).to eq(expected_response_url)
129
+ end
79
130
  end
80
131
 
81
- it "returns a url in the expected format" do
82
- expected_response = "#{success_url}?#{query_string}"
132
+ context "and is for a cancelled payment" do
133
+ let(:payment_status) { :CANCELLED }
134
+ let(:company_name) { "Cancel the thing" }
135
+ let(:mac_data) { [order_key, order_value, "GBP", mac_secret] }
83
136
 
84
- expect(described_class.run(success_url)).to eq(expected_response)
137
+ it "can generate a valid mac" do
138
+ expect(described_class.run(args).mac).to eq(mac)
139
+ end
140
+
141
+ it "returns a url in the expected format" do
142
+ expected_response_url = "#{cancel_url}?#{query_string}"
143
+
144
+ expect(described_class.run(args).url).to eq(expected_response_url)
145
+ end
85
146
  end
86
- end
87
147
 
88
- context "but the registration does not exist" do
89
- let(:relation) { double(:relation, first: nil) }
148
+ context "and is for an errored payment" do
149
+ let(:payment_status) { :ERROR }
150
+ let(:company_name) { "Error the thing" }
90
151
 
91
- it "causes an error" do
92
- expect { described_class.run(success_url) }.to raise_error MissingRegistrationError
152
+ it "can generate a valid mac" do
153
+ expect(described_class.run(args).mac).to eq(mac)
154
+ end
155
+
156
+ it "returns a url in the expected format" do
157
+ expected_response_url = "#{error_url}?#{query_string}"
158
+
159
+ expect(described_class.run(args).url).to eq(expected_response_url)
160
+ end
93
161
  end
94
162
  end
95
163
  end
96
164
 
97
165
  context "when the request comes from the waste-carriers-frontend" do
98
- before do
99
- # The service will search transient registrations for a match first
100
- # before then searching for the registration. Hence we need to stub
101
- # `locate_transient_registration()` to allow the service to then
102
- # call `locate_registration()`
103
- allow_any_instance_of(described_class).to receive(:locate_transient_registration).and_return(nil)
104
- end
105
-
106
166
  let(:success_url) { "http://example.com/your-registration/#{reference}/worldpay/success/54321/NEWREG?locale=en" }
167
+ let(:failure_url) { "http://example.com/your-registration/#{reference}/worldpay/failure/54321/NEWREG?locale=en" }
168
+ let(:pending_url) { "http://example.com/your-registration/#{reference}/worldpay/pending/54321/NEWREG?locale=en" }
169
+ let(:cancel_url) { "http://example.com/your-registration/#{reference}/worldpay/cancel/54321/NEWREG?locale=en" }
170
+ let(:error_url) { "http://example.com/your-registration/#{reference}/worldpay/error/54321/NEWREG?locale=en" }
107
171
 
108
172
  context "and is valid" do
109
173
  let(:relation) { double(:relation, first: registration) }
174
+ let(:mac_data) { [order_key, order_value, "GBP", payment_status, mac_secret] }
110
175
 
111
176
  it "can extract the reference from the `success_url`" do
112
- described_class.run(success_url)
113
-
114
- expect(::WasteCarriersEngine::Registration).to have_received(:where).with(reg_uuid: reference)
177
+ expect(described_class.run(args).reference).to eq(reference)
115
178
  end
116
179
 
117
180
  it "can generate a valid order key" do
118
- params = parse_for_params(described_class.run(success_url))
181
+ expect(described_class.run(args).order_key).to eq(order_key)
182
+ end
119
183
 
120
- expect(params["orderKey"]).to eq(order_key)
184
+ context "and is for a successful payment" do
185
+ it "can generate a valid mac" do
186
+ expect(described_class.run(args).mac).to eq(mac)
187
+ end
188
+
189
+ it "returns a url in the expected format" do
190
+ expected_response_url = "#{success_url}&#{query_string}"
191
+
192
+ expect(described_class.run(args).url).to eq(expected_response_url)
193
+ end
121
194
  end
122
195
 
123
- it "can generate a valid mac" do
124
- params = parse_for_params(described_class.run(success_url))
196
+ context "and is for a rejected payment" do
197
+ let(:payment_status) { :REFUSED }
198
+ let(:company_name) { "Reject for the thing" }
199
+
200
+ it "can generate a valid mac" do
201
+ expect(described_class.run(args).mac).to eq(mac)
202
+ end
125
203
 
126
- expect(params["mac"]).to eq(mac)
204
+ it "returns a url in the expected format" do
205
+ expected_response_url = "#{failure_url}&#{query_string}"
206
+
207
+ expect(described_class.run(args).url).to eq(expected_response_url)
208
+ end
127
209
  end
128
210
 
129
- it "returns a url in the expected format" do
130
- expected_response = "#{success_url}&#{query_string}"
211
+ context "and is for a stuck payment" do
212
+ let(:payment_status) { :STUCK }
213
+ let(:company_name) { "Give me a stuck thing" }
214
+
215
+ it "can generate a valid mac" do
216
+ expect(described_class.run(args).mac).to eq(mac)
217
+ end
131
218
 
132
- expect(described_class.run(success_url)).to eq(expected_response)
219
+ it "returns a status of :STUCK" do
220
+ expect(described_class.run(args).status).to eq(:STUCK)
221
+ end
133
222
  end
134
- end
135
223
 
136
- context "but the registration does not exist" do
137
- let(:relation) { double(:relation, first: nil) }
224
+ context "and is for a pending payment" do
225
+ let(:payment_status) { :SENT_FOR_AUTHORISATION }
226
+ let(:company_name) { "Pending for the thing" }
227
+
228
+ it "can generate a valid mac" do
229
+ expect(described_class.run(args).mac).to eq(mac)
230
+ end
231
+
232
+ it "returns a url in the expected format" do
233
+ expected_response_url = "#{pending_url}&#{query_string}"
234
+
235
+ expect(described_class.run(args).url).to eq(expected_response_url)
236
+ end
237
+ end
238
+
239
+ context "and is for a cancelled payment" do
240
+ let(:payment_status) { :CANCELLED }
241
+ let(:company_name) { "Cancel the thing" }
242
+ let(:mac_data) { [order_key, order_value, "GBP", mac_secret] }
243
+
244
+ it "can generate a valid mac" do
245
+ expect(described_class.run(args).mac).to eq(mac)
246
+ end
247
+
248
+ it "returns a url in the expected format" do
249
+ expected_response_url = "#{cancel_url}&#{query_string}"
250
+
251
+ expect(described_class.run(args).url).to eq(expected_response_url)
252
+ end
253
+ end
254
+
255
+ context "and is for an errored payment" do
256
+ let(:payment_status) { :ERROR }
257
+ let(:company_name) { "Error the thing" }
258
+
259
+ it "can generate a valid mac" do
260
+ expect(described_class.run(args).mac).to eq(mac)
261
+ end
262
+
263
+ it "returns a url in the expected format" do
264
+ expected_response_url = "#{error_url}&#{query_string}"
138
265
 
139
- it "causes an error" do
140
- expect { described_class.run(success_url) }.to raise_error MissingRegistrationError
266
+ expect(described_class.run(args).url).to eq(expected_response_url)
267
+ end
141
268
  end
142
269
  end
143
270
  end