savon 2.2.0 → 2.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.travis.yml +20 -9
  4. data/CHANGELOG.md +157 -10
  5. data/CONTRIBUTING.md +1 -1
  6. data/Gemfile +10 -2
  7. data/README.md +38 -13
  8. data/donate.png +0 -0
  9. data/lib/savon/builder.rb +81 -15
  10. data/lib/savon/client.rb +6 -2
  11. data/lib/savon/core_ext/string.rb +0 -1
  12. data/lib/savon/header.rb +68 -17
  13. data/lib/savon/log_message.rb +7 -3
  14. data/lib/savon/message.rb +6 -7
  15. data/lib/savon/mock/expectation.rb +12 -2
  16. data/lib/savon/model.rb +4 -0
  17. data/lib/savon/operation.rb +45 -38
  18. data/lib/savon/options.rb +149 -22
  19. data/lib/savon/qualified_message.rb +31 -25
  20. data/lib/savon/request.rb +24 -4
  21. data/lib/savon/request_logger.rb +48 -0
  22. data/lib/savon/response.rb +35 -18
  23. data/lib/savon/soap_fault.rb +11 -11
  24. data/lib/savon/version.rb +1 -3
  25. data/savon.gemspec +12 -11
  26. data/spec/fixtures/response/empty_soap_fault.xml +13 -0
  27. data/spec/fixtures/response/f5.xml +39 -0
  28. data/spec/fixtures/response/no_body.xml +1 -0
  29. data/spec/fixtures/response/soap_fault_funky.xml +8 -0
  30. data/spec/fixtures/wsdl/brand.xml +624 -0
  31. data/spec/fixtures/wsdl/elements_in_types.xml +43 -0
  32. data/spec/fixtures/wsdl/no_message_tag.xml +1267 -0
  33. data/spec/fixtures/wsdl/vies.xml +176 -0
  34. data/spec/integration/centra_spec.rb +67 -0
  35. data/spec/integration/email_example_spec.rb +1 -1
  36. data/spec/integration/random_quote_spec.rb +23 -0
  37. data/spec/integration/stockquote_example_spec.rb +7 -1
  38. data/spec/integration/support/application.rb +1 -1
  39. data/spec/integration/zipcode_example_spec.rb +1 -1
  40. data/spec/savon/builder_spec.rb +50 -0
  41. data/spec/savon/client_spec.rb +78 -0
  42. data/spec/savon/core_ext/string_spec.rb +9 -9
  43. data/spec/savon/features/message_tag_spec.rb +5 -0
  44. data/spec/savon/http_error_spec.rb +2 -2
  45. data/spec/savon/log_message_spec.rb +18 -1
  46. data/spec/savon/message_spec.rb +70 -0
  47. data/spec/savon/mock_spec.rb +31 -0
  48. data/spec/savon/model_spec.rb +28 -0
  49. data/spec/savon/operation_spec.rb +69 -3
  50. data/spec/savon/options_spec.rb +515 -87
  51. data/spec/savon/qualified_message_spec.rb +101 -0
  52. data/spec/savon/request_logger_spec.rb +37 -0
  53. data/spec/savon/request_spec.rb +85 -10
  54. data/spec/savon/response_spec.rb +118 -27
  55. data/spec/savon/soap_fault_spec.rb +25 -5
  56. data/spec/savon/softlayer_spec.rb +27 -0
  57. data/spec/spec_helper.rb +5 -2
  58. data/spec/support/adapters.rb +48 -0
  59. data/spec/support/integration.rb +1 -1
  60. metadata +76 -93
