api-tester 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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