defra_ruby_mocks 1.2.0 → 2.0.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.
@@ -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