@@ -0,0 +1,101 @@
1
+ require "spec_helper"
2
+
3
+ module Savon
4
+ describe QualifiedMessage, "#to_hash" do
5
+
6
+ context "if a key ends with !" do
7
+ let(:used_namespaces) { {} }
8
+ let(:key_converter) { :camelcase }
9
+ let(:types) { {} }
10
+
11
+ it "restores the ! in a key" do
12
+ message = described_class.new(types, used_namespaces, key_converter)
13
+ resulting_hash = message.to_hash({:Metal! => "<Nice/>"}, ["Rock"])
14
+
15
+ expect(resulting_hash).to eq({ :Metal! => "<Nice/>" })
16
+ end
17
+
18
+ it "properly handles special keys when namespaces are present" do
19
+ used_namespaces = {
20
+ %w(tns Foo) => 'ns',
21
+ %w(tns Foo Bar) => 'ns'
22
+ }
23
+
24
+ hash = {
25
+ :foo => {
26
+ :bar => {
27
+ :zing => 'pow'
28
+ },
29
+ :cash => {
30
+ :@attr1 => 'val1',
31
+ :content! => 'Chunky Bacon'
32
+ },
33
+ :attributes! => {
34
+ :bar => { :attr2 => 'val2' },
35
+ },
36
+ :"self_closing/" => '',
37
+ :order! => [:cash, :bar, :"self_closing/"]
38
+ }
39
+ }
40
+
41
+ good_result = {
42
+ "ns:Foo" => {
43
+ 'ns:Bar' => { :zing => "pow" },
44
+ :cash => {
45
+ :@attr1 => "val1",
46
+ :content! => "Chunky Bacon"
47
+ },
48
+ :attributes! => {
49
+ 'ns:Bar' => { :attr2 => 'val2' }
50
+ },
51
+ :"self_closing/" => '',
52
+ :order! => [:cash, 'ns:Bar', :"self_closing/"]
53
+ }
54
+ }
55
+
56
+ good_xml = %(<ns:Foo><Cash attr1="val1">Chunky Bacon</Cash><ns:Bar attr2="val2"><Zing>pow</Zing></ns:Bar><SelfClosing/></ns:Foo>)
57
+
58
+ message = described_class.new(types, used_namespaces, key_converter)
59
+ resulting_hash = message.to_hash(hash, ['tns'])
60
+ xml = Gyoku.xml(resulting_hash, key_converter: key_converter)
61
+
62
+ expect(resulting_hash).to eq good_result
63
+ expect(xml).to eq good_xml
64
+ end
65
+
66
+ it "properly handles boolean false" do
67
+ used_namespaces = {
68
+ %w(tns Foo) => 'ns'
69
+ }
70
+
71
+ hash = {
72
+ :foo => {
73
+ :falsey => {
74
+ :@attr1 => false,
75
+ :content! => false
76
+ }
77
+ }
78
+ }
79
+
80
+ good_result = {
81
+ "ns:Foo" => {
82
+ :falsey => {
83
+ :@attr1 => false,
84
+ :content! => false
85
+ }
86
+ }
87
+ }
88
+
89
+ good_xml = %(<ns:Foo><Falsey attr1="false">false</Falsey></ns:Foo>)
90
+
91
+ message = described_class.new(types, used_namespaces, key_converter)
92
+ resulting_hash = message.to_hash(hash, ['tns'])
93
+ xml = Gyoku.xml(resulting_hash, key_converter: key_converter)
94
+
95
+ expect(resulting_hash).to eq good_result
96
+ expect(xml).to eq good_xml
97
+ end
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::RequestLogger do
4
+
5
+ subject { described_class.new(globals) }
6
+ let(:globals) { Savon::GlobalOptions.new(:log => true, :pretty_print_xml => true) }
7
+ let(:request) {
8
+ stub('Request',
9
+ :url => 'http://example.com',
10
+ :headers => [],
11
+ :body => '<TestRequest />'
12
+ )
13
+ }
14
+
15
+ let(:response) {
16
+ stub('Response',
17
+ :code => 200,
18
+ :body => '<TestResponse />'
19
+ )
20
+ }
21
+
22
+ before(:each) {
23
+ globals[:logger].level = Logger::DEBUG
24
+ }
25
+
26
+ describe '#log_request / #log_response' do
27
+ it 'does not prepare log messages when no logging is needed' do
28
+ begin
29
+ globals[:logger].level = Logger::FATAL
30
+
31
+ Savon::LogMessage.expects(:new).never
32
+ subject.log(request) { response }
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -5,6 +5,7 @@ describe Savon::WSDLRequest do
5
5
 
