api-tester 1.1.1 → 1.1.2
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/.github/workflows/dependabot.yml +29 -0
- data/.github/workflows/push.yml +1 -1
- data/.github/workflows/test.yml +3 -3
- data/.rubocop.yml +136 -26
- data/README.md +1 -1
- data/api-tester.gemspec +3 -3
- data/lib/api-tester/config.rb +1 -2
- data/lib/api-tester/definition/boundary_case.rb +1 -3
- data/lib/api-tester/definition/contract.rb +4 -4
- data/lib/api-tester/definition/endpoint.rb +35 -17
- data/lib/api-tester/definition/fields/array_field.rb +8 -4
- data/lib/api-tester/definition/fields/boolean_field.rb +9 -2
- data/lib/api-tester/definition/fields/email_field.rb +16 -2
- data/lib/api-tester/definition/fields/enum_field.rb +8 -4
- data/lib/api-tester/definition/fields/field.rb +12 -6
- data/lib/api-tester/definition/fields/number_field.rb +13 -2
- data/lib/api-tester/definition/fields/object_field.rb +8 -4
- data/lib/api-tester/definition/fields/plain_array_field.rb +2 -2
- data/lib/api-tester/definition/method.rb +1 -3
- data/lib/api-tester/definition/request.rb +7 -10
- data/lib/api-tester/definition/response.rb +11 -4
- data/lib/api-tester/method_case_test.rb +8 -8
- data/lib/api-tester/modules/benchmark_module.rb +35 -0
- data/lib/api-tester/modules/extra_verbs.rb +7 -1
- data/lib/api-tester/modules/good_case.rb +1 -1
- data/lib/api-tester/modules/good_variations.rb +69 -0
- data/lib/api-tester/modules/injection_module.rb +12 -6
- data/lib/api-tester/modules/missing_resource.rb +64 -0
- data/lib/api-tester/modules/server_information.rb +1 -2
- data/lib/api-tester/modules/typo.rb +3 -1
- data/lib/api-tester/modules/unused_fields.rb +1 -1
- data/lib/api-tester/reporter/api_report.rb +3 -2
- data/lib/api-tester/reporter/missing_field_report.rb +1 -4
- data/lib/api-tester/reporter/report.rb +2 -6
- data/lib/api-tester/reporter/response_time_report.rb +24 -0
- data/lib/api-tester/reporter/status_code_report.rb +1 -2
- data/lib/api-tester/test_helper.rb +2 -0
- data/lib/api-tester/util/response_evaluator.rb +37 -22
- data/lib/api-tester/util/supported_verbs.rb +2 -2
- data/lib/api-tester/version.rb +1 -1
- metadata +14 -9
@@ -5,10 +5,7 @@ require 'api-tester/definition/boundary_case'
|
|
5
5
|
module ApiTester
|
6
6
|
# Class for defining requests in a contract
|
7
7
|
class Request
|
8
|
-
attr_accessor :definition
|
9
|
-
attr_accessor :header_fields
|
10
|
-
attr_accessor :fields
|
11
|
-
attr_accessor :query_params
|
8
|
+
attr_accessor :definition, :header_fields, :fields, :query_params
|
12
9
|
|
13
10
|
def initialize
|
14
11
|
self.fields = []
|
@@ -27,7 +24,7 @@ module ApiTester
|
|
27
24
|
end
|
28
25
|
|
29
26
|
def default_query
|
30
|
-
query_params.map { |param| "#{param.name}=#{param.
|
27
|
+
query_params.map { |param| "#{param.name}=#{param.default}" }.join('&')
|
31
28
|
end
|
32
29
|
|
33
30
|
def add_header_field(new_header)
|
@@ -39,7 +36,7 @@ module ApiTester
|
|
39
36
|
response = {}
|
40
37
|
fields.each do |field|
|
41
38
|
if field.required == true
|
42
|
-
response[field.name] = field.
|
39
|
+
response[field.name] = field.default
|
43
40
|
end
|
44
41
|
end
|
45
42
|
response
|
@@ -50,17 +47,17 @@ module ApiTester
|
|
50
47
|
end
|
51
48
|
|
52
49
|
def default_headers
|
53
|
-
if header_fields
|
54
|
-
headers
|
55
|
-
else
|
50
|
+
if header_fields == []
|
56
51
|
{ content_type: :json, accept: :json }
|
52
|
+
else
|
53
|
+
headers
|
57
54
|
end
|
58
55
|
end
|
59
56
|
|
60
57
|
def headers
|
61
58
|
header_response = {}
|
62
59
|
header_fields.each do |header_field|
|
63
|
-
header_response[header_field.name] = header_field.
|
60
|
+
header_response[header_field.name] = header_field.default
|
64
61
|
end
|
65
62
|
header_response
|
66
63
|
end
|
@@ -3,8 +3,7 @@
|
|
3
3
|
module ApiTester
|
4
4
|
# Class for defining expected responses
|
5
5
|
class Response
|
6
|
-
attr_accessor :code
|
7
|
-
attr_accessor :body
|
6
|
+
attr_accessor :code, :body
|
8
7
|
|
9
8
|
def initialize(status_code: 200)
|
10
9
|
self.code = status_code
|
@@ -19,7 +18,11 @@ module ApiTester
|
|
19
18
|
def to_s
|
20
19
|
des = {}
|
21
20
|
body.map do |f|
|
22
|
-
|
21
|
+
if f.has_key
|
22
|
+
des[f.name] = field_display f
|
23
|
+
else
|
24
|
+
des = field_display f
|
25
|
+
end
|
23
26
|
end
|
24
27
|
des.to_json
|
25
28
|
end
|
@@ -29,7 +32,11 @@ module ApiTester
|
|
29
32
|
if field.subfields?
|
30
33
|
des = {}
|
31
34
|
field.fields.map do |f|
|
32
|
-
|
35
|
+
if f.has_key
|
36
|
+
des[f.name] = field_display f
|
37
|
+
else
|
38
|
+
des = field_display f
|
39
|
+
end
|
33
40
|
end
|
34
41
|
des.to_json
|
35
42
|
end
|
@@ -1,16 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'api-tester/util/response_evaluator
|
3
|
+
require 'api-tester/util/response_evaluator'
|
4
4
|
|
5
5
|
module ApiTester
|
6
6
|
# Class for testing methods
|
7
7
|
class MethodCaseTest
|
8
|
-
attr_accessor :expected_response
|
9
|
-
attr_accessor :payload
|
10
|
-
attr_accessor :response
|
11
|
-
attr_accessor :reports
|
12
|
-
attr_accessor :url
|
13
|
-
attr_accessor :module_name
|
8
|
+
attr_accessor :expected_response, :payload, :response, :reports, :url, :module_name
|
14
9
|
|
15
10
|
def initialize(response:, payload:, expected_response:, url:, verb:, module_name:)
|
16
11
|
self.payload = payload
|
@@ -22,6 +17,7 @@ module ApiTester
|
|
22
17
|
end
|
23
18
|
|
24
19
|
def response_code_report
|
20
|
+
print 'F'
|
25
21
|
report = StatusCodeReport.new description: "#{module_name} - Incorrect response code",
|
26
22
|
url: url,
|
27
23
|
request: payload,
|
@@ -32,6 +28,7 @@ module ApiTester
|
|
32
28
|
end
|
33
29
|
|
34
30
|
def missing_field_report(field)
|
31
|
+
print 'F'
|
35
32
|
report = Report.new description: "#{module_name} - Missing field #{field}",
|
36
33
|
url: url,
|
37
34
|
request: payload,
|
@@ -42,6 +39,7 @@ module ApiTester
|
|
42
39
|
end
|
43
40
|
|
44
41
|
def extra_field_report(field)
|
42
|
+
print 'F'
|
45
43
|
report = Report.new description: "#{module_name} - Found extra field #{field}",
|
46
44
|
url: url,
|
47
45
|
request: payload,
|
@@ -53,6 +51,7 @@ module ApiTester
|
|
53
51
|
|
54
52
|
def check
|
55
53
|
if check_response_code
|
54
|
+
print '.'
|
56
55
|
evaluator = ApiTester::ResponseEvaluator.new actual_body: json_parse(response.body),
|
57
56
|
expected_fields: expected_response
|
58
57
|
evaluator.missing_fields.map { |field| missing_field_report(field) }
|
@@ -63,7 +62,8 @@ module ApiTester
|
|
63
62
|
end
|
64
63
|
|
65
64
|
def check_response_code
|
66
|
-
if response.code != expected_response.code
|
65
|
+
if response && (response.code != expected_response.code)
|
66
|
+
print 'F'
|
67
67
|
response_code_report
|
68
68
|
return false
|
69
69
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'api-tester/reporter/response_time_report'
|
4
|
+
|
5
|
+
module ApiTester
|
6
|
+
# Checks the response times collected during the test run
|
7
|
+
# Note: Needs at least one calling module, like GoodCase, to work
|
8
|
+
module BenchmarkModule
|
9
|
+
def self.go(contract)
|
10
|
+
reports = []
|
11
|
+
|
12
|
+
contract.endpoints.each do |endpoint|
|
13
|
+
longest_time = endpoint.longest_time
|
14
|
+
longest_time[:time] = longest_time[:time] * 1000.0 # Convert from seconds to ms
|
15
|
+
if longest_time[:time] > contract.max_time
|
16
|
+
print 'F'
|
17
|
+
reports << ResponseTimeReport.new(url: endpoint.url,
|
18
|
+
verb: longest_time[:verb],
|
19
|
+
payload: longest_time[:payload],
|
20
|
+
max_time: contract.max_time,
|
21
|
+
actual_time: longest_time[:time],
|
22
|
+
description: 'BenchmarkModule')
|
23
|
+
else
|
24
|
+
print '.'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
reports
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.order
|
32
|
+
99
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'api-tester/util/supported_verbs'
|
4
|
+
require 'api-tester/definition/method'
|
5
|
+
require 'api-tester/method_case_test'
|
4
6
|
|
5
7
|
module ApiTester
|
6
8
|
# Check verbs not explicitly defined in contract
|
@@ -9,7 +11,7 @@ module ApiTester
|
|
9
11
|
reports = []
|
10
12
|
|
11
13
|
contract.endpoints.each do |endpoint|
|
12
|
-
extras =
|
14
|
+
extras = supported_verbs - endpoint.verbs
|
13
15
|
headers = endpoint.methods[0].request.default_headers
|
14
16
|
extras.each do |verb|
|
15
17
|
verb_case = BoundaryCase.new description: "Verb check with #{verb} for #{endpoint.name}",
|
@@ -34,6 +36,10 @@ module ApiTester
|
|
34
36
|
reports
|
35
37
|
end
|
36
38
|
|
39
|
+
def self.supported_verbs
|
40
|
+
ApiTester::SupportedVerbs.all
|
41
|
+
end
|
42
|
+
|
37
43
|
def self.order
|
38
44
|
3
|
39
45
|
end
|
@@ -11,7 +11,7 @@ module ApiTester
|
|
11
11
|
|
12
12
|
contract.endpoints.each do |endpoint|
|
13
13
|
endpoint.methods.each do |method|
|
14
|
-
default_case = BoundaryCase.new description: contract.base_url + endpoint.
|
14
|
+
default_case = BoundaryCase.new description: contract.base_url + endpoint.display_url,
|
15
15
|
payload: method.request.default_payload,
|
16
16
|
headers: method.request.default_headers
|
17
17
|
response = endpoint.call base_url: contract.base_url,
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'api-tester/reporter/status_code_report'
|
4
|
+
require 'api-tester/method_case_test'
|
5
|
+
|
6
|
+
module ApiTester
|
7
|
+
# Checks the good case as defined in contract
|
8
|
+
module GoodVariations
|
9
|
+
def self.go(contract)
|
10
|
+
reports = []
|
11
|
+
|
12
|
+
contract.endpoints.each do |endpoint|
|
13
|
+
endpoint.methods.each do |method|
|
14
|
+
method.request.fields.each do |field|
|
15
|
+
field.good_cases.each do |value|
|
16
|
+
payload = method.request.default_payload
|
17
|
+
payload[field.name] = value
|
18
|
+
call = BoundaryCase.new description: contract.base_url + endpoint.display_url,
|
19
|
+
payload: payload,
|
20
|
+
headers: method.request.default_headers
|
21
|
+
response = endpoint.call base_url: contract.base_url,
|
22
|
+
method: method,
|
23
|
+
payload: payload,
|
24
|
+
headers: call.headers
|
25
|
+
test = GoodVariationTest.new response: response,
|
26
|
+
url: contract.base_url + endpoint.url,
|
27
|
+
method: method
|
28
|
+
reports.concat test.check
|
29
|
+
end
|
30
|
+
end
|
31
|
+
method.request.query_params.each do |field|
|
32
|
+
field.good_cases.each do |value|
|
33
|
+
payload = method.request.default_payload
|
34
|
+
payload[field.name] = value
|
35
|
+
call = BoundaryCase.new description: contract.base_url + endpoint.display_url,
|
36
|
+
payload: payload,
|
37
|
+
headers: method.request.default_headers
|
38
|
+
response = endpoint.call base_url: contract.base_url,
|
39
|
+
method: method,
|
40
|
+
payload: payload,
|
41
|
+
headers: call.headers
|
42
|
+
test = GoodVariationTest.new response: response,
|
43
|
+
url: contract.base_url + endpoint.url,
|
44
|
+
method: method
|
45
|
+
reports.concat test.check
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
reports
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.order
|
54
|
+
1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Test layout used by module
|
59
|
+
class GoodVariationTest < MethodCaseTest
|
60
|
+
def initialize(response:, url:, method:)
|
61
|
+
super response: response,
|
62
|
+
payload: method.request.default_payload,
|
63
|
+
expected_response: method.expected_response,
|
64
|
+
url: url,
|
65
|
+
verb: method.verb,
|
66
|
+
module_name: 'GoodVariationsModule'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -21,7 +21,7 @@ module ApiTester
|
|
21
21
|
|
22
22
|
method.request.fields.each do |field|
|
23
23
|
sql_injections.each do |injection|
|
24
|
-
injection_value = "#{field.
|
24
|
+
injection_value = "#{field.default}#{injection}"
|
25
25
|
payload = method.request.altered_payload field_name: field.name,
|
26
26
|
value: injection_value
|
27
27
|
response = endpoint.call base_url: base_url,
|
@@ -41,7 +41,12 @@ module ApiTester
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def self.check_response(response, endpoint)
|
44
|
-
response.code == 200 || check_error(response, endpoint)
|
44
|
+
if response.code == 200 || check_error(response, endpoint)
|
45
|
+
print '.'
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
print 'F'
|
49
|
+
false
|
45
50
|
end
|
46
51
|
|
47
52
|
def self.check_error(response, endpoint)
|
@@ -54,15 +59,16 @@ module ApiTester
|
|
54
59
|
response.code == endpoint.bad_request_response.code &&
|
55
60
|
missing_fields.size.zero? && extra_fields.size.zero?
|
56
61
|
end
|
62
|
+
|
63
|
+
def self.order
|
64
|
+
5
|
65
|
+
end
|
57
66
|
end
|
58
67
|
end
|
59
68
|
|
60
69
|
# Report for InjectionModule
|
61
70
|
class InjectionReport
|
62
|
-
attr_accessor :injection_type
|
63
|
-
attr_accessor :url
|
64
|
-
attr_accessor :payload
|
65
|
-
attr_accessor :response
|
71
|
+
attr_accessor :injection_type, :url, :payload, :response
|
66
72
|
|
67
73
|
def initialize(injection_type, url, payload, response)
|
68
74
|
self.injection_type = injection_type
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'api-tester/reporter/status_code_report'
|
4
|
+
require 'api-tester/util/supported_verbs'
|
5
|
+
require 'pry'
|
6
|
+
|
7
|
+
module ApiTester
|
8
|
+
# Module checking various not found scenarios
|
9
|
+
module MissingResource
|
10
|
+
def self.go(contract)
|
11
|
+
reports = []
|
12
|
+
|
13
|
+
contract.endpoints.each do |endpoint|
|
14
|
+
endpoint.path_params.each do |path_param|
|
15
|
+
bad_resource = endpoint.relative_url.gsub("{#{path_param}}", 'gibberish')
|
16
|
+
|
17
|
+
bad_endpoint = ApiTester::Endpoint.new name: 'Bad Resource',
|
18
|
+
relative_url: bad_resource
|
19
|
+
method = ApiTester::Method.new verb: ApiTester::SupportedVerbs::GET,
|
20
|
+
response: ApiTester::Response.new(
|
21
|
+
status_code: 200
|
22
|
+
),
|
23
|
+
request: ApiTester::Request.new
|
24
|
+
response = bad_endpoint.call base_url: contract.base_url + bad_resource,
|
25
|
+
method: method,
|
26
|
+
payload: {},
|
27
|
+
headers: contract.required_headers
|
28
|
+
test = MissingResourceTest.new response,
|
29
|
+
{},
|
30
|
+
endpoint.not_found_response,
|
31
|
+
bad_resource,
|
32
|
+
ApiTester::SupportedVerbs::GET
|
33
|
+
test.check
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
reports
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.allowed_verbs(endpoint)
|
41
|
+
allowances = []
|
42
|
+
endpoint.methods.each do |method|
|
43
|
+
allowances << method.verb
|
44
|
+
end
|
45
|
+
allowances.uniq
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.order
|
49
|
+
4
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Test layout for Missing Resource
|
54
|
+
class MissingResourceTest < MethodCaseTest
|
55
|
+
def initialize(response, payload, expected_response, url, verb)
|
56
|
+
super response: response,
|
57
|
+
payload: payload,
|
58
|
+
expected_response: expected_response,
|
59
|
+
url: url,
|
60
|
+
verb: verb,
|
61
|
+
module_name: 'Missing Resource'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -9,7 +9,9 @@ module ApiTester
|
|
9
9
|
def self.go(contract)
|
10
10
|
reports = []
|
11
11
|
|
12
|
-
|
12
|
+
# Filtering out endpoints with ids since not a better way to check this
|
13
|
+
# Need to redesign system to handle this better
|
14
|
+
contract.endpoints.reject { |e| e.relative_url.include?('{') }.each do |endpoint|
|
13
15
|
allowances(endpoint).each do
|
14
16
|
reports.concat check_typo_url(contract.base_url, endpoint)
|
15
17
|
end
|
@@ -10,7 +10,7 @@ module ApiTester
|
|
10
10
|
|
11
11
|
contract.endpoints.each do |endpoint|
|
12
12
|
endpoint.methods.each do |method|
|
13
|
-
method.expected_response.body.each do |field|
|
13
|
+
method.expected_response.body.filter(&:has_key).each do |field|
|
14
14
|
next unless field.is_seen.zero?
|
15
15
|
|
16
16
|
reports << MissingFieldReport.new(url: endpoint.url,
|
@@ -31,14 +31,15 @@ module ApiTester
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def print
|
34
|
+
puts ''
|
34
35
|
if reports.size.zero?
|
35
36
|
puts 'No issues found'
|
36
37
|
else
|
37
38
|
puts "Issues discovered: #{reports.size}"
|
38
39
|
reports.each do |report|
|
39
40
|
report.print
|
40
|
-
puts '
|
41
|
-
puts '
|
41
|
+
puts ''
|
42
|
+
puts ''
|
42
43
|
end
|
43
44
|
puts "Total issues: #{reports.size}"
|
44
45
|
end
|
@@ -3,10 +3,7 @@
|
|
3
3
|
module ApiTester
|
4
4
|
# Report used for when response is missing a field
|
5
5
|
class MissingFieldReport
|
6
|
-
attr_accessor :url
|
7
|
-
attr_accessor :verb
|
8
|
-
attr_accessor :expected_field
|
9
|
-
attr_accessor :description
|
6
|
+
attr_accessor :url, :verb, :expected_field, :description
|
10
7
|
|
11
8
|
def initialize(url:, verb:, expected_field:, description:)
|
12
9
|
self.url = url
|
@@ -3,11 +3,7 @@
|
|
3
3
|
module ApiTester
|
4
4
|
# Standard report format for differing responses
|
5
5
|
class Report
|
6
|
-
attr_accessor :description
|
7
|
-
attr_accessor :url
|
8
|
-
attr_accessor :request
|
9
|
-
attr_accessor :expected_response
|
10
|
-
attr_accessor :actual_response
|
6
|
+
attr_accessor :description, :url, :request, :expected_response, :actual_response
|
11
7
|
|
12
8
|
def initialize(description:, url:, request:, expected_response:, actual_response:)
|
13
9
|
self.description = description
|
@@ -22,7 +18,7 @@ module ApiTester
|
|
22
18
|
puts " Requested #{url} with payload:"
|
23
19
|
puts " #{request.to_json}"
|
24
20
|
puts ' Expecting: '
|
25
|
-
puts
|
21
|
+
puts " #{expected_response}"
|
26
22
|
puts ' Receiving: '
|
27
23
|
puts " #{actual_response}"
|
28
24
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ApiTester
|
4
|
+
# Report used for when response took too long
|
5
|
+
class ResponseTimeReport
|
6
|
+
attr_accessor :url, :verb, :payload, :max_time, :actual_time, :description
|
7
|
+
|
8
|
+
def initialize(url:, verb:, payload:, max_time:, actual_time:, description:)
|
9
|
+
self.url = url
|
10
|
+
self.verb = verb
|
11
|
+
self.payload = payload
|
12
|
+
self.max_time = max_time
|
13
|
+
self.actual_time = actual_time
|
14
|
+
self.description = description
|
15
|
+
end
|
16
|
+
|
17
|
+
def print
|
18
|
+
puts "#{description}:"
|
19
|
+
puts " #{verb} #{url} took #{actual_time}ms, the max time is #{max_time}ms:"
|
20
|
+
puts ' Payload:'
|
21
|
+
puts " #{payload}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -5,8 +5,7 @@ require 'api-tester/reporter/report'
|
|
5
5
|
module ApiTester
|
6
6
|
# Report for when status code is different than expected
|
7
7
|
class StatusCodeReport < Report
|
8
|
-
attr_accessor :expected_status_code
|
9
|
-
attr_accessor :actual_status_code
|
8
|
+
attr_accessor :expected_status_code, :actual_status_code
|
10
9
|
|
11
10
|
def initialize(description:, url:, request:, expected_status_code:, actual_status_code:)
|
12
11
|
super description: description,
|
@@ -3,12 +3,12 @@
|
|
3
3
|
module ApiTester
|
4
4
|
# Class for evaluating responses against what is expected
|
5
5
|
class ResponseEvaluator
|
6
|
-
attr_accessor :response_body
|
7
|
-
attr_accessor :expected_response
|
6
|
+
attr_accessor :response_body, :expected_response, :expected_fields_hash
|
8
7
|
|
9
8
|
def initialize(actual_body:, expected_fields:)
|
10
9
|
self.response_body = actual_body
|
11
10
|
self.expected_response = expected_fields
|
11
|
+
self.expected_fields_hash = expected_field_array(expected_response.body)
|
12
12
|
end
|
13
13
|
|
14
14
|
def response_field_array
|
@@ -29,10 +29,6 @@ module ApiTester
|
|
29
29
|
seen
|
30
30
|
end
|
31
31
|
|
32
|
-
def expected_fields_hash
|
33
|
-
expected_field_array expected_response.body
|
34
|
-
end
|
35
|
-
|
36
32
|
def extra_fields
|
37
33
|
response_field_array - expected_fields
|
38
34
|
end
|
@@ -44,9 +40,14 @@ module ApiTester
|
|
44
40
|
def expected_field_array(expected_fields)
|
45
41
|
fields = {}
|
46
42
|
expected_fields.each do |field|
|
47
|
-
|
43
|
+
field_name = field.name
|
44
|
+
if field.has_key
|
45
|
+
fields[field.name] = field
|
46
|
+
else
|
47
|
+
field_name = field.type
|
48
|
+
end
|
48
49
|
fields = fields.merge inner_expected_field(expected_fields: field.fields,
|
49
|
-
name:
|
50
|
+
name: field_name)
|
50
51
|
end
|
51
52
|
fields
|
52
53
|
end
|
@@ -55,7 +56,11 @@ module ApiTester
|
|
55
56
|
fields = {}
|
56
57
|
expected_fields.each do |field|
|
57
58
|
inner_name = "#{name}.#{field.name}"
|
58
|
-
|
59
|
+
if field.has_key
|
60
|
+
fields[inner_name] = field
|
61
|
+
else
|
62
|
+
inner_name = "#{name}.#{field.type}"
|
63
|
+
end
|
59
64
|
fields = fields.merge inner_expected_field(expected_fields: field.fields,
|
60
65
|
name: inner_name)
|
61
66
|
end
|
@@ -65,21 +70,31 @@ module ApiTester
|
|
65
70
|
def field_array(object)
|
66
71
|
fields = []
|
67
72
|
|
68
|
-
object.
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
73
|
+
if object.instance_of?(Array)
|
74
|
+
name = 'array'
|
75
|
+
fields.concat(field_array(object[0]).map { |i| "#{name}.#{i}" })
|
76
|
+
else
|
77
|
+
object.each do |key, value|
|
78
|
+
if key.respond_to?('each')
|
79
|
+
fields.concat(field_array(key))
|
80
|
+
elsif value == nil || value == 0 || value == false
|
81
|
+
fields << key.to_s
|
82
|
+
fields.concat(field_array(value).map { |i| "#{key}.#{i}" })
|
83
|
+
elsif value.to_s[0] == '[' && value.to_s[-1] == ']' && !value.to_s.include?('=>')
|
84
|
+
fields << key.to_s
|
85
|
+
elsif value
|
86
|
+
passed_value = value
|
87
|
+
fields << key.to_s
|
88
|
+
if value.instance_of?(Array)
|
89
|
+
passed_value = value[0]
|
90
|
+
end
|
91
|
+
fields.concat(field_array(passed_value).map { |i| "#{key}.#{i}" })
|
92
|
+
else
|
93
|
+
fields.concat(field_array(key))
|
94
|
+
end
|
81
95
|
end
|
82
96
|
end
|
97
|
+
|
83
98
|
fields
|
84
99
|
rescue NoMethodError
|
85
100
|
fields
|
data/lib/api-tester/version.rb
CHANGED