soaspec 0.0.30 → 0.0.31
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.
- checksums.yaml +4 -4
- data/ChangeLog +5 -0
- data/Gemfile.lock +1 -1
- data/lib/soaspec.rb +5 -3
- data/lib/soaspec/exchange.rb +1 -1
- data/lib/soaspec/{exchange_handler.rb → exchange_handlers/exchange_handler.rb} +2 -2
- data/lib/soaspec/{rest_handler.rb → exchange_handlers/rest_handler.rb} +48 -33
- data/lib/soaspec/{basic_soap_handler.rb → exchange_handlers/soap_handler.rb} +38 -15
- data/lib/soaspec/interpreter.rb +26 -0
- data/lib/soaspec/matchers.rb +7 -9
- data/lib/soaspec/not_found_errors.rb +14 -0
- data/lib/soaspec/soaspec_shared_examples.rb +1 -1
- data/lib/soaspec/version.rb +1 -1
- metadata +7 -6
- data/lib/soaspec/xpath_not_found.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e08d39845eefbfb87ab3a5b7b8e6ae80fa321d54
|
4
|
+
data.tar.gz: 7903a5ab815ef9d56c9b6223b1d945181c57317e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccf078e392801d2ff1686836701c4ded6afbb2166591ad543c6ba6fa7b54fa0946f637e5bfdb3401b0e90deb105751e01edc2040379295dc280bf64acded3528
|
7
|
+
data.tar.gz: 2d8c97db2287c39369b0e6258202a3b446aa4c4e4375fd35af46402daf2bab6d5f260d93934d31852d089073549f5b94b7168ae6b85b99477387055388352b12
|
data/ChangeLog
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
Version 0.0.31 / 2018-3-8
|
2
|
+
* Enhancements
|
3
|
+
* Compacted unit tests for exchange handler
|
4
|
+
* Implemented include_key? and find via xpath for REST handler. See specs
|
5
|
+
|
1
6
|
Version 0.0.30 / 2018-3-6
|
2
7
|
* Bug fix
|
3
8
|
* Made generated class file name in soaspec-generate snakecase (was CamelCase)
|
data/Gemfile.lock
CHANGED
data/lib/soaspec.rb
CHANGED
@@ -8,16 +8,18 @@ require 'nokogiri' # XPath
|
|
8
8
|
require 'date'
|
9
9
|
|
10
10
|
require 'soaspec/version'
|
11
|
-
require 'soaspec/
|
12
|
-
require 'soaspec/exchange_handler'
|
11
|
+
require 'soaspec/exchange_handlers/soap_handler'
|
12
|
+
require 'soaspec/exchange_handlers/exchange_handler'
|
13
13
|
require 'soaspec/exchange'
|
14
14
|
require 'soaspec/matchers'
|
15
15
|
require 'soaspec/soaspec_shared_examples'
|
16
16
|
require 'soaspec/hash_methods'
|
17
17
|
require 'soaspec/spec_logger'
|
18
18
|
require 'soaspec/exe_helpers'
|
19
|
-
require 'soaspec/rest_handler'
|
19
|
+
require 'soaspec/exchange_handlers/rest_handler'
|
20
20
|
require 'soaspec/accessors'
|
21
|
+
require 'soaspec/interpreter'
|
22
|
+
require 'soaspec/not_found_errors'
|
21
23
|
|
22
24
|
# Gem for handling SOAP and REST api tests
|
23
25
|
module Soaspec
|
data/lib/soaspec/exchange.rb
CHANGED
@@ -39,7 +39,7 @@ class Exchange
|
|
39
39
|
end
|
40
40
|
|
41
41
|
# Extract value from path api class
|
42
|
-
# @param [
|
42
|
+
# @param [Object] path Path to return element for api class E.g - for SOAP this is XPath string. For JSON, this is Hash dig Array
|
43
43
|
# @return [String] Value at path
|
44
44
|
def [](path)
|
45
45
|
@api_class.value_from_path(self, path)
|
@@ -9,7 +9,7 @@ module Soaspec
|
|
9
9
|
|
10
10
|
# Set instance variable name
|
11
11
|
# @param [String, Symbol] name Name used when describing API test
|
12
|
-
# @param [Hash] options Parameters defining
|
12
|
+
# @param [Hash] options Parameters defining handler. Used in descendants
|
13
13
|
def initialize(name, options)
|
14
14
|
@name = name
|
15
15
|
end
|
@@ -18,7 +18,7 @@ module Soaspec
|
|
18
18
|
# @return [String] Name set upon initialisation
|
19
19
|
def to_s
|
20
20
|
Soaspec::Environment.api_handler = self
|
21
|
-
@name
|
21
|
+
@name.to_s
|
22
22
|
end
|
23
23
|
|
24
24
|
# Set the request option type and the template name
|
@@ -1,8 +1,9 @@
|
|
1
1
|
|
2
2
|
require_relative 'exchange_handler'
|
3
|
-
require_relative 'hash_methods'
|
4
|
-
require_relative '
|
5
|
-
require_relative 'accessors'
|
3
|
+
require_relative '../hash_methods'
|
4
|
+
require_relative '../not_found_errors'
|
5
|
+
require_relative '../accessors'
|
6
|
+
require_relative '../interpreter'
|
6
7
|
require 'json'
|
7
8
|
require 'nori'
|
8
9
|
|
@@ -54,16 +55,10 @@ module Soaspec
|
|
54
55
|
end
|
55
56
|
|
56
57
|
def name(name)
|
57
|
-
@test_values = {}
|
58
58
|
@test_name = name
|
59
59
|
self
|
60
60
|
end
|
61
61
|
|
62
|
-
def override(request_parameters)
|
63
|
-
@test_values = request_parameters
|
64
|
-
self
|
65
|
-
end
|
66
|
-
|
67
62
|
# Used in together with Exchange request that passes such override parameters
|
68
63
|
# @param [Hash] override_parameters Params to characterize REST request
|
69
64
|
def make_request(override_parameters)
|
@@ -103,25 +98,17 @@ module Soaspec
|
|
103
98
|
response.body.include? expected
|
104
99
|
end
|
105
100
|
|
101
|
+
# Whether the request found the desired value or not
|
106
102
|
def found?(response)
|
107
|
-
response
|
103
|
+
status_code_for(response) != 404
|
108
104
|
end
|
109
105
|
|
110
106
|
# Convert XML or JSON response into a Hash
|
111
107
|
# @param [String] response Response as a String (either in XML or JSON)
|
112
108
|
# @return [Hash]
|
113
109
|
def extract_hash(response)
|
114
|
-
raise "Empty Body. Can't assert on it" if response.body.empty?
|
115
|
-
|
116
|
-
when '<'
|
117
|
-
:xml
|
118
|
-
when '{'
|
119
|
-
:json
|
120
|
-
else
|
121
|
-
:unknown
|
122
|
-
end
|
123
|
-
|
124
|
-
case type
|
110
|
+
raise ArgumentError("Empty Body. Can't assert on it") if response.body.empty?
|
111
|
+
case Interpreter.response_type_for response
|
125
112
|
when :json
|
126
113
|
JSON.parse(response.body).transform_keys_to_symbols
|
127
114
|
when :xml
|
@@ -132,10 +119,17 @@ module Soaspec
|
|
132
119
|
end
|
133
120
|
end
|
134
121
|
|
122
|
+
# @return [Boolean] Whether response contains expected value
|
135
123
|
def include_value?(response, expected)
|
136
124
|
extract_hash(response).include_value? expected
|
137
125
|
end
|
138
126
|
|
127
|
+
# @return [Boolean] Whether response body contains expected key
|
128
|
+
def include_key?(response, expected)
|
129
|
+
extract_hash(response).include_key? expected
|
130
|
+
end
|
131
|
+
|
132
|
+
# @return [Integer] HTTP Status code for response
|
139
133
|
def status_code_for(response)
|
140
134
|
response.code
|
141
135
|
end
|
@@ -160,23 +154,44 @@ module Soaspec
|
|
160
154
|
end
|
161
155
|
|
162
156
|
# Returns the value at the provided xpath
|
163
|
-
|
157
|
+
# @param [Exchange] exchange
|
158
|
+
# @param [String] xpath
|
159
|
+
# @return [String] Value inside element found through Xpath
|
160
|
+
def xpath_value_for(exchange: nil, xpath: nil)
|
161
|
+
raise ArgumentError unless exchange && xpath
|
162
|
+
response = exchange.response
|
163
|
+
raise "Can't perform XPATH if response is not XML" unless Interpreter.response_type_for(response) == :xml
|
164
164
|
result =
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
raise NoElementAtXpath, "No value at Xpath '#{param[:xpath]}'" unless result
|
165
|
+
if Soaspec::Environment.strip_namespaces? && !xpath.include?(':')
|
166
|
+
temp_doc = Nokogiri.parse response.body
|
167
|
+
temp_doc.remove_namespaces!
|
168
|
+
temp_doc.xpath(xpath).first
|
169
|
+
else
|
170
|
+
Nokogiri.parse(response.body).xpath(xpath).first
|
171
|
+
end
|
172
|
+
raise NoElementAtXpath, "No value at Xpath '#{xpath}'" unless result
|
174
173
|
result.inner_text
|
175
174
|
end
|
176
175
|
|
176
|
+
# Based on a exchange, return the value at the provided xpath
|
177
|
+
# If the path does not begin with a '/', a '//' is added to it
|
178
|
+
# @param [Exchange] exchange
|
179
|
+
# @param [Object] path Xpath or other path identifying how to find element
|
180
|
+
# @return [String] Value at Xpath
|
177
181
|
def value_from_path(exchange, path)
|
178
|
-
|
179
|
-
|
182
|
+
case Interpreter.response_type_for(exchange.response)
|
183
|
+
when :xml
|
184
|
+
path = '//' + path if path[0] != '/'
|
185
|
+
xpath_value_for(exchange: exchange, xpath: path)
|
186
|
+
when :json
|
187
|
+
hash = extract_hash exchange.response
|
188
|
+
value = hash.dig(*path)
|
189
|
+
raise NoElementInHash, "Element in #{hash} not found with path '#{path}'" unless value
|
190
|
+
value
|
191
|
+
else
|
192
|
+
raise 'Unrecognised response message. Neither xml nor json detected'
|
193
|
+
end
|
194
|
+
|
180
195
|
end
|
181
196
|
|
182
197
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
|
2
2
|
require_relative 'exchange_handler'
|
3
|
-
require_relative 'hash_methods'
|
4
|
-
require_relative '
|
5
|
-
require_relative 'accessors'
|
3
|
+
require_relative '../hash_methods'
|
4
|
+
require_relative '../not_found_errors'
|
5
|
+
require_relative '../accessors'
|
6
|
+
require_relative '../interpreter'
|
6
7
|
|
7
8
|
module Soaspec
|
8
9
|
|
@@ -73,20 +74,16 @@ module Soaspec
|
|
73
74
|
options.merge! savon_options
|
74
75
|
options.merge!(specific_options)
|
75
76
|
@client = Savon.client(options)
|
77
|
+
@default_hash = {}
|
78
|
+
@request_option = :hash
|
76
79
|
super
|
77
80
|
end
|
78
81
|
|
79
82
|
def name(name)
|
80
|
-
@test_values = {}
|
81
83
|
@test_name = name
|
82
84
|
self
|
83
85
|
end
|
84
86
|
|
85
|
-
def override(request_parameters)
|
86
|
-
@test_values = request_parameters
|
87
|
-
self
|
88
|
-
end
|
89
|
-
|
90
87
|
# Used in together with Exchange request that passes such override parameters
|
91
88
|
def make_request(override_parameters)
|
92
89
|
test_values = override_parameters # Used in Erb
|
@@ -101,6 +98,8 @@ module Soaspec
|
|
101
98
|
end
|
102
99
|
end
|
103
100
|
|
101
|
+
# Set the default hash representing data to be used in making a request
|
102
|
+
# This will set the @request_option instance variable too
|
104
103
|
def default_hash=(hash)
|
105
104
|
@request_option = :hash
|
106
105
|
@default_hash = Soaspec::Environment.always_use_keys? ? hash.transform_keys_to_symbols : hash
|
@@ -119,28 +118,51 @@ module Soaspec
|
|
119
118
|
end
|
120
119
|
end
|
121
120
|
|
121
|
+
# @return [Boolean] Whether the request found the desired value or not
|
122
|
+
def found?(response)
|
123
|
+
status_code_for(response) != 404
|
124
|
+
end
|
125
|
+
|
126
|
+
# Response status code for response. '200' indicates a success
|
127
|
+
# @param [Savon::Response] response
|
128
|
+
# @return [Integer] Status code
|
122
129
|
def status_code_for(response)
|
123
130
|
response.http.code
|
124
131
|
end
|
125
132
|
|
133
|
+
# @return [Boolean] Whether response includes provided string within it
|
126
134
|
def include_in_body?(response, expected)
|
127
135
|
response.to_xml.to_s.include? expected
|
128
136
|
end
|
129
137
|
|
138
|
+
# @return [Boolean] Whether response body contains expected key
|
139
|
+
def include_key?(response, expected)
|
140
|
+
response.body.include_key? expected
|
141
|
+
end
|
142
|
+
|
130
143
|
# Returns the value at the provided xpath
|
131
|
-
|
144
|
+
# @param [Exchange] exchange
|
145
|
+
# @param [String] xpath
|
146
|
+
# @return [String] Value inside element found through Xpath
|
147
|
+
def xpath_value_for(exchange: nil, xpath: nil)
|
148
|
+
raise ArgumentError unless exchange && xpath
|
132
149
|
result =
|
133
|
-
if Soaspec::Environment.strip_namespaces? && !
|
134
|
-
temp_doc =
|
150
|
+
if Soaspec::Environment.strip_namespaces? && !xpath.include?(':')
|
151
|
+
temp_doc = exchange.response.doc
|
135
152
|
temp_doc.remove_namespaces!
|
136
|
-
temp_doc.xpath(
|
153
|
+
temp_doc.xpath(xpath).first
|
137
154
|
else
|
138
|
-
|
155
|
+
exchange.response.xpath(xpath).first
|
139
156
|
end
|
140
|
-
raise NoElementAtXpath, "No value at Xpath '#{
|
157
|
+
raise NoElementAtXpath, "No value at Xpath '#{xpath}'" unless result
|
141
158
|
result.inner_text
|
142
159
|
end
|
143
160
|
|
161
|
+
# Based on a exchange, return the value at the provided xpath
|
162
|
+
# If the path does not begin with a '/', a '//' is added to it
|
163
|
+
# @param [Exchange] exchange
|
164
|
+
# @param [String] path Xpath
|
165
|
+
# @return [String] Value at Xpath
|
144
166
|
def value_from_path(exchange, path)
|
145
167
|
path = '//' + path if path[0] != '/'
|
146
168
|
xpath_value_for(exchange: exchange, xpath: path)
|
@@ -153,6 +175,7 @@ module Soaspec
|
|
153
175
|
|
154
176
|
end
|
155
177
|
|
178
|
+
# Deprecated class name. Will be removed in the future
|
156
179
|
class BasicSoapHandler < SoapHandler
|
157
180
|
|
158
181
|
def initialize(name, specific_options = {})
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
# Help interpret the general type of a particular object
|
3
|
+
class Interpreter
|
4
|
+
|
5
|
+
# @param [Object] response API response
|
6
|
+
# @return [Symbol] Type of provided response
|
7
|
+
def self.response_type_for(response)
|
8
|
+
if response.is_a? String
|
9
|
+
case response.body[0]
|
10
|
+
when '<'
|
11
|
+
:xml
|
12
|
+
when '{'
|
13
|
+
:json
|
14
|
+
else
|
15
|
+
:unknown
|
16
|
+
end
|
17
|
+
elsif response.is_a? Hash
|
18
|
+
:hash
|
19
|
+
elsif response.is_a? Nokogiri::XML::NodeSet
|
20
|
+
:xml
|
21
|
+
else
|
22
|
+
:unknown
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/soaspec/matchers.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
|
2
2
|
require_relative 'hash_methods'
|
3
|
-
require_relative '
|
3
|
+
require_relative 'not_found_errors'
|
4
4
|
|
5
5
|
# TODO: Mathcers are specific to SOAP. Make generic for REST and others by using actual.api_class
|
6
6
|
|
@@ -10,9 +10,8 @@ RSpec::Matchers.define :contain_value do |expected|
|
|
10
10
|
expect(actual.api_class.include_value?(actual.response, expected)).to be true
|
11
11
|
end
|
12
12
|
|
13
|
-
# TODO: Fix this for REST
|
14
13
|
failure_message do |actual|
|
15
|
-
"expected that #{actual.response
|
14
|
+
"expected that #{actual.api_class.response_body(actual.response, format: :hash)} would contain value #{expected}"
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
@@ -22,31 +21,30 @@ RSpec::Matchers.define :include_in_body do |expected|
|
|
22
21
|
expect(actual.api_class.include_in_body?(actual.response, expected)).to be true
|
23
22
|
end
|
24
23
|
|
25
|
-
# TODO: Fix this for REST
|
26
24
|
failure_message do |actual|
|
27
|
-
"expected that #{actual.
|
25
|
+
"expected that #{actual.api_class.response_body(actual.response, format: :xml)} would contain value #{expected}"
|
28
26
|
end
|
29
27
|
end
|
30
28
|
|
31
29
|
# Whether expected element exists in body
|
32
30
|
RSpec::Matchers.define :contain_key do |expected|
|
33
31
|
match do |actual|
|
34
|
-
expect(actual.
|
32
|
+
expect(actual.api_class.include_key?(actual.response, expected)).to be true
|
35
33
|
end
|
36
34
|
|
37
35
|
failure_message do |actual|
|
38
|
-
"expected that #{actual.response
|
36
|
+
"expected that #{actual.api_class.response_body(actual.response, format: :hash)} would contain key #{expected}"
|
39
37
|
end
|
40
38
|
end
|
41
39
|
|
42
40
|
# Whether an element exists at expected xpath
|
43
41
|
RSpec::Matchers.define :have_element_at_xpath do |xpath|
|
44
42
|
match do |exchange|
|
45
|
-
expect { exchange[xpath] }.to_not raise_error
|
43
|
+
expect { exchange[xpath] }.to_not raise_error # Error will be raised if XPath returns no value
|
46
44
|
end
|
47
45
|
|
48
46
|
failure_message do |actual|
|
49
|
-
"expected that #{actual.response
|
47
|
+
"expected that #{actual.api_class.response_body(actual.response, format: :xml)} would have element at xpath '#{xpath}'"
|
50
48
|
end
|
51
49
|
end
|
52
50
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
# Raised to represent when there's no element at an Xpath
|
3
|
+
class NoElementAtXpath < StandardError
|
4
|
+
def initialize(msg="No element at Xpath found")
|
5
|
+
super
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# Did not find any element by provided key in the Hash
|
10
|
+
class NoElementInHash < StandardError
|
11
|
+
def initialize(msg='No element in Hash found')
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
@@ -10,7 +10,7 @@ shared_examples_for 'success scenario' do
|
|
10
10
|
expect(described_class).to contain_key mandatory_element
|
11
11
|
end
|
12
12
|
end
|
13
|
-
# TODO: Remove this. Handle
|
13
|
+
# TODO: Remove this. Handle deprecated method temporarily
|
14
14
|
described_class.api_class.mandatory_elements.each do |mandatory_element|
|
15
15
|
puts "Overriding 'mandatory_elements' deprecated. Use new 'expected_mandatory_elements' instead of overriding this method"
|
16
16
|
it mandatory_element do
|
data/lib/soaspec/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: soaspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.31
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SamuelGarrattIQA
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -152,17 +152,18 @@ files:
|
|
152
152
|
- exe/xml_to_yaml_file
|
153
153
|
- lib/soaspec.rb
|
154
154
|
- lib/soaspec/accessors.rb
|
155
|
-
- lib/soaspec/basic_soap_handler.rb
|
156
155
|
- lib/soaspec/exchange.rb
|
157
|
-
- lib/soaspec/exchange_handler.rb
|
156
|
+
- lib/soaspec/exchange_handlers/exchange_handler.rb
|
157
|
+
- lib/soaspec/exchange_handlers/rest_handler.rb
|
158
|
+
- lib/soaspec/exchange_handlers/soap_handler.rb
|
158
159
|
- lib/soaspec/exe_helpers.rb
|
159
160
|
- lib/soaspec/hash_methods.rb
|
161
|
+
- lib/soaspec/interpreter.rb
|
160
162
|
- lib/soaspec/matchers.rb
|
161
|
-
- lib/soaspec/
|
163
|
+
- lib/soaspec/not_found_errors.rb
|
162
164
|
- lib/soaspec/soaspec_shared_examples.rb
|
163
165
|
- lib/soaspec/spec_logger.rb
|
164
166
|
- lib/soaspec/version.rb
|
165
|
-
- lib/soaspec/xpath_not_found.rb
|
166
167
|
- soaspec.gemspec
|
167
168
|
- template/soap_template.xml
|
168
169
|
- test.wsdl
|