6
6
  let(:globals) { Savon::GlobalOptions.new }
7
7
  let(:http_request) { HTTPI::Request.new }
8
+ let(:ciphers) { OpenSSL::Cipher.ciphers }
8
9
 
9
10
  def new_wsdl_request
10
11
  Savon::WSDLRequest.new(globals, http_request)
@@ -16,6 +17,20 @@ describe Savon::WSDLRequest do
16
17
  expect(wsdl_request.build).to be_an(HTTPI::Request)
17
18
  end
18
19
 
20
+ describe "headers" do
21
+ it "are set when specified" do
22
+ globals.headers("Proxy-Authorization" => "Basic auth")
23
+ configured_http_request = new_wsdl_request.build
24
+
25
+ expect(configured_http_request.headers["Proxy-Authorization"]).to eq("Basic auth")
26
+ end
27
+
28
+ it "are not set otherwise" do
29
+ configured_http_request = new_wsdl_request.build
30
+ expect(configured_http_request.headers).to_not include("Proxy-Authorization")
31
+ end
32
+ end
33
+
19
34
  describe "proxy" do
20
35
  it "is set when specified" do
21
36
  globals.proxy("http://proxy.example.com")
@@ -60,8 +75,8 @@ describe Savon::WSDLRequest do
60
75
 
61
76
  describe "ssl version" do
62
77
  it "is set when specified" do
63
- globals.ssl_version(:SSLv3)
64
- http_request.auth.ssl.expects(:ssl_version=).with(:SSLv3)
78
+ globals.ssl_version(:TLSv1)
79
+ http_request.auth.ssl.expects(:ssl_version=).with(:TLSv1)
65
80
 
66
81
  new_wsdl_request.build
67
82
  end
@@ -74,8 +89,8 @@ describe Savon::WSDLRequest do
74
89
 
75
90
  describe "ssl verify mode" do
76
91
  it "is set when specified" do
77
- globals.ssl_verify_mode(:none)
78
- http_request.auth.ssl.expects(:verify_mode=).with(:none)
92
+ globals.ssl_verify_mode(:peer)
93
+ http_request.auth.ssl.expects(:verify_mode=).with(:peer)
79
94
 
80
95
  new_wsdl_request.build
81
96
  end
@@ -86,6 +101,20 @@ describe Savon::WSDLRequest do
86
101
  end
87
102
  end
88
103
 
104
+ describe "ssl ciphers" do
105
+ it "is set when specified" do
106
+ globals.ssl_ciphers(ciphers)
107
+ http_request.auth.ssl.expects(:ciphers=).with(ciphers)
108
+
109
+ new_wsdl_request.build
110
+ end
111
+
112
+ it "is not set otherwise" do
113
+ http_request.auth.ssl.expects(:ciphers=).never
114
+ new_wsdl_request.build
115
+ end
116
+ end
117
+
89
118
  describe "ssl cert key file" do
90
119
  it "is set when specified" do
91
120
  cert_key = File.expand_path("../../fixtures/ssl/client_key.pem", __FILE__)
@@ -129,12 +158,15 @@ describe Savon::WSDLRequest do
129
158
 
130
159
  new_wsdl_request.build
131
160
 
132
- expect { http_request.auth.ssl.cert_key }.to raise_error(OpenSSL::PKey::RSAError)
161
+ expect { http_request.auth.ssl.cert_key }.to raise_error
133
162
  end
134
163
  end
135
164
 
136
165
  describe "set with a valid decrypting password" do
137
166
  it "handles SSL private keys properly" do
167
+ if RUBY_ENGINE == 'jruby'
168
+ pending("find out why this fails with a null pointer exception on jruby")
169
+ end
138
170
  pass = "secure-password!42"
139
171
  key = File.expand_path("../../fixtures/ssl/client_encrypted_key.pem", __FILE__)
