rspec-rails-api 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -5
- data/.gitlab-ci.yml +1 -1
- data/.rubocop.yml +5 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +98 -0
- data/README.md +3 -3
- data/lib/rspec/rails/api/dsl/example.rb +3 -5
- data/lib/rspec/rails/api/dsl/example_group.rb +1 -1
- data/lib/rspec/rails/api/entity_config.rb +5 -8
- data/lib/rspec/rails/api/field_config.rb +2 -2
- data/lib/rspec/rails/api/matchers.rb +22 -27
- data/lib/rspec/rails/api/metadata.rb +27 -19
- data/lib/rspec/rails/api/open_api_renderer.rb +24 -13
- data/lib/rspec/rails/api/utils.rb +28 -129
- data/lib/rspec/rails/api/validator.rb +211 -0
- data/lib/rspec/rails/api/version.rb +1 -1
- data/lib/rspec_rails_api.rb +0 -4
- data/rspec-rails-api.gemspec +4 -1
- metadata +49 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 232e1ea8b43dd1e3b5258f0029d28a54d886156634e87d4a6854a3543752fb0f
|
4
|
+
data.tar.gz: 71828ab75d08ff900cbe9f018af219bc79b98231118712d127e35c274690d7ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbb37718158f52e0a2056bbe9b8ccde44782cafe915cc146f05333532484b10ae8260e7abbd3f571e657c778b8d8ac37c731adfa452d3e94af253dcf6849aede
|
7
|
+
data.tar.gz: 731f623490f7e15b3f0acb8851955835083249b60e62f722ab9870c6658d3e690ed0b6aca8ac4edcdc3f6b1c892517511937d190459b8020fcb2b3c2ef99047a
|
data/.gitignore
CHANGED
data/.gitlab-ci.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
---
|
2
2
|
require:
|
3
3
|
- rubocop-performance
|
4
|
+
- rubocop-rake
|
5
|
+
- rubocop-rspec
|
4
6
|
|
5
7
|
AllCops:
|
6
|
-
TargetRubyVersion: 2.
|
8
|
+
TargetRubyVersion: 2.7
|
7
9
|
Exclude:
|
8
10
|
- dummy/**/*
|
9
11
|
- vendor/bundle/**/*
|
@@ -33,3 +35,5 @@ Style/TrailingCommaInArrayLiteral:
|
|
33
35
|
Style/TrailingCommaInHashLiteral:
|
34
36
|
EnforcedStyleForMultiline: comma
|
35
37
|
|
38
|
+
RSpec/NestedGroups:
|
39
|
+
Max: 4
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.7.0
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file.
|
|
3
3
|
|
4
4
|
## Not released
|
5
5
|
|
6
|
+
## 0.5.0 - 2023-01-02
|
7
|
+
|
8
|
+
- Improved error messages
|
9
|
+
- Improved usage of primitive types: use `:string` instead of `:type_string`, and more generally, remove the `type_`
|
10
|
+
prefix
|
11
|
+
- Fixed an error when an object is defined with an attribute named `type`.
|
12
|
+
|
13
|
+
## 0.4.0 - 2021-12-19
|
14
|
+
|
6
15
|
- All parameters attributes are considered required unless specified
|
7
16
|
- Fix object `attributes` key in spec and documentation.
|
8
17
|
When defining object attributes, documentation and tests used `properties` key
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rspec-rails-api (0.5.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activesupport (6.1.7)
|
10
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
+
i18n (>= 1.6, < 2)
|
12
|
+
minitest (>= 5.1)
|
13
|
+
tzinfo (~> 2.0)
|
14
|
+
zeitwerk (~> 2.3)
|
15
|
+
ast (2.4.2)
|
16
|
+
byebug (11.1.3)
|
17
|
+
concurrent-ruby (1.1.10)
|
18
|
+
diff-lcs (1.5.0)
|
19
|
+
docile (1.4.0)
|
20
|
+
i18n (1.12.0)
|
21
|
+
concurrent-ruby (~> 1.0)
|
22
|
+
json (2.6.3)
|
23
|
+
minitest (5.16.3)
|
24
|
+
parallel (1.22.1)
|
25
|
+
parser (3.1.3.0)
|
26
|
+
ast (~> 2.4.1)
|
27
|
+
rack (3.0.3)
|
28
|
+
rainbow (3.1.1)
|
29
|
+
rake (10.5.0)
|
30
|
+
regexp_parser (2.6.1)
|
31
|
+
rexml (3.2.5)
|
32
|
+
rspec (3.12.0)
|
33
|
+
rspec-core (~> 3.12.0)
|
34
|
+
rspec-expectations (~> 3.12.0)
|
35
|
+
rspec-mocks (~> 3.12.0)
|
36
|
+
rspec-core (3.12.0)
|
37
|
+
rspec-support (~> 3.12.0)
|
38
|
+
rspec-expectations (3.12.1)
|
39
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
40
|
+
rspec-support (~> 3.12.0)
|
41
|
+
rspec-mocks (3.12.1)
|
42
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
43
|
+
rspec-support (~> 3.12.0)
|
44
|
+
rspec-support (3.12.0)
|
45
|
+
rubocop (1.41.1)
|
46
|
+
json (~> 2.3)
|
47
|
+
parallel (~> 1.10)
|
48
|
+
parser (>= 3.1.2.1)
|
49
|
+
rainbow (>= 2.2.2, < 4.0)
|
50
|
+
regexp_parser (>= 1.8, < 3.0)
|
51
|
+
rexml (>= 3.2.5, < 4.0)
|
52
|
+
rubocop-ast (>= 1.23.0, < 2.0)
|
53
|
+
ruby-progressbar (~> 1.7)
|
54
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
55
|
+
rubocop-ast (1.24.1)
|
56
|
+
parser (>= 3.1.1.0)
|
57
|
+
rubocop-performance (1.15.2)
|
58
|
+
rubocop (>= 1.7.0, < 2.0)
|
59
|
+
rubocop-ast (>= 0.4.0)
|
60
|
+
rubocop-rake (0.6.0)
|
61
|
+
rubocop (~> 1.0)
|
62
|
+
rubocop-rspec (2.16.0)
|
63
|
+
rubocop (~> 1.33)
|
64
|
+
ruby-progressbar (1.11.0)
|
65
|
+
simplecov (0.22.0)
|
66
|
+
docile (~> 1.1)
|
67
|
+
simplecov-html (~> 0.11)
|
68
|
+
simplecov_json_formatter (~> 0.1)
|
69
|
+
simplecov-html (0.12.3)
|
70
|
+
simplecov_json_formatter (0.1.4)
|
71
|
+
tzinfo (2.0.5)
|
72
|
+
concurrent-ruby (~> 1.0)
|
73
|
+
unicode-display_width (2.3.0)
|
74
|
+
webrick (1.7.0)
|
75
|
+
yard (0.9.28)
|
76
|
+
webrick (~> 1.7.0)
|
77
|
+
zeitwerk (2.6.6)
|
78
|
+
|
79
|
+
PLATFORMS
|
80
|
+
x86_64-linux
|
81
|
+
|
82
|
+
DEPENDENCIES
|
83
|
+
activesupport (~> 6.0)
|
84
|
+
bundler
|
85
|
+
byebug
|
86
|
+
rack
|
87
|
+
rake (~> 10.0)
|
88
|
+
rspec (~> 3.0)
|
89
|
+
rspec-rails-api!
|
90
|
+
rubocop
|
91
|
+
rubocop-performance
|
92
|
+
rubocop-rake
|
93
|
+
rubocop-rspec
|
94
|
+
simplecov
|
95
|
+
yard
|
96
|
+
|
97
|
+
BUNDLED WITH
|
98
|
+
2.4.1
|
data/README.md
CHANGED
@@ -263,12 +263,12 @@ inline.
|
|
263
263
|
Both `:of` and `attributes` may be a hash of fields or a symbol. If they
|
264
264
|
are omitted, they will be documented, but responses won't be validated.
|
265
265
|
|
266
|
-
Arrays of primitives are supported;
|
267
|
-
|
266
|
+
Arrays of primitives are supported; refer to the [documentation](https://swagger.io/specification/#data-types) for the
|
267
|
+
list. Usage:
|
268
268
|
|
269
269
|
```rb
|
270
270
|
entity :user,
|
271
|
-
|
271
|
+
favorite_numbers: { type: :array, of: :int32 }
|
272
272
|
```
|
273
273
|
|
274
274
|
Check `lib/rspec_rails_api.rb` for the full list.
|
@@ -44,17 +44,15 @@ module RSpec
|
|
44
44
|
#
|
45
45
|
# @return [RSpec::Rails::Api::EntityConfig, Hash] Defined entity
|
46
46
|
def defined(entity)
|
47
|
-
return { type: entity
|
47
|
+
return { type: entity } if PRIMITIVES.include? entity
|
48
48
|
|
49
49
|
current_resource = rra_metadata.current_resource
|
50
50
|
raise '@current_resource is unset' unless current_resource
|
51
51
|
|
52
52
|
entities = rra_metadata.resources[current_resource][:entities]
|
53
|
+
raise "Unknown entity '#{entity}' in resource '#{current_resource}'" unless entities.key? entity.to_sym
|
53
54
|
|
54
|
-
|
55
|
-
raise "Unknown entity '#{entity}' in resource '#{current_resource}'" unless out
|
56
|
-
|
57
|
-
out.expand_with(entities)
|
55
|
+
entities[entity.to_sym].expand_with(entities)
|
58
56
|
end
|
59
57
|
|
60
58
|
##
|
@@ -186,7 +186,7 @@ module RSpec
|
|
186
186
|
#
|
187
187
|
# @return [void]
|
188
188
|
def execute_for_code_block(callback_block)
|
189
|
-
example 'Test and create documentation', caller: callback_block.send(:caller) do
|
189
|
+
example 'Test response and create documentation', caller: callback_block.send(:caller) do
|
190
190
|
instance_eval(&callback_block) if callback_block
|
191
191
|
end
|
192
192
|
end
|
@@ -55,15 +55,12 @@ module RSpec
|
|
55
55
|
# @param attribute [Symbol] Attribute name
|
56
56
|
# @param entities [Hash] List of entities
|
57
57
|
def expand_attribute(attribute, entities)
|
58
|
-
|
59
|
-
|
60
|
-
{ type: attribute.to_s.split('_').last.to_sym }
|
61
|
-
else
|
62
|
-
# Defined attribute
|
63
|
-
raise "Entity #{attribute} not found for entity completion." unless entities[attribute]
|
58
|
+
# Primitives support
|
59
|
+
return { type: attribute } if PRIMITIVES.include? attribute
|
64
60
|
|
65
|
-
|
66
|
-
|
61
|
+
raise "Entity #{attribute} not found for entity completion." unless entities[attribute]
|
62
|
+
|
63
|
+
entities[attribute].expand_with(entities)
|
67
64
|
end
|
68
65
|
end
|
69
66
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rspec/rails/api/entity_config'
|
4
|
-
require 'rspec/rails/api/
|
4
|
+
require 'rspec/rails/api/validator'
|
5
5
|
|
6
6
|
module RSpec
|
7
7
|
module Rails
|
@@ -14,7 +14,7 @@ module RSpec
|
|
14
14
|
def initialize(type:, description:, required: true, attributes: nil, of: nil)
|
15
15
|
@required = required
|
16
16
|
@description = description
|
17
|
-
raise "Field type not allowed: '#{type}'" unless
|
17
|
+
raise "Field type not allowed: '#{type}'" unless Validator.valid_type?(type)
|
18
18
|
|
19
19
|
define_attributes attributes if type == :object
|
20
20
|
define_attributes of if type == :array
|
@@ -1,53 +1,48 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'active_support/hash_with_indifferent_access'
|
4
|
+
require 'yaml'
|
4
5
|
|
6
|
+
require 'rspec/rails/api/validator'
|
5
7
|
require 'rspec/rails/api/utils'
|
6
8
|
|
7
9
|
##
|
8
10
|
# RSpec matcher to check something against an array of `expected`
|
9
|
-
#
|
10
|
-
# FIXME: Split the matcher in something else; it's too messy.
|
11
11
|
RSpec::Matchers.define :have_many do |expected|
|
12
12
|
match do |actual|
|
13
|
-
|
14
|
-
@actual = JSON.parse(actual.body) if actual.respond_to? :body
|
13
|
+
actual = RSpec::Rails::Api::Utils.hash_from_response actual
|
15
14
|
|
16
|
-
raise "Response is not an array: #{
|
17
|
-
raise 'Response has no item to compare with' unless
|
15
|
+
raise "Response is not an array: #{actual.class}" unless actual.is_a? Array
|
16
|
+
raise 'Response has no item to compare with' unless actual.count.positive?
|
18
17
|
|
19
|
-
|
20
|
-
if expected[:type].is_a?(Symbol)
|
21
|
-
@actual.each do |item|
|
22
|
-
return false unless RSpec::Rails::Api::Utils.check_value_type(expected[:type], item)
|
23
|
-
end
|
18
|
+
@errors = RSpec::Rails::Api::Validator.validate_array actual, expected
|
24
19
|
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
# Check every entry
|
29
|
-
@actual.each do |item|
|
30
|
-
return false unless RSpec::Rails::Api::Utils.validate_object_structure item, expected
|
31
|
-
end
|
32
|
-
|
33
|
-
true
|
20
|
+
@errors.blank?
|
34
21
|
end
|
35
22
|
|
36
|
-
|
23
|
+
failure_message do |actual|
|
24
|
+
object = RSpec::Rails::Api::Utils.hash_from_response(actual).to_json.chomp
|
25
|
+
RSpec::Rails::Api::Validator.format_failure_message @errors, object
|
26
|
+
end
|
37
27
|
end
|
38
28
|
|
39
29
|
##
|
40
30
|
# RSpec matcher to check something against the `expected` definition
|
41
|
-
# FIXME: Split the matcher in something else; it's too messy.
|
42
31
|
RSpec::Matchers.define :have_one do |expected|
|
43
32
|
match do |actual|
|
44
|
-
|
45
|
-
@actual = JSON.parse(actual.body) if actual.respond_to? :body
|
33
|
+
actual = RSpec::Rails::Api::Utils.hash_from_response actual
|
46
34
|
|
47
|
-
|
35
|
+
@errors = if expected.keys.count == 1 && expected.key?(:type)
|
36
|
+
RSpec::Rails::Api::Validator.validate_type actual, expected[:type]
|
37
|
+
else
|
38
|
+
RSpec::Rails::Api::Validator.validate_object actual, expected
|
39
|
+
end
|
48
40
|
|
49
|
-
|
41
|
+
@errors.blank?
|
50
42
|
end
|
51
43
|
|
52
|
-
|
44
|
+
failure_message do |actual|
|
45
|
+
object = RSpec::Rails::Api::Utils.hash_from_response(actual).to_json.chomp
|
46
|
+
RSpec::Rails::Api::Validator.format_failure_message @errors, object
|
47
|
+
end
|
53
48
|
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rspec/rails/api/utils'
|
4
|
+
require 'rspec/rails/api/validator'
|
4
5
|
require 'rspec/rails/api/open_api_renderer'
|
5
6
|
require 'rspec/rails/api/entity_config'
|
6
7
|
|
7
8
|
module RSpec
|
8
9
|
module Rails
|
9
10
|
module Api
|
10
|
-
# Handles contexts and examples
|
11
|
+
# Handles contexts and examples metadata.
|
11
12
|
class Metadata # rubocop:disable Metrics/ClassLength
|
12
13
|
attr_reader :entities, :resources, :parameters, :current_resource, :current_url, :current_method, :current_code
|
13
14
|
|
@@ -30,7 +31,7 @@ module RSpec
|
|
30
31
|
#
|
31
32
|
# @return [void]
|
32
33
|
def add_resource(name, description)
|
33
|
-
@resources[name.to_sym] = { description: description, paths: {} }
|
34
|
+
@resources[name.to_sym] = { description: description, paths: {}, entities: {} }
|
34
35
|
@current_resource = name.to_sym
|
35
36
|
end
|
36
37
|
|
@@ -44,7 +45,7 @@ module RSpec
|
|
44
45
|
# @return [void]
|
45
46
|
def add_entity(name, fields)
|
46
47
|
Utils.deep_set(@resources,
|
47
|
-
|
48
|
+
[@current_resource, 'entities', name],
|
48
49
|
EntityConfig.new(fields))
|
49
50
|
end
|
50
51
|
|
@@ -76,11 +77,11 @@ module RSpec
|
|
76
77
|
chunks = @current_url.split('?')
|
77
78
|
|
78
79
|
fields.each do |name, field|
|
79
|
-
valid_attribute =
|
80
|
+
valid_attribute = Validator.valid_type?(field[:type], except: %i[array object])
|
80
81
|
raise "Field type not allowed: #{field[:type]}" unless valid_attribute
|
81
82
|
|
82
83
|
scope = path_param_scope(chunks, name)
|
83
|
-
Utils.deep_set(@resources,
|
84
|
+
Utils.deep_set(@resources, [@current_resource, 'paths', @current_url, 'path_params', name],
|
84
85
|
description: field[:description] || nil,
|
85
86
|
type: field[:type] || nil,
|
86
87
|
required: field[:required] || true,
|
@@ -109,7 +110,7 @@ module RSpec
|
|
109
110
|
|
110
111
|
params = organize_params fields
|
111
112
|
Utils.deep_set(@resources,
|
112
|
-
|
113
|
+
[@current_resource, 'paths', @current_url, 'actions', @current_method, 'params'],
|
113
114
|
params)
|
114
115
|
end
|
115
116
|
|
@@ -125,7 +126,7 @@ module RSpec
|
|
125
126
|
def add_action(method, url, summary, description = '')
|
126
127
|
check_current_context :resource
|
127
128
|
|
128
|
-
Utils.deep_set(@resources,
|
129
|
+
Utils.deep_set(@resources, [@current_resource, 'paths', url, 'actions', method],
|
129
130
|
description: description || '',
|
130
131
|
summary: summary,
|
131
132
|
statuses: {},
|
@@ -148,7 +149,7 @@ module RSpec
|
|
148
149
|
check_current_context :resource, :url, :method
|
149
150
|
|
150
151
|
Utils.deep_set(@resources,
|
151
|
-
|
152
|
+
[@current_resource, 'paths', @current_url, 'actions', @current_method, 'statuses', status_code],
|
152
153
|
description: description,
|
153
154
|
example: { response: nil })
|
154
155
|
@current_code = status_code
|
@@ -160,10 +161,13 @@ module RSpec
|
|
160
161
|
#
|
161
162
|
# @return [Hash] Current example metadata
|
162
163
|
def current_example
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
164
|
+
@resources.dig @current_resource,
|
165
|
+
:paths,
|
166
|
+
@current_url.to_sym,
|
167
|
+
:actions,
|
168
|
+
@current_method.to_sym,
|
169
|
+
:statuses,
|
170
|
+
@current_code.to_s.to_sym
|
167
171
|
end
|
168
172
|
|
169
173
|
##
|
@@ -179,7 +183,7 @@ module RSpec
|
|
179
183
|
|
180
184
|
# rubocop:disable Layout/LineLength
|
181
185
|
Utils.deep_set(@resources,
|
182
|
-
|
186
|
+
[@current_resource, 'paths', @current_url, 'actions', @current_method, 'statuses', @current_code, 'expectations'],
|
183
187
|
{
|
184
188
|
one: one,
|
185
189
|
many: many,
|
@@ -195,20 +199,20 @@ module RSpec
|
|
195
199
|
# @param action [String, nil] HTTP verb
|
196
200
|
# @param status_code [Integer, nil] Status code
|
197
201
|
# @param response [String, nil] Response body
|
198
|
-
# @param path_params [Hash, nil] Used path
|
202
|
+
# @param path_params [Hash, nil] Used path parameters
|
199
203
|
# @param params [Hash, nil] Used body parameters
|
200
204
|
#
|
201
205
|
# rubocop:disable Metrics/ParameterLists
|
202
206
|
def add_request_example(url: nil, action: nil, status_code: nil, response: nil, path_params: nil, params: nil)
|
203
207
|
resource = nil
|
204
208
|
@resources.each do |key, res|
|
205
|
-
resource = key if
|
209
|
+
resource = key if res.dig :paths, url.to_sym, :actions, action.to_sym, :statuses, status_code.to_s.to_sym
|
206
210
|
end
|
207
211
|
|
208
212
|
raise "Resource not found for #{action.upcase} #{url}" unless resource
|
209
213
|
|
210
214
|
Utils.deep_set(@resources,
|
211
|
-
|
215
|
+
[resource, 'paths', url, 'actions', action, 'statuses', status_code, 'example'],
|
212
216
|
path_params: path_params,
|
213
217
|
params: params,
|
214
218
|
response: response)
|
@@ -261,12 +265,16 @@ module RSpec
|
|
261
265
|
##
|
262
266
|
# Checks and complete a field definition
|
263
267
|
#
|
264
|
-
# @param fields [Hash] Fields definitions
|
268
|
+
# @param fields [Hash,Symbol] Fields definitions
|
265
269
|
#
|
266
|
-
# @return [Hash] Completed field definition
|
267
|
-
def organize_params(fields) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
270
|
+
# @return [Hash,Symbol] Completed field definition
|
271
|
+
def organize_params(fields) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
272
|
+
return fields if fields.is_a?(Symbol) && PRIMITIVES.include?(fields)
|
273
|
+
raise "Unsupported type \"#{fields}\"" unless fields.is_a? Hash
|
274
|
+
|
268
275
|
out = { properties: {} }
|
269
276
|
required = []
|
277
|
+
|
270
278
|
allowed_types = %i[array object]
|
271
279
|
fields.each do |name, field|
|
272
280
|
allowed_type = allowed_types.include?(field[:type]) || PARAM_TYPES.key?(field[:type])
|
@@ -6,7 +6,7 @@ require 'active_support'
|
|
6
6
|
module RSpec
|
7
7
|
module Rails
|
8
8
|
module Api
|
9
|
-
# Class to render
|
9
|
+
# Class to render metadata.
|
10
10
|
# Example:
|
11
11
|
# ```rb
|
12
12
|
# renderer = RSpec::Rails::Api::OpenApiRenderer.new
|
@@ -35,11 +35,11 @@ module RSpec
|
|
35
35
|
#
|
36
36
|
# @return [void
|
37
37
|
def merge_context(context, dump_metadata: false)
|
38
|
-
@metadata[:resources].deep_merge! context[:resources]
|
39
|
-
@metadata[:entities].deep_merge! context[:entities]
|
38
|
+
@metadata[:resources].deep_merge! context.respond_to?(:resources) ? context.resources : context[:resources]
|
39
|
+
@metadata[:entities].deep_merge! context.respond_to?(:entities) ? context.entities : context[:entities]
|
40
40
|
|
41
41
|
# Save context for debug and fixtures
|
42
|
-
File.write ::Rails.root.join('tmp', 'rra_metadata.yaml'),
|
42
|
+
File.write ::Rails.root.join('tmp', 'rra_metadata.yaml'), @metadata.to_yaml if dump_metadata
|
43
43
|
end
|
44
44
|
|
45
45
|
##
|
@@ -50,10 +50,11 @@ module RSpec
|
|
50
50
|
#
|
51
51
|
# @return [void]
|
52
52
|
def write_files(path = nil, only: %i[yaml json])
|
53
|
+
return unless write_file? RSpec.world.filtered_examples
|
54
|
+
|
53
55
|
path ||= ::Rails.root.join('tmp', 'rspec_api_rails')
|
54
56
|
|
55
57
|
file_types = %i[yaml json]
|
56
|
-
|
57
58
|
only.each do |type|
|
58
59
|
next unless file_types.include? type
|
59
60
|
|
@@ -66,7 +67,7 @@ module RSpec
|
|
66
67
|
#
|
67
68
|
# @return [Hash] The OpenAPI structure
|
68
69
|
def prepare_metadata
|
69
|
-
|
70
|
+
extract_metadata
|
70
71
|
# Example: https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore-expanded.yaml
|
71
72
|
hash = {
|
72
73
|
openapi: '3.0.0',
|
@@ -107,11 +108,23 @@ module RSpec
|
|
107
108
|
|
108
109
|
private
|
109
110
|
|
111
|
+
def write_file?(examples)
|
112
|
+
acceptance_examples = examples.values.flatten.filter do |e|
|
113
|
+
e.metadata[:type] == :acceptance
|
114
|
+
end
|
115
|
+
unless acceptance_examples.none?(&:exception)
|
116
|
+
puts "\n\e[00;31mSome acceptance tests failed. OpenApi specification file was not updated.\n\e[00m"
|
117
|
+
return false
|
118
|
+
end
|
119
|
+
|
120
|
+
true
|
121
|
+
end
|
122
|
+
|
110
123
|
##
|
111
124
|
# Extracts metadata for rendering
|
112
125
|
#
|
113
126
|
# @return [void]
|
114
|
-
def
|
127
|
+
def extract_metadata
|
115
128
|
extract_from_resources
|
116
129
|
api_infos
|
117
130
|
api_servers
|
@@ -190,10 +203,8 @@ module RSpec
|
|
190
203
|
property[:format] = PARAM_TYPES[field.type][:format] if PARAM_TYPES[field.type][:format]
|
191
204
|
schema[:properties][name] = property
|
192
205
|
# Primitives support
|
193
|
-
if PRIMITIVES.include? field.attributes
|
194
|
-
|
195
|
-
{ type: field.attributes.to_s.split('_').last.to_sym }
|
196
|
-
end
|
206
|
+
property[:items] = { type: field.attributes } if PRIMITIVES.include? field.attributes
|
207
|
+
|
197
208
|
required.push name unless field.required == false
|
198
209
|
end
|
199
210
|
|
@@ -282,7 +293,7 @@ module RSpec
|
|
282
293
|
#
|
283
294
|
# @return [void]
|
284
295
|
def process_request_body(schema: nil, ref: nil, examples: {})
|
285
|
-
Utils.deep_set @api_components,
|
296
|
+
Utils.deep_set @api_components, ['schemas', ref], schema
|
286
297
|
{
|
287
298
|
# description: '',
|
288
299
|
required: true,
|
@@ -321,7 +332,7 @@ module RSpec
|
|
321
332
|
def response_schema(expectations)
|
322
333
|
if expectations[:many]
|
323
334
|
items = if PRIMITIVES.include?(expectations[:many])
|
324
|
-
{ type: expectations[:many]
|
335
|
+
{ type: expectations[:many] }
|
325
336
|
else
|
326
337
|
{ '$ref' => "#/components/schemas/#{expectations[:many]}" }
|
327
338
|
end
|
@@ -7,139 +7,38 @@ module RSpec
|
|
7
7
|
module Api
|
8
8
|
# Helper methods
|
9
9
|
class Utils
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
10
|
+
class << self
|
11
|
+
##
|
12
|
+
# Sets a value at given dotted path in a hash
|
13
|
+
#
|
14
|
+
# @param hash [Hash] The target hash
|
15
|
+
# @param path [Array] List of keys to access value
|
16
|
+
# @param value [*] Value to set
|
17
|
+
#
|
18
|
+
# @return [Hash] The modified hash
|
19
|
+
def deep_set(hash, path, value)
|
20
|
+
raise 'path should be an array' unless path.is_a? Array
|
21
|
+
|
22
|
+
return value if path.count.zero?
|
23
|
+
|
24
|
+
current_key = path.shift.to_s.to_sym
|
25
|
+
hash[current_key] = {} unless hash[current_key].is_a?(Hash)
|
26
|
+
hash[current_key] = deep_set(hash[current_key], path, value)
|
27
|
+
|
28
|
+
hash
|
22
29
|
end
|
23
|
-
end
|
24
|
-
|
25
|
-
##
|
26
|
-
# Sets a value at given dotted path in a hash
|
27
|
-
#
|
28
|
-
# @param hash [Hash] The target hash
|
29
|
-
# @param path [String] Dotted path
|
30
|
-
# @param value [*] Value to set
|
31
|
-
#
|
32
|
-
# @return [Hash] The modified hash
|
33
|
-
def self.deep_set(hash, path, value)
|
34
|
-
path = path.split('.') unless path.is_a? Array
|
35
|
-
|
36
|
-
return value if path.count.zero?
|
37
|
-
|
38
|
-
current_key = path.shift.to_sym
|
39
|
-
hash[current_key] = {} unless hash[current_key].is_a?(Hash)
|
40
|
-
hash[current_key] = deep_set(hash[current_key], path, value)
|
41
|
-
|
42
|
-
hash
|
43
|
-
end
|
44
|
-
|
45
|
-
##
|
46
|
-
# Checks if a value is of the given parameter type
|
47
|
-
#
|
48
|
-
# @param type [Symbol] Type to compare to
|
49
|
-
# @param value [*] Value to test
|
50
|
-
#
|
51
|
-
# @return [Boolean] True when the value corresponds to the given type
|
52
|
-
def self.check_value_type(type, value)
|
53
|
-
return true if type == :boolean && (value.is_a?(TrueClass) || value.is_a?(FalseClass))
|
54
|
-
return true if type == :array && value.is_a?(Array)
|
55
|
-
|
56
|
-
raise "Unknown type #{type}" unless PARAM_TYPES.key? type
|
57
|
-
|
58
|
-
value.is_a? PARAM_TYPES[type][:class]
|
59
|
-
end
|
60
|
-
|
61
|
-
##
|
62
|
-
# Validates an object keys and values types
|
63
|
-
#
|
64
|
-
# @param actual [Hash] Hash to compare
|
65
|
-
# @param expected [Hash] Structure to compare
|
66
|
-
#
|
67
|
-
# @return [Boolean] True when the object matches the structure
|
68
|
-
def self.validate_object_structure(actual, expected)
|
69
|
-
# Check keys
|
70
|
-
return false unless same_keys? actual, expected
|
71
|
-
|
72
|
-
expected.each_key do |key|
|
73
|
-
next unless expected[key][:required]
|
74
|
-
|
75
|
-
expected_type = expected[key][:type]
|
76
|
-
expected_attributes = expected[key][:attributes]
|
77
30
|
|
78
|
-
|
79
|
-
|
31
|
+
##
|
32
|
+
# Returns a hash from an object
|
33
|
+
#
|
34
|
+
# @param value [Hash,Class] A hash or something with a "body" (as responses object in tests)
|
35
|
+
#
|
36
|
+
# @return [Hash]
|
37
|
+
def hash_from_response(value)
|
38
|
+
return JSON.parse(value.body) if value.respond_to? :body
|
80
39
|
|
81
|
-
|
82
|
-
return false unless validate_deep_object expected_type, expected_attributes, actual[key.to_s]
|
40
|
+
value
|
83
41
|
end
|
84
|
-
|
85
|
-
true
|
86
|
-
end
|
87
|
-
|
88
|
-
##
|
89
|
-
# Validates an array or hash against a definition
|
90
|
-
#
|
91
|
-
# @param expected_type [:object, :array] The expected type
|
92
|
-
# @param expected_attributes [Hash] Attributes configuration
|
93
|
-
# @param actual [Array, Hash] Value to check
|
94
|
-
#
|
95
|
-
# @return [Boolean] True when `actual` is of the expected definition
|
96
|
-
def self.validate_deep_object(expected_type, expected_attributes, actual)
|
97
|
-
if %i[object array].include?(expected_type) && expected_attributes.is_a?(Hash)
|
98
|
-
case expected_type
|
99
|
-
when :object
|
100
|
-
return false unless validate_object_structure actual, expected_attributes
|
101
|
-
when :array
|
102
|
-
return false unless validate_deep_object_array actual, expected_attributes
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
true
|
107
|
-
end
|
108
|
-
|
109
|
-
##
|
110
|
-
# Validates each entry of an array
|
111
|
-
#
|
112
|
-
# @param array [Array] The array to check
|
113
|
-
# @param expected_attributes [Hash] Attributes configuration
|
114
|
-
#
|
115
|
-
# @return [Boolean] True when all values matches the attribute configuration
|
116
|
-
def self.validate_deep_object_array(array, expected_attributes)
|
117
|
-
array.each do |array_entry|
|
118
|
-
if expected_attributes[:type]
|
119
|
-
return false unless check_value_type expected_attributes[:type], array_entry
|
120
|
-
else
|
121
|
-
return false unless validate_object_structure array_entry, expected_attributes
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
true
|
126
|
-
end
|
127
|
-
|
128
|
-
##
|
129
|
-
# Checks if a hash have the required keys in it
|
130
|
-
#
|
131
|
-
# @param actual [Hash] The hash
|
132
|
-
# @param expected [Hash] Attributes definitions
|
133
|
-
#
|
134
|
-
# @return [Boolean] True when the object is valid
|
135
|
-
def self.same_keys?(actual, expected)
|
136
|
-
optional = expected.reject { |_key, value| value[:required] }.keys
|
137
|
-
actual.symbolize_keys.keys.sort - optional == expected.keys.sort - optional
|
138
|
-
end
|
139
|
-
|
140
|
-
def self.check_attribute_type(type, except: [])
|
141
|
-
keys = PARAM_TYPES.keys.reject { |key| except.include? key }
|
142
|
-
keys.include?(type)
|
143
42
|
end
|
144
43
|
end
|
145
44
|
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/hash_with_indifferent_access'
|
4
|
+
require 'rspec_rails_api'
|
5
|
+
|
6
|
+
module RSpec
|
7
|
+
module Rails
|
8
|
+
module Api
|
9
|
+
# Set of method to validate data and data structures
|
10
|
+
class Validator
|
11
|
+
class << self
|
12
|
+
##
|
13
|
+
# Validates an object keys and values types
|
14
|
+
#
|
15
|
+
# @param actual [*] Value to compare
|
16
|
+
# @param expected [Hash, NilClass] Definition
|
17
|
+
#
|
18
|
+
# @return [String, Hash, NilClass] Nil when no error, string when not an object and dictionary of errors
|
19
|
+
# otherwise
|
20
|
+
def validate_object(actual, expected)
|
21
|
+
return 'is not a hash' unless actual.is_a? Hash
|
22
|
+
# Don't validate without a definition
|
23
|
+
return unless expected
|
24
|
+
|
25
|
+
keys_errors = validate_object_keys actual, expected
|
26
|
+
return keys_errors unless keys_errors.nil?
|
27
|
+
|
28
|
+
attributes_errors = validate_object_attributes(actual, expected)
|
29
|
+
|
30
|
+
attributes_errors unless attributes_errors.keys.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Validates each entry of an array
|
35
|
+
#
|
36
|
+
# @param array [*] The array to check
|
37
|
+
# @param expected [Symbol, Hash, NilClass] Attributes configuration
|
38
|
+
#
|
39
|
+
# @return [String, Hash, NilClass] Nil when no error, string when not an object and dictionary of errors
|
40
|
+
# otherwise
|
41
|
+
def validate_array(array, expected)
|
42
|
+
return 'is not an array' unless array.is_a? Array
|
43
|
+
# Arrays without an expected entry type
|
44
|
+
return unless expected
|
45
|
+
|
46
|
+
errors = {}
|
47
|
+
array.each_with_index do |array_entry, index|
|
48
|
+
value_error = validate_array_entry array_entry, expected
|
49
|
+
errors["##{index}"] = value_error if value_error
|
50
|
+
end
|
51
|
+
|
52
|
+
errors unless errors.keys.empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Returns a human-readable string from matcher errors
|
57
|
+
#
|
58
|
+
# @param errors [String,Hash] Validation errors
|
59
|
+
# @param values [String] JSON string representing the value
|
60
|
+
#
|
61
|
+
# @return [String]
|
62
|
+
def format_failure_message(errors, values)
|
63
|
+
if errors.is_a? Hash
|
64
|
+
errors = errors.deep_stringify_keys.to_yaml.split("\n")
|
65
|
+
errors.shift
|
66
|
+
errors.map! do |line|
|
67
|
+
" #{line.sub(/^(\s+)"(#\d+)":(.*)$/, '\1\2:\3')}"
|
68
|
+
end
|
69
|
+
errors = errors.join("\n")
|
70
|
+
end
|
71
|
+
|
72
|
+
<<~TXT
|
73
|
+
expected object structure not to have these errors:
|
74
|
+
#{errors}
|
75
|
+
|
76
|
+
As a notice, here is the JSON object:
|
77
|
+
#{values}
|
78
|
+
TXT
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Checks if a given type is in the supported types list
|
83
|
+
#
|
84
|
+
# @param type [Symbol] Type to check
|
85
|
+
# @param except [[Symbol]] List of types to ignore
|
86
|
+
#
|
87
|
+
# @return [Boolean]
|
88
|
+
def valid_type?(type, except: [])
|
89
|
+
keys = PARAM_TYPES.keys.reject { |key| except.include? key }
|
90
|
+
keys.include?(type)
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Checks if a value is of the given type
|
95
|
+
#
|
96
|
+
# @param value [*] Value to test
|
97
|
+
# @param type [Symbol] Type to compare to
|
98
|
+
#
|
99
|
+
# @return [String,NilClass] True when the value corresponds to the given type
|
100
|
+
def validate_type(value, type)
|
101
|
+
if type == :boolean
|
102
|
+
return nil if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
103
|
+
|
104
|
+
return 'is not a "boolean"'
|
105
|
+
end
|
106
|
+
|
107
|
+
raise "Unknown type #{type}" unless PARAM_TYPES.key? type
|
108
|
+
|
109
|
+
return nil if value.is_a? PARAM_TYPES[type][:class]
|
110
|
+
|
111
|
+
"is not a \"#{type}\""
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
# Checks if a key should be skipped, whether it's missing and optional or nil
|
117
|
+
#
|
118
|
+
# @param key [Symbol] Key to check
|
119
|
+
# @param value [*] Associated value
|
120
|
+
# @param definition [Hash] Entity definitions
|
121
|
+
#
|
122
|
+
# @return [Boolean]
|
123
|
+
def skip_key_check?(key, value, definition)
|
124
|
+
# Ignore missing optional keys
|
125
|
+
return true unless value.key?(key.to_s) || definition[key][:required]
|
126
|
+
# Ignore null optional keys
|
127
|
+
return true if !definition[key][:required] && value[key.to_s].nil?
|
128
|
+
|
129
|
+
false
|
130
|
+
end
|
131
|
+
|
132
|
+
# Validates the keys of a hash
|
133
|
+
#
|
134
|
+
# @param actual [Hash] The hash to check
|
135
|
+
# @param definition [Hash] The object definition
|
136
|
+
#
|
137
|
+
# @return [String, Hash, NilClass] Nil when no error, string when not an object and dictionary of errors
|
138
|
+
# otherwise
|
139
|
+
def validate_object_keys(actual, definition)
|
140
|
+
# Hashes without an expected attributes type
|
141
|
+
return unless definition
|
142
|
+
|
143
|
+
errors = {}
|
144
|
+
actual.each_key do |key|
|
145
|
+
errors[key] = 'is not defined' unless definition.key?(key.to_sym)
|
146
|
+
end
|
147
|
+
|
148
|
+
errors unless errors.keys.empty?
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# Validates the attributes of a Hash
|
153
|
+
#
|
154
|
+
# @param actual [Hash] Value to compare
|
155
|
+
# @param expected [Hash] Definition
|
156
|
+
#
|
157
|
+
# @return [String, Hash, NilClass] Nil when no error, string when not an object and dictionary of errors
|
158
|
+
# otherwise
|
159
|
+
def validate_object_attributes(actual, expected)
|
160
|
+
errors = {}
|
161
|
+
expected.each_key do |key|
|
162
|
+
next if skip_key_check? key, actual, expected
|
163
|
+
|
164
|
+
value_error = validate_object_attribute key, actual, expected[key][:type], expected[key][:attributes]
|
165
|
+
errors[key] = value_error unless value_error.nil?
|
166
|
+
end
|
167
|
+
|
168
|
+
errors unless errors.keys.nil?
|
169
|
+
end
|
170
|
+
|
171
|
+
# Checks the value of an entry in a Hash
|
172
|
+
#
|
173
|
+
# @param key [Symbol] Key to check
|
174
|
+
# @param actual [Hash] Hash to check
|
175
|
+
# @param expected_type [Symbol] Expected type
|
176
|
+
# @param definition [Symbol,Hash] Attribute definition
|
177
|
+
#
|
178
|
+
# @return [String,Hash,NilClass] Nil when no error is met, string when not a primitive and dictionary of
|
179
|
+
# errors otherwise
|
180
|
+
def validate_object_attribute(key, actual, expected_type, definition)
|
181
|
+
return 'is missing' unless actual.key? key.to_s
|
182
|
+
|
183
|
+
case expected_type
|
184
|
+
when :object
|
185
|
+
validate_object actual[key.to_s], definition
|
186
|
+
when :array
|
187
|
+
validate_array actual[key.to_s], definition
|
188
|
+
else
|
189
|
+
validate_type actual[key.to_s], expected_type
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Checks the validity of an array entry against a definition
|
194
|
+
#
|
195
|
+
# @param entry [*] Entry to check
|
196
|
+
# @param definition [Hash] Fields definition
|
197
|
+
#
|
198
|
+
# @return [String,Hash,NilClass] Nil when no error is met, string when not a primitive and dictionary of
|
199
|
+
# errors otherwise
|
200
|
+
def validate_array_entry(entry, definition)
|
201
|
+
if definition[:type].is_a? Symbol # Array of "simple" values
|
202
|
+
validate_type entry, definition[:type]
|
203
|
+
else # Objects
|
204
|
+
validate_object entry, definition
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
data/lib/rspec_rails_api.rb
CHANGED
@@ -35,11 +35,7 @@ module RSpec
|
|
35
35
|
object: { type: 'object', format: nil, class: Hash },
|
36
36
|
}.freeze
|
37
37
|
|
38
|
-
EXCLUDED_PRIMITIVES = %i[array object].freeze
|
39
|
-
|
40
38
|
PRIMITIVES = PARAM_TYPES.keys
|
41
|
-
.reject { |key| EXCLUDED_PRIMITIVES.include? key }
|
42
|
-
.map { |key| "type_#{key}".to_sym }
|
43
39
|
end
|
44
40
|
end
|
45
41
|
end
|
data/rspec-rails-api.gemspec
CHANGED
@@ -33,15 +33,18 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
34
34
|
spec.require_paths = ['lib']
|
35
35
|
|
36
|
-
spec.required_ruby_version = '>= 2.
|
36
|
+
spec.required_ruby_version = '>= 2.7.0'
|
37
37
|
|
38
38
|
spec.add_development_dependency 'activesupport', '~> 6.0'
|
39
39
|
spec.add_development_dependency 'bundler'
|
40
40
|
spec.add_development_dependency 'byebug'
|
41
|
+
spec.add_development_dependency 'rack'
|
41
42
|
spec.add_development_dependency 'rake', '~> 10.0'
|
42
43
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
43
44
|
spec.add_development_dependency 'rubocop'
|
44
45
|
spec.add_development_dependency 'rubocop-performance'
|
46
|
+
spec.add_development_dependency 'rubocop-rake'
|
47
|
+
spec.add_development_dependency 'rubocop-rspec'
|
45
48
|
spec.add_development_dependency 'simplecov'
|
46
49
|
spec.add_development_dependency 'yard'
|
47
50
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-rails-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manuel Tancoigne
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,34 @@ dependencies:
|
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop-rake
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop-rspec
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
111
153
|
- !ruby/object:Gem::Dependency
|
112
154
|
name: simplecov
|
113
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -149,10 +191,12 @@ files:
|
|
149
191
|
- ".gitlab-ci.yml"
|
150
192
|
- ".rspec"
|
151
193
|
- ".rubocop.yml"
|
194
|
+
- ".ruby-version"
|
152
195
|
- ".travis.yml"
|
153
196
|
- CHANGELOG.md
|
154
197
|
- CODE_OF_CONDUCT.md
|
155
198
|
- Gemfile
|
199
|
+
- Gemfile.lock
|
156
200
|
- LICENSE.txt
|
157
201
|
- README.md
|
158
202
|
- Rakefile
|
@@ -166,6 +210,7 @@ files:
|
|
166
210
|
- lib/rspec/rails/api/metadata.rb
|
167
211
|
- lib/rspec/rails/api/open_api_renderer.rb
|
168
212
|
- lib/rspec/rails/api/utils.rb
|
213
|
+
- lib/rspec/rails/api/validator.rb
|
169
214
|
- lib/rspec/rails/api/version.rb
|
170
215
|
- lib/rspec_rails_api.rb
|
171
216
|
- rspec-rails-api.gemspec
|
@@ -185,15 +230,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
185
230
|
requirements:
|
186
231
|
- - ">="
|
187
232
|
- !ruby/object:Gem::Version
|
188
|
-
version: 2.
|
233
|
+
version: 2.7.0
|
189
234
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
190
235
|
requirements:
|
191
236
|
- - ">="
|
192
237
|
- !ruby/object:Gem::Version
|
193
238
|
version: '0'
|
194
239
|
requirements: []
|
195
|
-
|
196
|
-
rubygems_version: 2.7.6
|
240
|
+
rubygems_version: 3.4.1
|
197
241
|
signing_key:
|
198
242
|
specification_version: 4
|
199
243
|
summary: Tests standard Rails API responses and generate doc
|