api_mini_tester 0.1.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ab778aea0e70140ad7987422ea3cc84423ca3c83
4
+ data.tar.gz: 482db1276239fca74afb2b54a490e464f1529ccb
5
+ SHA512:
6
+ metadata.gz: f75c1d2e8af06c2629da0c2e52f8b63f154871df0c3a0fb950e03dd2adf8f485f99161cbeb22f385d7869c5460341893a3f65ed366c9f217b1ecf4a8c3bf7bae
7
+ data.tar.gz: d72335d77cab38d7f09a0171914b2a56323a59ae057c9ef2acac8a38ae9c5b6a1b176aa0de9889d675988eeceb4c9bbe099d2258b49a8cd2eaad04bf0dcbcb09
@@ -0,0 +1,6 @@
1
+ module ApiMiniTester
2
+ end
3
+
4
+ require 'api_mini_tester/test_step'
5
+ require 'api_mini_tester/test_scenario'
6
+ require 'api_mini_tester/test_suite'
@@ -0,0 +1,209 @@
1
+ require 'builder'
2
+ require 'socket'
3
+
4
+ class TestFormatter
5
+
6
+ RESULT_SECTIONS = %i[status headers body timing].freeze
7
+ SECTION_TRANSLATE = {
8
+ status: "Status",
9
+ headers: "Headers",
10
+ body: "Body",
11
+ timing: "Timing"
12
+ }.freeze
13
+
14
+ attr_accessor :results
15
+
16
+ def initialize(results)
17
+ @results = results
18
+ end
19
+
20
+ def to_json
21
+ clean_up_infinity.to_json
22
+ end
23
+
24
+ def to_yaml
25
+ clean_up_infinity.to_yaml
26
+ end
27
+
28
+ def to_junit_xml
29
+ xml = Builder::XmlMarkup.new(indent: 2)
30
+ xml.instruct! :xml, encoding: "UTF-8"
31
+ xml.testsuites do
32
+ results[:scenarios].each do |scenario|
33
+ xml.testsuite name: scenario[:name],
34
+ timestamp: timestamp,
35
+ hostname: hostname,
36
+ tests: tests_in_scenario(scenario),
37
+ skipped: 0,
38
+ failures: failed_in_scenario(scenario),
39
+ errors: 0,
40
+ time: time_in_scenario(scenario) do
41
+ scenario[:steps].each do |step|
42
+ classname = name_to_camelcase(step[:name])
43
+ RESULT_SECTIONS.each do |section|
44
+ step[section].each do |s|
45
+ xml.testcase classname: classname,
46
+ name: s[:name],
47
+ time: step_timing(step),
48
+ file: "./#{classname}.rb" do
49
+ s[:result] ? nil : xml.failure(message: s[:desc])
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ def timestamp
60
+ Time.now.strftime("%FT%T%:z")
61
+ end
62
+
63
+ def scenarios_count
64
+ results[:scenarios].size
65
+ end
66
+
67
+ def steps_count(scenario)
68
+ scenario[:steps].size
69
+ end
70
+
71
+ def test_count(step)
72
+ count = 0
73
+ [:status, :headers, :body, :timing].each do |section|
74
+ count += step[section].size
75
+ end
76
+ count
77
+ end
78
+
79
+ def tests_in_scenario(scenario)
80
+ count = 0
81
+ scenario[:steps].each do |step|
82
+ count += test_count(step)
83
+ end
84
+ count
85
+ end
86
+
87
+ def time_in_scenario(scenario)
88
+ time = 0.0
89
+ scenario[:steps].each do |step|
90
+ time += step[:timing].first[:real]
91
+ end
92
+ time
93
+ end
94
+
95
+ def failed_in_scenario(scenario)
96
+ count = 0
97
+ scenario[:steps].each do |step|
98
+ [:status, :headers, :body, :timing].each do |section|
99
+ count += step[section].map { |res| res[:result] }.select(&:!).size
100
+ end
101
+ end
102
+ count
103
+ end
104
+
105
+ def hostname
106
+ Socket.gethostname
107
+ end
108
+
109
+ def name_to_camelcase(name)
110
+ name.gsub(/[[:space:]]+/, '_').downcase.gsub(/(?:^|_)([a-z])/) { $1.upcase }
111
+ end
112
+
113
+ def step_timing(step)
114
+ step[:timing].first ? step[:timing].first[:real] : 0
115
+ end
116
+
117
+ def clean_up_infinity
118
+ res = results.dup
119
+ res[:scenarios].each do |scenario|
120
+ scenario[:steps].each do |step|
121
+ step[:timing].each do |timing|
122
+ timing[:exp] = "Not Specified" if timing.is_a?(Hash) && timing[:exp] && timing[:exp] == Float::INFINITY
123
+ end
124
+ end
125
+ end
126
+ res
127
+ end
128
+
129
+ def array_in(array)
130
+ list = ''
131
+ array.each do |item|
132
+ if item.instance_of?(Array)
133
+ list << array_in(item)
134
+ elsif item.instance_of?(Hash)
135
+ list << hash_in(item)
136
+ end
137
+ end
138
+ list
139
+ end
140
+
141
+ def hash_in(hash)
142
+ list = ''
143
+ hash.each do |k, v|
144
+ if v.instance_of?(Hash)
145
+ list << hash_in(v)
146
+ elsif v.instance_of?(Array)
147
+ list << array_in(v)
148
+ elsif k == :result
149
+ list << (v ? '.' : 'E')
150
+ end
151
+ end
152
+ list
153
+ end
154
+
155
+ def to_simple
156
+ hash_in results
157
+ end
158
+
159
+ def md_section_header(header, desc, level)
160
+ output = []
161
+ output << "#{'#' * level} #{header}"
162
+ output << ""
163
+ if desc
164
+ output << "Desc: #{desc}"
165
+ output << ""
166
+ end
167
+ output
168
+ end
169
+
170
+ def md_step_header(step)
171
+ output = []
172
+ output.push(*md_section_header(step[:name], step[:desc], 3))
173
+ output.push(*md_section_header("Call", nil, 4))
174
+ step[:url].each do |url|
175
+ output << "* #{url[:desc]}"
176
+ end
177
+ step[:method].each do |method|
178
+ output << "* #{method[:desc]}"
179
+ end
180
+ output << ""
181
+ output
182
+ end
183
+
184
+ def md_section_content(step, section)
185
+ output = []
186
+ output << md_section_header(SECTION_TRANSLATE[section], nil, 4)
187
+ step[section].each do |status|
188
+ output << "* `#{status[:result]}`: #{status[:desc]}"
189
+ end
190
+ output << ""
191
+ output
192
+ end
193
+
194
+ def to_markdown
195
+ output = []
196
+ output << md_section_header(results[:name], results[:desc], 1)
197
+ results[:scenarios].each do |scenario|
198
+ output << md_section_header(scenario[:name], scenario[:desc], 2)
199
+ scenario[:steps].each do |step|
200
+ output.push(*md_step_header(step))
201
+ RESULT_SECTIONS.each do |section|
202
+ output.push(*md_section_content(step, section))
203
+ end
204
+ end
205
+ end
206
+ output.join("\n")
207
+ end
208
+
209
+ end
@@ -0,0 +1,44 @@
1
+ require_relative 'test_step'
2
+
3
+ module ApiMiniTester
4
+ class TestScenario
5
+
6
+ attr_accessor :base_uri, :scenario, :data, :results, :name
7
+
8
+ def initialize(base_uri, scenario, data)
9
+ @base_uri = base_uri
10
+ @scenario = scenario
11
+ @data = data
12
+ @name = scenario['name']
13
+ @results = {name: scenario['name'], desc: scenario['desc'], steps: []}
14
+ end
15
+
16
+ def valid?
17
+ return false if scenario.nil? || scenario['steps'].nil?
18
+ return false unless scenario['steps'].is_a?(Array) || scenario['steps'].empty?
19
+ return false if name.nil? || name.empty?
20
+ return false if base_uri.nil? || base_uri.empty?
21
+ true
22
+ end
23
+
24
+ def add_result(result)
25
+ @results.steps << result
26
+ end
27
+
28
+ def print_results
29
+ @results.each do |line|
30
+ puts line
31
+ end
32
+ end
33
+
34
+ def run_scenario
35
+ @context = []
36
+ scenario['steps'].each do |step|
37
+ step = TestStep.new(base_uri, step, @context, data)
38
+ step_result, context = step.run_step
39
+ @results[:steps] << step_result
40
+ @context << context
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,199 @@
1
+ require 'httparty'
2
+ require 'liquid'
3
+ require 'hash_parser'
4
+ require 'uri'
5
+ require 'faker'
6
+ require 'json'
7
+
8
+ module ApiMiniTester
9
+ class TestStep
10
+
11
+ include HTTParty
12
+
13
+ SUPPORTED_METHODS = %i[ get post put delete ].freeze
14
+
15
+ attr_accessor :uri, :method, :name, :input, :output
16
+ attr_reader :results
17
+
18
+ def initialize(base_uri, step, context = nil, data = nil)
19
+ @context = context
20
+ uri_template = Liquid::Template.parse([base_uri, step['uri']].join("/"), error_mode: :strict)
21
+ @name = step['name']
22
+ @uri = uri_template.render({'context' => context, 'data' => data}, { strict_variables: true })
23
+ @method = step['method'].downcase.to_sym
24
+
25
+ input_template = Liquid::Template.parse(step['input'].to_yaml.to_s, error_mode: :strict)
26
+ @input = YAML.load(input_template.render({'context' => context, 'data' => data}, { strict_variables: true }))
27
+
28
+ output_template = Liquid::Template.parse(step['output'].to_yaml.to_s, error_mode: :strict)
29
+ @output = YAML.load(output_template.render({'context' => context, 'data' => data}, { strict_variables: true }))
30
+
31
+ @results = { name: step['name'], desc: step['desc'], status: [], headers: [], body: [], url: [], method: [], timing: [] }
32
+ end
33
+
34
+ def valid?
35
+ return false if uri.nil? || uri.empty?
36
+ return false unless URI.parse(uri) rescue false
37
+ return false unless SUPPORTED_METHODS.include? method
38
+ return false if @name.nil? || @name.empty?
39
+ true
40
+ end
41
+
42
+ def content_type
43
+ @input['content_type'] || 'application/json'
44
+ end
45
+
46
+ def headers
47
+ @input['header']['Content-type'] = content_type if content_type == 'application/json'
48
+ @input['header']
49
+ end
50
+
51
+ def body
52
+ case content_type
53
+ when 'application/x-www-form-urlencoded'
54
+ body_to_form_data
55
+ when 'multipart/form-data'
56
+ body_to_form_data
57
+ else
58
+ @input["body"].to_json
59
+ end
60
+ end
61
+
62
+ def body_to_form_data
63
+ body = {}
64
+ @input["body"].each do |item|
65
+ body[item['name']] = item['value'] if item['type'] == 'input'
66
+ body[item['name']] = File.open(item['value'], 'r') if item['type'] == 'file'
67
+ end
68
+ body
69
+ end
70
+
71
+ def test_headers
72
+ @output['header']
73
+ end
74
+
75
+ def test_body
76
+ @output['body']
77
+ end
78
+
79
+ def test_status
80
+ @output['status']
81
+ end
82
+
83
+ def test_timing
84
+ @output['timing']
85
+ end
86
+
87
+ def run_step
88
+ @timing = Time.now
89
+ case method
90
+ when :get
91
+ response = HTTParty.get(uri, headers: headers)
92
+ when :post
93
+ response = HTTParty.post(uri, headers: headers, body: body)
94
+ when :put
95
+ response = HTTParty.put(uri, headers: headers, body: body)
96
+ when :delete
97
+ response = HTTParty.delete(uri, headers: headers)
98
+ end
99
+ @timing = Time.now - @timing
100
+
101
+ add_result :url, { result: true, desc: "Url: #{uri}" }
102
+ add_result :method, { result: true, desc: "Method: #{method}" }
103
+
104
+ assert_status(response.code, test_status)
105
+ assert_headers(response.headers, test_headers)
106
+ assert_body(response.parsed_response, test_body)
107
+ assert_timing(@timing, test_timing)
108
+
109
+ [ results, response ]
110
+ end
111
+
112
+ def print_results
113
+ @results.each do |line|
114
+ puts line
115
+ end
116
+ end
117
+
118
+ def add_result(section, result)
119
+ @results[section] << result
120
+ end
121
+
122
+ def assert_timing(runtime, limit = nil)
123
+ limit ||= Float::INFINITY
124
+ add_result :timing, { result: (runtime < limit),
125
+ name: "Request time < #{limit}",
126
+ desc: "Expected request time #{limit}, real time #{runtime}",
127
+ exp: limit, real: runtime }
128
+ end
129
+
130
+ def assert_status(response, output)
131
+ add_result :status, { result: (response == output),
132
+ name: "Response code == #{output}",
133
+ desc: "Expected response #{output}, got response #{response}",
134
+ exp: output, real: response }
135
+ end
136
+
137
+ def assert_headers(response, output)
138
+ return if output.nil?
139
+ output.each do |k, v|
140
+ add_result :headers, { result: (v == response[k]),
141
+ name: "Header value: #{k} == #{v}",
142
+ desc: "Header #{k} expected: #{v}, got #{response[k]}",
143
+ exp: v, real: response[k] }
144
+ end
145
+ end
146
+
147
+ def assert_body(response, output)
148
+ if output.instance_of?(Hash)
149
+ hash_diff(output, response)
150
+ elsif output.instance_of?(Array)
151
+ array_diff(output, response)
152
+ end
153
+ end
154
+
155
+ def array_diff(a, b, path = nil, section = :body)
156
+ a.each do |a_item|
157
+ if a_item.instance_of?(Hash)
158
+ found = false
159
+ b.each do |b_item|
160
+ matching = true
161
+ a_item.each_key do |k, v|
162
+ matching = (b_item[k] == a_item[k]) if matching
163
+ end
164
+ found = true if matching
165
+ end
166
+ add_result section, { result: found,
167
+ name: "Response body value: #{[path].join(".")}",
168
+ desc: "Assert #{[path].join(".")} #{found ? 'contains' : 'does not contains'} #{a_item}" }
169
+ elsif a_item.instance_of?(Array)
170
+ # TODO: Add support for array of array it isn't so needed to compate so deep structures
171
+ else
172
+ add_result section, { result: b.include?(a_item),
173
+ name: "Response boby value: #{[path].join(".")}",
174
+ desc: "Assert #{[path].join(".")} #{b.include?(a_item) ? 'contains' : 'does not contains'} #{a_item}" }
175
+ end
176
+ end
177
+ end
178
+
179
+ def hash_diff(a, b, path = nil, section = :body)
180
+ return nil if a.nil? || b.nil?
181
+ a.each_key do |k, v|
182
+ current_path = [path, k].join('.')
183
+ if b[k].nil?
184
+ add_result section, { result: false,
185
+ name: "Reponse value: #{[path, k].join(".")}",
186
+ desc: "Missing #{current_path}" }
187
+ elsif v.instance_of?(Hash)
188
+ hash_diff(a[k], b[k], current_path, section)
189
+ elsif v.instance_of?(Array)
190
+ array_diff(a[k], b[k], current_path, section)
191
+ else
192
+ add_result section, { result: (a[k] == b[k]),
193
+ name: "Reponse body value: #{[path, k].join(".")}",
194
+ desc: "Assert #{[path, k].join(".")}: #{a[k]} #{a[k] == b[k] ? '==' : '!='} #{b[k]}" }
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,47 @@
1
+ require 'yaml'
2
+ require_relative 'test_scenario'
3
+ require_relative 'test_formatter'
4
+
5
+ module ApiMiniTester
6
+ class TestSuite
7
+
8
+ attr_accessor :base_uri, :scenarios, :data, :results
9
+
10
+ def initialize(suite_def)
11
+ if suite_def.is_a?(String)
12
+ @test = YAML.load(File.open(suite_def))
13
+ elsif suite_def.is_a?(Hash)
14
+ @test = suite_def
15
+ end
16
+ setup
17
+ end
18
+
19
+ def valid?
20
+ return false if base_uri.nil? || base_uri.empty?
21
+ return false if scenarios.nil? || scenarios.empty?
22
+ true
23
+ end
24
+
25
+ def setup
26
+ @base_uri = @test['settings']['baseurl']
27
+ @scenarios = @test['tests']
28
+ @data = @test['data']
29
+ @results = {name: @test['name'], desc: @test['desc'], scenarios: []}
30
+ end
31
+
32
+ def run_scenarios
33
+ scenarios.each do |scenario|
34
+ runner = TestScenario.new(base_uri, scenario, data)
35
+ runner.run_scenario
36
+ @results[:scenarios] << runner.results
37
+ end
38
+ @results
39
+ end
40
+
41
+ def print_results(format)
42
+ formatter = TestFormatter.new(results)
43
+ formatter.send("to_#{format}")
44
+ end
45
+
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,268 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: api_mini_tester
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Jindrich Skupa (@eMan)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-09-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: builder
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.4
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.0.4
33
+ - !ruby/object:Gem::Dependency
34
+ name: faker
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.8'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.8.7
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.8'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.8.7
53
+ - !ruby/object:Gem::Dependency
54
+ name: hash_parser
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.0'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 0.0.2
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.0'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 0.0.2
73
+ - !ruby/object:Gem::Dependency
74
+ name: httparty
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '0.16'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.16.0
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.16'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 0.16.0
93
+ - !ruby/object:Gem::Dependency
94
+ name: liquid
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '4.0'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 4.0.0
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '4.0'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 4.0.0
113
+ - !ruby/object:Gem::Dependency
114
+ name: minitest
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '5.11'
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 5.11.3
123
+ type: :development
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '5.11'
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 5.11.3
133
+ - !ruby/object:Gem::Dependency
134
+ name: minitest-reporters-json_reporter
135
+ requirement: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '1.0'
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: 1.0.0
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: '1.0'
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: 1.0.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: nexus
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.4'
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: 1.4.0
163
+ type: :development
164
+ prerelease: false
165
+ version_requirements: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - "~>"
168
+ - !ruby/object:Gem::Version
169
+ version: '1.4'
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: 1.4.0
173
+ - !ruby/object:Gem::Dependency
174
+ name: rubocop
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '0.58'
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: 0.58.2
183
+ type: :development
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '0.58'
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: 0.58.2
193
+ - !ruby/object:Gem::Dependency
194
+ name: simplecov
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: '0.16'
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: 0.16.1
203
+ type: :development
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - "~>"
208
+ - !ruby/object:Gem::Version
209
+ version: '0.16'
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: 0.16.1
213
+ - !ruby/object:Gem::Dependency
214
+ name: webmock
215
+ requirement: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - "~>"
218
+ - !ruby/object:Gem::Version
219
+ version: '3.4'
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: 3.4.2
223
+ type: :development
224
+ prerelease: false
225
+ version_requirements: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - "~>"
228
+ - !ruby/object:Gem::Version
229
+ version: '3.4'
230
+ - - ">="
231
+ - !ruby/object:Gem::Version
232
+ version: 3.4.2
233
+ description: Runs automated REST API based on YAML definiti
234
+ email: jindrich.skupa@gmail.com
235
+ executables: []
236
+ extensions: []
237
+ extra_rdoc_files: []
238
+ files:
239
+ - lib/api_mini_tester.rb
240
+ - lib/api_mini_tester/test_formatter.rb
241
+ - lib/api_mini_tester/test_scenario.rb
242
+ - lib/api_mini_tester/test_step.rb
243
+ - lib/api_mini_tester/test_suite.rb
244
+ homepage: http://rubygems.org/gems/api_mini_tester
245
+ licenses:
246
+ - MIT
247
+ metadata: {}
248
+ post_install_message:
249
+ rdoc_options: []
250
+ require_paths:
251
+ - lib
252
+ required_ruby_version: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - ">="
255
+ - !ruby/object:Gem::Version
256
+ version: '0'
257
+ required_rubygems_version: !ruby/object:Gem::Requirement
258
+ requirements:
259
+ - - ">="
260
+ - !ruby/object:Gem::Version
261
+ version: '0'
262
+ requirements: []
263
+ rubyforge_project:
264
+ rubygems_version: 2.6.8
265
+ signing_key:
266
+ specification_version: 4
267
+ summary: Runs automated REST API based on YAML definition
268
+ test_files: []