140
172
  cert = File.expand_path("../../fixtures/ssl/client_encrypted_key_cert.pem", __FILE__)
@@ -145,7 +177,7 @@ describe Savon::WSDLRequest do
145
177
 
146
178
  new_wsdl_request.build
147
179
 
148
- http_request.auth.ssl.cert_key.to_s.should =~ /BEGIN RSA PRIVATE KEY/
180
+ expect(http_request.auth.ssl.cert_key.to_s).to match(/BEGIN RSA PRIVATE KEY/)
149
181
  end
150
182
  end
151
183
  end
@@ -207,6 +239,20 @@ describe Savon::WSDLRequest do
207
239
  new_wsdl_request.build
208
240
  end
209
241
  end
242
+
243
+ describe "ntlm auth" do
244
+ it "is set when specified" do
245
+ globals.ntlm("han", "super-secret")
246
+ http_request.auth.expects(:ntlm).with("han", "super-secret")
247
+
248
+ new_wsdl_request.build
249
+ end
250
+
251
+ it "is not set otherwise" do
252
+ http_request.auth.expects(:ntlm).never
253
+ new_wsdl_request.build
254
+ end
255
+ end
210
256
  end
211
257
 
212
258
  end
@@ -215,6 +261,7 @@ describe Savon::SOAPRequest do
215
261
 
216
262
  let(:globals) { Savon::GlobalOptions.new }
217
263
  let(:http_request) { HTTPI::Request.new }
264
+ let(:ciphers) { OpenSSL::Cipher.ciphers }
218
265
 
219
266
  def new_soap_request
220
267
  Savon::SOAPRequest.new(globals, http_request)
@@ -347,8 +394,8 @@ describe Savon::SOAPRequest do
347
394
 
348
395
  describe "ssl version" do
349
396
  it "is set when specified" do
350
- globals.ssl_version(:SSLv3)
351
- http_request.auth.ssl.expects(:ssl_version=).with(:SSLv3)
397
+ globals.ssl_version(:TLSv1)
398
+ http_request.auth.ssl.expects(:ssl_version=).with(:TLSv1)
352
399
 
353
400
  new_soap_request.build
354
401
  end
@@ -361,8 +408,8 @@ describe Savon::SOAPRequest do
361
408
 
362
409
  describe "ssl verify mode" do
363
410
  it "is set when specified" do
364
- globals.ssl_verify_mode(:none)
365
- http_request.auth.ssl.expects(:verify_mode=).with(:none)
411
+ globals.ssl_verify_mode(:peer)
412
+ http_request.auth.ssl.expects(:verify_mode=).with(:peer)
366
413
 
367
414
  new_soap_request.build
368
415
  end
@@ -373,6 +420,20 @@ describe Savon::SOAPRequest do
373
420
  end
374
421
  end
375
422
 
423
+ describe "ssl ciphers" do
424
+ it "is set when specified" do
425
+ globals.ssl_ciphers(ciphers)
426
+ http_request.auth.ssl.expects(:ciphers=).with(ciphers)
427
+
428
+ new_soap_request.build
429
+ end
430
+
431
+ it "is not set otherwise" do
432
+ http_request.auth.ssl.expects(:ciphers=).never
433
+ new_soap_request.build
434
+ end
435
+ end
436
+
376
437
  describe "ssl cert key file" do
377
438
  it "is set when specified" do
378
439
  cert_key = File.expand_path("../../fixtures/ssl/client_key.pem", __FILE__)
@@ -460,6 +521,20 @@ describe Savon::SOAPRequest do
460
521
  new_soap_request.build
461
522
  end
462
523
  end
524
+
525
+ describe "ntlm auth" do
526
+ it "is set when specified" do
527
+ globals.ntlm("han", "super-secret")
528
+ http_request.auth.expects(:ntlm).with("han", "super-secret")
529
+
530
+ new_soap_request.build
531
+ end
532
+
533
+ it "is not set otherwise" do
534
+ http_request.auth.expects(:ntlm).never
535
+ new_soap_request.build
536
+ end
537
+ end
463
538
  end
