rspec-rails-api 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.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
|