api-tester 0.3.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 +5 -5
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/dependabot.yml +29 -0
- data/.github/workflows/push.yml +39 -0
- data/.github/workflows/test.yml +31 -0
- data/.rspec +1 -0
- data/.rubocop.yml +171 -0
- data/Gemfile +2 -0
- data/Guardfile +70 -0
- data/README.md +67 -63
- data/Rakefile +8 -3
- data/api-tester.gemspec +29 -23
- data/changelog.txt +19 -0
- data/lib/api-tester/config.rb +17 -15
- data/lib/api-tester/definition/boundary_case.rb +5 -4
- data/lib/api-tester/definition/contract.rb +10 -5
- data/lib/api-tester/definition/endpoint.rb +59 -32
- data/lib/api-tester/definition/fields/array_field.rb +26 -21
- data/lib/api-tester/definition/fields/boolean_field.rb +17 -7
- data/lib/api-tester/definition/fields/email_field.rb +28 -11
- data/lib/api-tester/definition/fields/enum_field.rb +19 -12
- data/lib/api-tester/definition/fields/field.rb +52 -45
- data/lib/api-tester/definition/fields/number_field.rb +20 -6
- data/lib/api-tester/definition/fields/object_field.rb +37 -30
- data/lib/api-tester/definition/fields/plain_array_field.rb +25 -0
- data/lib/api-tester/definition/method.rb +8 -5
- data/lib/api-tester/definition/request.rb +55 -13
- data/lib/api-tester/definition/response.rb +35 -25
- data/lib/api-tester/method_case_test.rb +68 -54
- data/lib/api-tester/modules/benchmark_module.rb +35 -0
- data/lib/api-tester/modules/extra_verbs.rb +37 -10
- data/lib/api-tester/modules/format.rb +23 -8
- data/lib/api-tester/modules/good_case.rb +25 -10
- data/lib/api-tester/modules/good_variations.rb +69 -0
- data/lib/api-tester/modules/injection_module.rb +44 -23
- data/lib/api-tester/modules/missing_resource.rb +64 -0
- data/lib/api-tester/modules/required_fields.rb +51 -0
- data/lib/api-tester/modules/server_information.rb +14 -12
- data/lib/api-tester/modules/typo.rb +39 -14
- data/lib/api-tester/modules/unexpected_fields.rb +61 -0
- data/lib/api-tester/modules/unused_fields.rb +13 -7
- data/lib/api-tester/reporter/api_report.rb +25 -16
- data/lib/api-tester/reporter/missing_field_report.rb +11 -15
- data/lib/api-tester/reporter/report.rb +12 -13
- data/lib/api-tester/reporter/response_time_report.rb +24 -0
- data/lib/api-tester/reporter/status_code_report.rb +10 -4
- data/lib/api-tester/test_helper.rb +8 -6
- data/lib/api-tester/util/response_evaluator.rb +84 -56
- data/lib/api-tester/util/supported_verbs.rb +8 -5
- data/lib/api-tester/version.rb +3 -1
- data/lib/api-tester.rb +6 -3
- metadata +117 -24
- data/.travis.yml +0 -6
- data/lib/api-tester/reporter/missing_response_field_report.rb +0 -21
@@ -1,18 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'api-tester/definition/fields/field'
|
2
4
|
|
3
5
|
module ApiTester
|
6
|
+
# Class for defining numeric fields in contracts
|
4
7
|
class NumberField < Field
|
5
|
-
def initialize(name,
|
6
|
-
super
|
8
|
+
def initialize(name:, default: 5, required: false)
|
9
|
+
super name: name, default: default, required: required
|
7
10
|
end
|
8
11
|
|
9
12
|
def negative_boundary_values
|
10
13
|
super +
|
14
|
+
[
|
15
|
+
'string',
|
16
|
+
true,
|
17
|
+
false,
|
18
|
+
{}
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def good_cases
|
11
23
|
[
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
24
|
+
-1,
|
25
|
+
0,
|
26
|
+
1,
|
27
|
+
100,
|
28
|
+
9999,
|
29
|
+
12_345_678_901_234_567_890
|
16
30
|
]
|
17
31
|
end
|
18
32
|
end
|
@@ -1,44 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'api-tester/definition/fields/field'
|
2
4
|
|
3
5
|
module ApiTester
|
6
|
+
# Class for defining objects in a contract
|
4
7
|
class ObjectField < Field
|
5
|
-
|
8
|
+
attr_accessor :fields
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
10
|
+
def initialize(name:, required: false, has_key: true)
|
11
|
+
super name: name, required: required, has_key: has_key
|
12
|
+
self.fields = []
|
13
|
+
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
def with_field(new_field)
|
16
|
+
fields << new_field
|
17
|
+
self
|
18
|
+
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
+
def subfields?
|
21
|
+
true
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
24
|
+
def type
|
25
|
+
'object'
|
26
|
+
end
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
end
|
28
|
+
def default
|
29
|
+
obj = {}
|
27
30
|
|
28
|
-
|
31
|
+
fields.each do |field|
|
32
|
+
obj[field.name] = field.default
|
29
33
|
end
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
35
|
+
obj
|
36
|
+
end
|
37
|
+
|
38
|
+
def negative_boundary_values
|
39
|
+
super +
|
40
|
+
[
|
41
|
+
'string',
|
42
|
+
[],
|
43
|
+
123,
|
44
|
+
1,
|
45
|
+
0,
|
46
|
+
true,
|
47
|
+
false
|
48
|
+
]
|
49
|
+
end
|
43
50
|
end
|
44
51
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'api-tester/definition/fields/field'
|
4
|
+
|
5
|
+
module ApiTester
|
6
|
+
# Class for defining plain arrays
|
7
|
+
class PlainArrayField < Field
|
8
|
+
def initialize(name:, default: [], required: false)
|
9
|
+
super name: name, default: default, required: required
|
10
|
+
end
|
11
|
+
|
12
|
+
def negative_boundary_values
|
13
|
+
super +
|
14
|
+
[
|
15
|
+
'string',
|
16
|
+
123,
|
17
|
+
0,
|
18
|
+
1,
|
19
|
+
{},
|
20
|
+
true,
|
21
|
+
false
|
22
|
+
]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,17 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ApiTester
|
4
|
+
# Class for defining methods as part of an endpoint
|
2
5
|
class Method
|
3
|
-
attr_accessor :request
|
4
|
-
attr_accessor :expected_response
|
5
|
-
attr_accessor :verb
|
6
|
+
attr_accessor :request, :expected_response, :verb
|
6
7
|
|
7
|
-
def initialize
|
8
|
+
def initialize(verb:, response:, request:)
|
8
9
|
self.verb = verb
|
9
10
|
self.request = request
|
10
11
|
self.expected_response = response
|
11
12
|
end
|
12
13
|
|
13
14
|
def default_request
|
14
|
-
{:
|
15
|
+
{ method: verb,
|
16
|
+
payload: request.default_payload,
|
17
|
+
headers: request.default_headers }
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
@@ -1,24 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'api-tester/definition/boundary_case'
|
2
4
|
|
3
5
|
module ApiTester
|
6
|
+
# Class for defining requests in a contract
|
4
7
|
class Request
|
5
|
-
attr_accessor :definition
|
6
|
-
attr_accessor :headers
|
7
|
-
attr_accessor :fields
|
8
|
+
attr_accessor :definition, :header_fields, :fields, :query_params
|
8
9
|
|
9
10
|
def initialize
|
10
11
|
self.fields = []
|
12
|
+
self.header_fields = []
|
13
|
+
self.query_params = []
|
11
14
|
end
|
12
15
|
|
13
16
|
def add_field(new_field)
|
14
|
-
|
17
|
+
fields << new_field
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_query_param(new_query_param)
|
22
|
+
query_params << new_query_param
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def default_query
|
27
|
+
query_params.map { |param| "#{param.name}=#{param.default}" }.join('&')
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_header_field(new_header)
|
31
|
+
header_fields << new_header
|
15
32
|
self
|
16
33
|
end
|
17
34
|
|
18
35
|
def payload
|
19
|
-
response =
|
20
|
-
|
21
|
-
|
36
|
+
response = {}
|
37
|
+
fields.each do |field|
|
38
|
+
if field.required == true
|
39
|
+
response[field.name] = field.default
|
40
|
+
end
|
22
41
|
end
|
23
42
|
response
|
24
43
|
end
|
@@ -28,24 +47,47 @@ module ApiTester
|
|
28
47
|
end
|
29
48
|
|
30
49
|
def default_headers
|
31
|
-
|
50
|
+
if header_fields == []
|
51
|
+
{ content_type: :json, accept: :json }
|
52
|
+
else
|
53
|
+
headers
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def headers
|
58
|
+
header_response = {}
|
59
|
+
header_fields.each do |header_field|
|
60
|
+
header_response[header_field.name] = header_field.default
|
61
|
+
end
|
62
|
+
header_response
|
32
63
|
end
|
33
64
|
|
34
65
|
def cases
|
35
|
-
boundary_cases =
|
36
|
-
|
66
|
+
boundary_cases = []
|
67
|
+
fields.each do |field|
|
37
68
|
field.negative_boundary_values.each do |value|
|
38
|
-
bcase = BoundaryCase.new
|
39
|
-
|
69
|
+
bcase = BoundaryCase.new description: "Setting #{field.name} to #{value}",
|
70
|
+
payload: altered_payload(field_name: field.name,
|
71
|
+
value: value),
|
72
|
+
headers: default_headers
|
73
|
+
boundary_cases.push bcase
|
40
74
|
end
|
41
75
|
end
|
42
76
|
boundary_cases
|
43
77
|
end
|
44
78
|
|
45
|
-
def altered_payload
|
79
|
+
def altered_payload(field_name:, value:)
|
46
80
|
body = payload
|
47
81
|
body[field_name] = value
|
48
82
|
body
|
49
83
|
end
|
84
|
+
|
85
|
+
def altered_payload_with(fields)
|
86
|
+
body = payload
|
87
|
+
fields.each do |field|
|
88
|
+
body[field[:name]] = field[:value]
|
89
|
+
end
|
90
|
+
body
|
91
|
+
end
|
50
92
|
end
|
51
93
|
end
|
@@ -1,36 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ApiTester
|
4
|
+
# Class for defining expected responses
|
2
5
|
class Response
|
3
|
-
|
4
|
-
attr_accessor :body
|
6
|
+
attr_accessor :code, :body
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
def initialize(status_code: 200)
|
9
|
+
self.code = status_code
|
10
|
+
self.body = []
|
11
|
+
end
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def add_field(new_field)
|
14
|
+
body << new_field
|
15
|
+
self
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
def to_s
|
19
|
+
des = {}
|
20
|
+
body.map do |f|
|
21
|
+
if f.has_key
|
22
|
+
des[f.name] = field_display f
|
23
|
+
else
|
24
|
+
des = field_display f
|
25
|
+
end
|
22
26
|
end
|
27
|
+
des.to_json
|
28
|
+
end
|
23
29
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
def field_display(field)
|
31
|
+
des = field.display_class
|
32
|
+
if field.subfields?
|
33
|
+
des = {}
|
34
|
+
field.fields.map do |f|
|
35
|
+
if f.has_key
|
36
|
+
des[f.name] = field_display f
|
37
|
+
else
|
38
|
+
des = field_display f
|
32
39
|
end
|
33
|
-
|
40
|
+
end
|
41
|
+
des.to_json
|
34
42
|
end
|
43
|
+
des
|
44
|
+
end
|
35
45
|
end
|
36
46
|
end
|
@@ -1,69 +1,83 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'api-tester/util/response_evaluator'
|
2
4
|
|
3
5
|
module ApiTester
|
6
|
+
# Class for testing methods
|
4
7
|
class MethodCaseTest
|
5
|
-
|
6
|
-
attr_accessor :payload
|
7
|
-
attr_accessor :response
|
8
|
-
attr_accessor :reports
|
9
|
-
attr_accessor :url
|
10
|
-
attr_accessor :module_name
|
8
|
+
attr_accessor :expected_response, :payload, :response, :reports, :url, :module_name
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
def initialize(response:, payload:, expected_response:, url:, verb:, module_name:)
|
11
|
+
self.payload = payload
|
12
|
+
self.response = response
|
13
|
+
self.expected_response = expected_response
|
14
|
+
self.reports = []
|
15
|
+
self.url = "#{verb} #{url}"
|
16
|
+
self.module_name = module_name
|
17
|
+
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
def response_code_report
|
20
|
+
print 'F'
|
21
|
+
report = StatusCodeReport.new description: "#{module_name} - Incorrect response code",
|
22
|
+
url: url,
|
23
|
+
request: payload,
|
24
|
+
expected_status_code: expected_response.code,
|
25
|
+
actual_status_code: "#{response.code} : #{response.body}"
|
26
|
+
reports << report
|
27
|
+
nil
|
28
|
+
end
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
def missing_field_report(field)
|
31
|
+
print 'F'
|
32
|
+
report = Report.new description: "#{module_name} - Missing field #{field}",
|
33
|
+
url: url,
|
34
|
+
request: payload,
|
35
|
+
expected_response: expected_response,
|
36
|
+
actual_response: response
|
37
|
+
reports << report
|
38
|
+
nil
|
39
|
+
end
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
41
|
+
def extra_field_report(field)
|
42
|
+
print 'F'
|
43
|
+
report = Report.new description: "#{module_name} - Found extra field #{field}",
|
44
|
+
url: url,
|
45
|
+
request: payload,
|
46
|
+
expected_response: expected_response,
|
47
|
+
actual_response: response
|
48
|
+
reports << report
|
49
|
+
nil
|
50
|
+
end
|
38
51
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
52
|
+
def check
|
53
|
+
if check_response_code
|
54
|
+
print '.'
|
55
|
+
evaluator = ApiTester::ResponseEvaluator.new actual_body: json_parse(response.body),
|
56
|
+
expected_fields: expected_response
|
57
|
+
evaluator.missing_fields.map { |field| missing_field_report(field) }
|
58
|
+
evaluator.extra_fields.map { |field| extra_field_report(field) }
|
59
|
+
increment_fields evaluator.seen_fields
|
47
60
|
end
|
61
|
+
reports
|
62
|
+
end
|
48
63
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
return true
|
64
|
+
def check_response_code
|
65
|
+
if response && (response.code != expected_response.code)
|
66
|
+
print 'F'
|
67
|
+
response_code_report
|
68
|
+
return false
|
55
69
|
end
|
70
|
+
true
|
71
|
+
end
|
56
72
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
73
|
+
def increment_fields(seen_fields)
|
74
|
+
seen_fields.each(&:seen)
|
75
|
+
end
|
62
76
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
77
|
+
def json_parse(body)
|
78
|
+
JSON.parse!(body)
|
79
|
+
rescue JSON::ParserError
|
80
|
+
body
|
81
|
+
end
|
68
82
|
end
|
69
83
|
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,17 +1,34 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'api-tester/util/supported_verbs'
|
4
|
+
require 'api-tester/definition/method'
|
5
|
+
require 'api-tester/method_case_test'
|
2
6
|
|
3
7
|
module ApiTester
|
8
|
+
# Check verbs not explicitly defined in contract
|
4
9
|
module ExtraVerbs
|
5
|
-
def self.go
|
10
|
+
def self.go(contract)
|
6
11
|
reports = []
|
7
12
|
|
8
13
|
contract.endpoints.each do |endpoint|
|
9
|
-
extras =
|
14
|
+
extras = supported_verbs - endpoint.verbs
|
15
|
+
headers = endpoint.methods[0].request.default_headers
|
10
16
|
extras.each do |verb|
|
11
|
-
verb_case = BoundaryCase.new
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
verb_case = BoundaryCase.new description: "Verb check with #{verb} for #{endpoint.name}",
|
18
|
+
payload: {},
|
19
|
+
headers: headers
|
20
|
+
method = ApiTester::Method.new verb: verb,
|
21
|
+
response: ApiTester::Response.new,
|
22
|
+
request: ApiTester::Request.new
|
23
|
+
response = endpoint.call base_url: contract.base_url,
|
24
|
+
method: method,
|
25
|
+
payload: verb_case.payload,
|
26
|
+
headers: verb_case.headers
|
27
|
+
test = VerbClass.new response: response,
|
28
|
+
payload: verb_case.payload,
|
29
|
+
expected_response: endpoint.not_allowed_response,
|
30
|
+
url: endpoint.url,
|
31
|
+
verb: verb
|
15
32
|
reports.concat test.check
|
16
33
|
end
|
17
34
|
end
|
@@ -19,14 +36,24 @@ module ApiTester
|
|
19
36
|
reports
|
20
37
|
end
|
21
38
|
|
39
|
+
def self.supported_verbs
|
40
|
+
ApiTester::SupportedVerbs.all
|
41
|
+
end
|
42
|
+
|
22
43
|
def self.order
|
23
44
|
3
|
24
45
|
end
|
25
46
|
end
|
26
47
|
|
48
|
+
# Test template used for module
|
27
49
|
class VerbClass < MethodCaseTest
|
28
|
-
|
29
|
-
|
30
|
-
|
50
|
+
def initialize(response:, payload:, expected_response:, url:, verb:)
|
51
|
+
super response: response,
|
52
|
+
payload: payload,
|
53
|
+
expected_response: expected_response,
|
54
|
+
url: url,
|
55
|
+
verb: verb,
|
56
|
+
module_name: 'VerbModule'
|
57
|
+
end
|
31
58
|
end
|
32
59
|
end
|
@@ -1,21 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'api-tester/reporter/status_code_report'
|
2
4
|
require 'api-tester/method_case_test'
|
3
5
|
|
4
6
|
module ApiTester
|
5
|
-
|
6
|
-
|
7
|
+
# Checks the format constraints defined in contract
|
8
|
+
module Format
|
9
|
+
def self.go(contract)
|
7
10
|
reports = []
|
8
11
|
contract.endpoints.each do |endpoint|
|
9
12
|
endpoint.methods.each do |method|
|
10
13
|
cases = method.request.cases
|
11
14
|
cases.each do |format_case|
|
12
|
-
response = endpoint.call
|
13
|
-
|
15
|
+
response = endpoint.call base_url: contract.base_url,
|
16
|
+
method: method,
|
17
|
+
payload: format_case.payload,
|
18
|
+
headers: format_case.headers
|
19
|
+
test = FormatTest.new response: response,
|
20
|
+
payload: format_case.payload,
|
21
|
+
expected_response: endpoint.bad_request_response,
|
22
|
+
url: endpoint.url,
|
23
|
+
verb: method.verb
|
14
24
|
reports.concat test.check
|
15
25
|
end
|
16
26
|
end
|
17
27
|
end
|
18
|
-
|
19
28
|
reports
|
20
29
|
end
|
21
30
|
|
@@ -24,9 +33,15 @@ module ApiTester
|
|
24
33
|
end
|
25
34
|
end
|
26
35
|
|
36
|
+
# Test layout used by Format module
|
27
37
|
class FormatTest < MethodCaseTest
|
28
|
-
|
29
|
-
|
30
|
-
|
38
|
+
def initialize(response:, payload:, expected_response:, url:, verb:)
|
39
|
+
super response: response,
|
40
|
+
payload: payload,
|
41
|
+
expected_response: expected_response,
|
42
|
+
url: url,
|
43
|
+
verb: verb,
|
44
|
+
module_name: 'FormatModule'
|
45
|
+
end
|
31
46
|
end
|
32
47
|
end
|