464
539
 
465
540
  end
@@ -7,16 +7,16 @@ describe Savon::Response do
7
7
 
8
8
  describe ".new" do
9
9
  it "should raise a Savon::Fault in case of a SOAP fault" do
10
- lambda { soap_fault_response }.should raise_error(Savon::SOAPFault)
10
+ expect { soap_fault_response }.to raise_error(Savon::SOAPFault)
11
11
  end
12
12
 
13
13
  it "should not raise a Savon::Fault in case the default is turned off" do
14
14
  globals[:raise_errors] = false
15
- lambda { soap_fault_response }.should_not raise_error(Savon::SOAPFault)
15
+ expect { soap_fault_response }.not_to raise_error
16
16
  end
17
17
 
18
18
  it "should raise a Savon::HTTP::Error in case of an HTTP error" do
19
- lambda { soap_response :code => 500 }.should raise_error(Savon::HTTPError)
19
+ expect { soap_response :code => 500 }.to raise_error(Savon::HTTPError)
20
20
  end
21
21
 
22
22
  it "should not raise a Savon::HTTP::Error in case the default is turned off" do
@@ -29,15 +29,15 @@ describe Savon::Response do
29
29
  before { globals[:raise_errors] = false }
30
30
 
31
31
  it "should return true if the request was successful" do
32
- soap_response.should be_a_success
32
+ expect(soap_response).to be_a_success
33
33
  end
34
34
 
35
35
  it "should return false if there was a SOAP fault" do
36
- soap_fault_response.should_not be_a_success
36
+ expect(soap_fault_response).not_to be_a_success
37
37
  end
38
38
 
39
39
  it "should return false if there was an HTTP error" do
40
- http_error_response.should_not be_a_success
40
+ expect(http_error_response).not_to be_a_success
41
41
  end
42
42
  end
43
43
 
@@ -45,11 +45,23 @@ describe Savon::Response do
45
45
  before { globals[:raise_errors] = false }
46
46
 
47
47
  it "should not return true in case the response seems to be ok" do
48
- soap_response.soap_fault?.should be_false
48
+ expect(soap_response.soap_fault?).to be_falsey
49
49
  end
50
50
 
51
51
  it "should return true in case of a SOAP fault" do
52
- soap_fault_response.soap_fault?.should be_true
52
+ expect(soap_fault_response.soap_fault?).to be_truthy
53
+ end
54
+ end
55
+
56
+ describe "#soap_fault" do
57
+ before { globals[:raise_errors] = false }
58
+
59
+ it "should return nil in case the response seems to be ok" do
60
+ expect(soap_response.soap_fault).to be_nil
61
+ end
62
+
63
+ it "should return a SOAPFault in case of a SOAP fault" do
64
+ expect(soap_fault_response.soap_fault).to be_a(Savon::SOAPFault)
53
65
  end
54
66
  end
55
67
 
@@ -57,44 +69,108 @@ describe Savon::Response do
57
69
  before { globals[:raise_errors] = false }
58
70
 
59
71
  it "should not return true in case the response seems to be ok" do
60
- soap_response.http_error?.should_not be_true
72
+ expect(soap_response.http_error?).not_to be_truthy
61
73
  end
62
74
 
63
75
  it "should return true in case of an HTTP error" do
64
- soap_response(:code => 500).http_error?.should be_true
76
+ expect(soap_response(:code => 500).http_error?).to be_truthy
77
+ end
78
+ end
79
+
80
+ describe "#http_error" do
81
+ before { globals[:raise_errors] = false }
82
+
83
+ it "should return nil in case the response seems to be ok" do
84
+ expect(soap_response.http_error).to be_nil
85
+ end
86
+
87
+ it "should return a HTTPError in case of an HTTP error" do
88
+ expect(soap_response(:code => 500).http_error).to be_a(Savon::HTTPError)
65
89
  end
66
90
  end
67
91
 
68
92
  describe "#header" do
69
93
  it "should return the SOAP response header as a Hash" do
70
94
  response = soap_response :body => Fixture.response(:header)
71
- response.header.should include(:session_number => "ABCD1234")
95
+ expect(response.header).to include(:session_number => "ABCD1234")
96
+ end
97
+
98
+ it 'respects the global :strip_namespaces option' do
99
+ globals[:strip_namespaces] = false
100
+
101
+ response_with_header = soap_response(:body => Fixture.response(:header))
102
+ header = response_with_header.header
103
+
104
+ expect(header).to be_a(Hash)
105
+
106
+ # notice: :session_number is a snake_case Symbol without namespaces,
107
+ # but the Envelope and Header elements are qualified.
108
+ expect(header.keys).to include(:session_number)
109
+ end
110
+
111
+ it 'respects the global :convert_response_tags_to option' do
112
+ globals[:convert_response_tags_to] = lambda { |key| key.upcase }
113
+
114
+ response_with_header = soap_response(:body => Fixture.response(:header))
115
+ header = response_with_header.header
116
+
117
+ expect(header).to be_a(Hash)
118
+ expect(header.keys).to include('SESSIONNUMBER')
119
+ end
120
+
121
+ it 'respects the global :convert_attributes_to option' do
122
+ globals[:convert_attributes_to] = lambda { |k,v| [] }
123
+
124
+ response_with_header = soap_response(:body => Fixture.response(:header))
125
+ header = response_with_header.header
126
+
127
+ expect(header).to be_a(Hash)
128
+ expect(header.keys).to include(:session_number)
72
129
  end
73
130
 
74
131
  it "should throw an exception when the response header isn't parsable" do
75
- lambda { invalid_soap_response.header }.should raise_error Savon::InvalidResponseError
132
+ expect { invalid_soap_response.header }.to raise_error Savon::InvalidResponseError
76
133
  end
77
134
  end
78
135
 
79
136
  %w(body to_hash).each do |method|
80
137
  describe "##{method}" do
81
138
  it "should return the SOAP response body as a Hash" do
82
- soap_response.send(method)[:authenticate_response][:return].should ==
139
+ expect(soap_response.send(method)[:authenticate_response][:return]).to eq(
83
140
  Fixture.response_hash(:authentication)[:authenticate_response][:return]
141
+ )
84
142
  end
85
143
 
86
144
  it "should return a Hash for a SOAP multiRef response" do
87
145
  hash = soap_response(:body => Fixture.response(:multi_ref)).send(method)
88
146
 
89
- hash[:list_response].should be_a(Hash)
90
- hash[:multi_ref].should be_an(Array)
147
+ expect(hash[:list_response]).to be_a(Hash)
148
+ expect(hash[:multi_ref]).to be_an(Array)
91
149
  end
92
150
 
93
151
  it "should add existing namespaced elements as an array" do
94
152
  hash = soap_response(:body => Fixture.response(:list)).send(method)
95
153
 
96
- hash[:multi_namespaced_entry_response][:history].should be_a(Hash)
97
- hash[:multi_namespaced_entry_response][:history][:case].should be_an(Array)
154
+ expect(hash[:multi_namespaced_entry_response][:history]).to be_a(Hash)
155
+ expect(hash[:multi_namespaced_entry_response][:history][:case]).to be_an(Array)
156
+ end
157
+
158
+ it 'respects the global :strip_namespaces option' do
159
+ globals[:strip_namespaces] = false
160
+
161
+ body = soap_response.body
162
+
163
+ expect(body).to be_a(Hash)
164
+ expect(body.keys).to include(:"ns2:authenticate_response")
165
+ end
166
+
167
+ it 'respects the global :convert_response_tags_to option' do
168
+ globals[:convert_response_tags_to] = lambda { |key| key.upcase }
169
+
170
+ body = soap_response.body
171
+
172
+ expect(body).to be_a(Hash)
173
+ expect(body.keys).to include('AUTHENTICATERESPONSE')
98
174
  end
99
175
  end
100
176
  end
@@ -102,25 +178,26 @@ describe Savon::Response do
102
178
  describe "#to_array" do
103
179
  context "when the given path exists" do
104
180
  it "should return an Array containing the path value" do
105
- soap_response.to_array(:authenticate_response, :return).should ==
181
+ expect(soap_response.to_array(:authenticate_response, :return)).to eq(
106
182
  [Fixture.response_hash(:authentication)[:authenticate_response][:return]]
183
+ )
107
184
  end
108
185
 
109
186
  it "should properly return FalseClass values [#327]" do
110
187
  body = Gyoku.xml(:envelope => { :body => { :return => { :success => false } } })
111
- soap_response(:body => body).to_array(:return, :success).should == [false]
188
+ expect(soap_response(:body => body).to_array(:return, :success)).to eq([false])
112
189
  end
113
190
  end
114
191
 
115
192
  context "when the given path returns nil" do
116
193
  it "should return an empty Array" do
117
- soap_response.to_array(:authenticate_response, :undefined).should == []
194
+ expect(soap_response.to_array(:authenticate_response, :undefined)).to eq([])
118
195
  end
119
196
  end
120
197
 
121
198
  context "when the given path does not exist at all" do
122
199
  it "should return an empty Array" do
123
- soap_response.to_array(:authenticate_response, :some, :undefined, :path).should == []
200
+ expect(soap_response.to_array(:authenticate_response, :some, :undefined, :path)).to eq([])
124
201
  end
125
202
  end
126
203
  end
@@ -128,32 +205,46 @@ describe Savon::Response do
128
205
  describe "#hash" do
129
206
  it "should return the complete SOAP response XML as a Hash" do
130
207
  response = soap_response :body => Fixture.response(:header)
131
- response.hash[:envelope][:header][:session_number].should == "ABCD1234"
208
+ expect(response.hash[:envelope][:header][:session_number]).to eq("ABCD1234")
132
209
  end
133
210
  end
134
211
 
135
212
  describe "#to_xml" do
136
213
  it "should return the raw SOAP response body" do
137
- soap_response.to_xml.should == Fixture.response(:authentication)
214
+ expect(soap_response.to_xml).to eq(Fixture.response(:authentication))
138
215
  end
139
216
  end
140
217
 
141
218
  describe "#doc" do
142
219
  it "returns a Nokogiri::XML::Document for the SOAP response XML" do
143
- soap_response.doc.should be_a(Nokogiri::XML::Document)
220
+ expect(soap_response.doc).to be_a(Nokogiri::XML::Document)
144
221
  end
145
222
  end
146
223
 
147
224
  describe "#xpath" do
148
225
  it "permits XPath access to elements in the request" do
149
- soap_response.xpath("//client").first.inner_text.should == "radclient"
150
- soap_response.xpath("//ns2:authenticateResponse/return/success").first.inner_text.should == "true"
226
+ expect(soap_response.xpath("//client").first.inner_text).to eq("radclient")
227
+ expect(soap_response.xpath("//ns2:authenticateResponse/return/success").first.inner_text).to eq("true")
228
+ end
229
+ end
230
+
231
+ describe '#find' do
232
+ it 'delegates to Nori#find to find child elements inside the Envelope' do
233
+ result = soap_response.find('Body', 'authenticateResponse', 'return')
234
+
235
+ expect(result).to be_a(Hash)
236
+ expect(result.keys).to include(:authentication_value)
237
+ end
238
+
239
+ it 'fails correctly when envelope contains only string' do
240
+ response = soap_response({ :body => Fixture.response(:no_body) })
241
+ expect { response.find('Body') }.to raise_error Savon::InvalidResponseError
151
242
  end
152
243
  end
153
244
 
154
245
  describe "#http" do
155
246
  it "should return the HTTPI::Response" do
156
- soap_response.http.should be_an(HTTPI::Response)
247
+ expect(soap_response.http).to be_an(HTTPI::Response)
157
248
  end
158
249
  end
159
250