rspec-rails-api 0.3.0 → 0.3.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 +4 -4
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +12 -0
- data/README.md +11 -1
- data/lib/rspec/rails/api/dsl/example.rb +5 -3
- data/lib/rspec/rails/api/dsl/example_group.rb +3 -3
- data/lib/rspec/rails/api/field_config.rb +4 -3
- data/lib/rspec/rails/api/metadata.rb +14 -21
- data/lib/rspec/rails/api/open_api_renderer.rb +15 -13
- data/lib/rspec/rails/api/utils.rb +2 -2
- data/lib/rspec/rails/api/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9090792ade8b44f18851585ce025a354fab47ff9cb7903ae61982507c34302bf
|
4
|
+
data.tar.gz: 26551e11739758d40987f7026cc556e475952f79419cb24abf5df4207ba40364
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bc1803ab38dc596f0fbf3993da2f860e22849f1d2e9c68be91e860b36684ee3bf0129a98972afca1d7f65869531c6cc8aa0f36d66aa91d97f92ebbad69cfff1
|
7
|
+
data.tar.gz: b96392b596dd83d1de832b62a72d54afbed0f0a556c36bbf7627ed2fbec7c36d59c4d1d935186e3de62f72524243bf75f92a6429bc492cf559ebb22751e74dcc
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,18 @@
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
4
|
## Not released
|
5
|
+
## 0.3.4 - 2021-10-20
|
6
|
+
- Add the "required" attribute in parameters
|
7
|
+
|
8
|
+
## 0.3.3 - 2021-06-02
|
9
|
+
- Fix correct types on request parameters
|
10
|
+
|
11
|
+
## 0.3.2 - 2021-03-09
|
12
|
+
- Fix YAML rendering (ruby objects were sometimes rendered in documentation)
|
13
|
+
- Render examples results as YAML/JSON objects instead of text blocks.
|
14
|
+
|
15
|
+
## 0.3.1 - 2020-04-09
|
16
|
+
- Add support for "test only" examples, allowing to write examples without documentation.
|
5
17
|
|
6
18
|
## 0.3.0 - 2019-12-26
|
7
19
|
|
data/README.md
CHANGED
@@ -380,7 +380,7 @@ on_post '/api/items' do
|
|
380
380
|
end
|
381
381
|
```
|
382
382
|
|
383
|
-
##### `for_code(http_status, description = nil, doc_only: false &block)`
|
383
|
+
##### `for_code(http_status, description = nil, doc_only: false, test_only: false &block)`
|
384
384
|
|
385
385
|
Describes the desired output for a precedently defined URL.
|
386
386
|
|
@@ -388,6 +388,9 @@ Block takes one required argument, that should be passed to `visit`.
|
|
388
388
|
This argument will contain the block context and allow `visit` to access
|
389
389
|
the metadatas.
|
390
390
|
|
391
|
+
You can have only one documented code per action/url, unless you use
|
392
|
+
`test_only`.
|
393
|
+
|
391
394
|
- `http_status` is an integer representing an
|
392
395
|
[HTTP status](https://httpstat.us/)
|
393
396
|
- `description` should be some valid
|
@@ -395,6 +398,8 @@ the metadatas.
|
|
395
398
|
translation of the `http_status` will be used.
|
396
399
|
- `doc_only` can be set to true to temporarily disable block execution
|
397
400
|
and only create the documentation (without examples).
|
401
|
+
- `test_only` will omit the test from the documentation. Useful when you
|
402
|
+
need to test things _around_ the call (response content, db,...)
|
398
403
|
- `block` where additional tests can be performed. If `visit()` is
|
399
404
|
called within the block, its output will be used in documentation
|
400
405
|
examples, and the response type and code will actually be tested.
|
@@ -412,6 +417,11 @@ Once again, you have to pass an argument to the block if you use
|
|
412
417
|
visit url
|
413
418
|
# ...
|
414
419
|
end
|
420
|
+
|
421
|
+
for_code 200, 'Side test', test_only: true do |url|
|
422
|
+
visit url
|
423
|
+
# ...
|
424
|
+
end
|
415
425
|
# ...
|
416
426
|
```
|
417
427
|
|
@@ -6,7 +6,7 @@ module RSpec
|
|
6
6
|
module DSL
|
7
7
|
# These methods will be available in examples (i.e.: 'for_code')
|
8
8
|
module Example
|
9
|
-
def visit(example, path_params: {}, payload: {}, headers: {}) # rubocop:disable Metrics/AbcSize
|
9
|
+
def visit(example, path_params: {}, payload: {}, headers: {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
10
10
|
raise 'Missing context. Call visit with for_code context.' unless example
|
11
11
|
|
12
12
|
status_code = prepare_status_code example.class.description
|
@@ -21,6 +21,8 @@ module RSpec
|
|
21
21
|
|
22
22
|
check_response(response, status_code)
|
23
23
|
|
24
|
+
return if example.class.description.match?(/-> test (\d+)(.*)/)
|
25
|
+
|
24
26
|
set_request_example example.class.metadata[:rrad], request_params, status_code, response.body
|
25
27
|
end
|
26
28
|
|
@@ -53,7 +55,7 @@ module RSpec
|
|
53
55
|
end
|
54
56
|
|
55
57
|
def prepare_request_params(description, request_params = {}, payload = {}, request_headers = {})
|
56
|
-
example_params = description.split
|
58
|
+
example_params = description.split
|
57
59
|
|
58
60
|
{
|
59
61
|
action: example_params[0].downcase,
|
@@ -86,7 +88,7 @@ module RSpec
|
|
86
88
|
end
|
87
89
|
|
88
90
|
def prepare_status_code(description)
|
89
|
-
code_match = /-> (\d+) - .*/.match description
|
91
|
+
code_match = /->(?: test)? (\d+) - .*/.match description
|
90
92
|
|
91
93
|
raise 'Please provide a numerical code for the "for_code" block' unless code_match
|
92
94
|
|
@@ -74,12 +74,12 @@ module RSpec
|
|
74
74
|
describe("#{action.upcase} #{url}", &block)
|
75
75
|
end
|
76
76
|
|
77
|
-
def for_code(status_code, description = nil, doc_only: false, &block)
|
77
|
+
def for_code(status_code, description = nil, doc_only: false, test_only: false, &block)
|
78
78
|
description ||= Rack::Utils::HTTP_STATUS_CODES[status_code]
|
79
79
|
|
80
|
-
metadata[:rrad].add_status_code(status_code, description)
|
80
|
+
metadata[:rrad].add_status_code(status_code, description) unless test_only
|
81
81
|
|
82
|
-
describe "
|
82
|
+
describe "->#{test_only ? ' test' : ''} #{status_code} - #{description}" do
|
83
83
|
execute_for_code_block(status_code, doc_only, block)
|
84
84
|
end
|
85
85
|
end
|
@@ -11,7 +11,7 @@ module RSpec
|
|
11
11
|
class FieldConfig
|
12
12
|
attr_accessor :required, :type, :attributes, :description
|
13
13
|
|
14
|
-
def initialize(type:, required: true,
|
14
|
+
def initialize(type:, description:, required: true, attributes: nil, of: nil)
|
15
15
|
@required = required
|
16
16
|
@description = description
|
17
17
|
raise "Field type not allowed: '#{type}'" unless Utils.check_attribute_type(type)
|
@@ -40,9 +40,10 @@ module RSpec
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def define_attributes(attributes)
|
43
|
-
@attributes =
|
43
|
+
@attributes = case attributes
|
44
|
+
when Hash
|
44
45
|
@attributes = EntityConfig.new attributes
|
45
|
-
|
46
|
+
when Symbol
|
46
47
|
attributes
|
47
48
|
end
|
48
49
|
end
|
@@ -36,6 +36,9 @@ module RSpec
|
|
36
36
|
def add_parameter(type, fields)
|
37
37
|
raise "Parameter #{type} is already defined" if @parameters[type]
|
38
38
|
|
39
|
+
fields.each_value do |field|
|
40
|
+
field[:required] = true unless field[:required] == false
|
41
|
+
end
|
39
42
|
@parameters[type] = fields
|
40
43
|
end
|
41
44
|
|
@@ -87,7 +90,7 @@ module RSpec
|
|
87
90
|
@current_method = method
|
88
91
|
end
|
89
92
|
|
90
|
-
# rubocop:disable
|
93
|
+
# rubocop:disable Layout/LineLength
|
91
94
|
def add_status_code(status_code, description)
|
92
95
|
check_current_context :resource, :url, :method
|
93
96
|
|
@@ -97,7 +100,7 @@ module RSpec
|
|
97
100
|
example: { response: nil })
|
98
101
|
@current_code = status_code
|
99
102
|
end
|
100
|
-
# rubocop:enable
|
103
|
+
# rubocop:enable Layout/LineLength
|
101
104
|
|
102
105
|
# rubocop:disable Metrics/ParameterLists
|
103
106
|
def add_request_example(url: nil, action: nil, status_code: nil, response: nil, path_params: nil, params: nil)
|
@@ -125,25 +128,14 @@ module RSpec
|
|
125
128
|
|
126
129
|
private
|
127
130
|
|
128
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
129
|
-
def check_current_context(*scope)
|
131
|
+
def check_current_context(*scope) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
130
132
|
scope ||= []
|
131
|
-
if scope.include?(:resource)
|
132
|
-
|
133
|
-
|
134
|
-
if scope.include?(:
|
135
|
-
raise 'No action declared' unless @current_method
|
136
|
-
end
|
137
|
-
if scope.include?(:url)
|
138
|
-
raise 'No url declared' unless @current_url
|
139
|
-
end
|
140
|
-
if scope.include?(:code)
|
141
|
-
raise 'No status code declared' unless @current_code
|
142
|
-
end
|
133
|
+
raise 'No resource declared' if scope.include?(:resource) && !@current_resource
|
134
|
+
raise 'No action declared' if scope.include?(:method) && !@current_method
|
135
|
+
raise 'No url declared' if scope.include?(:url) && !@current_url
|
136
|
+
raise 'No status code declared' if scope.include?(:code) && !@current_code
|
143
137
|
end
|
144
138
|
|
145
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Style/GuardClause
|
146
|
-
|
147
139
|
def path_param_scope(url_chunks, name)
|
148
140
|
if /:#{name}/.match?(url_chunks[0])
|
149
141
|
:path
|
@@ -154,11 +146,12 @@ module RSpec
|
|
154
146
|
end
|
155
147
|
end
|
156
148
|
|
157
|
-
def organize_params(fields) # rubocop:disable Metrics/AbcSize
|
149
|
+
def organize_params(fields) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
158
150
|
out = { properties: {} }
|
159
151
|
required = []
|
152
|
+
allowed_types = %i[array object]
|
160
153
|
fields.each do |name, field|
|
161
|
-
allowed_type =
|
154
|
+
allowed_type = allowed_types.include?(field[:type]) || PARAM_TYPES.key?(field[:type])
|
162
155
|
raise "Field type not allowed: #{field[:type]}" unless allowed_type
|
163
156
|
|
164
157
|
required.push name.to_s if field[:required]
|
@@ -174,7 +167,7 @@ module RSpec
|
|
174
167
|
organize_params field[:properties]
|
175
168
|
else
|
176
169
|
properties = {
|
177
|
-
type: field[:type]
|
170
|
+
type: PARAM_TYPES[field[:type]][:type],
|
178
171
|
description: field[:description] || nil,
|
179
172
|
}
|
180
173
|
|
@@ -39,10 +39,12 @@ module RSpec
|
|
39
39
|
content = prepare_metadata
|
40
40
|
path ||= ::Rails.root.join('tmp', 'rspec_api_rails')
|
41
41
|
|
42
|
+
file_types = %i[yaml json]
|
43
|
+
|
42
44
|
only.each do |type|
|
43
|
-
next unless
|
45
|
+
next unless file_types.include? type
|
44
46
|
|
45
|
-
File.write "#{path}.#{type}", content.send("to_#{type}")
|
47
|
+
File.write "#{path}.#{type}", JSON.parse(JSON.pretty_generate(content)).send("to_#{type}")
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
@@ -89,13 +91,14 @@ module RSpec
|
|
89
91
|
end
|
90
92
|
|
91
93
|
def process_resource(resource: nil, resource_config: nil) # rubocop:disable Metrics/MethodLength
|
94
|
+
http_verbs = %i[get post put patch delete]
|
92
95
|
resource_config[:paths].each do |path_key, path|
|
93
96
|
url = path_with_params path_key.to_s
|
94
97
|
actions = {}
|
95
98
|
parameters = path.key?(:path_params) ? process_path_params(path[:path_params]) : []
|
96
99
|
|
97
100
|
path[:actions].each_key do |action|
|
98
|
-
next unless
|
101
|
+
next unless http_verbs.include? action
|
99
102
|
|
100
103
|
actions[action] = process_action resource: resource,
|
101
104
|
path: path_key,
|
@@ -117,7 +120,7 @@ module RSpec
|
|
117
120
|
parameters
|
118
121
|
end
|
119
122
|
|
120
|
-
def process_path_param(name, param) # rubocop:disable Metrics/MethodLength
|
123
|
+
def process_path_param(name, param) # rubocop:disable Metrics/MethodLength
|
121
124
|
parameter = {
|
122
125
|
name: name.to_s,
|
123
126
|
description: param[:description],
|
@@ -138,13 +141,12 @@ module RSpec
|
|
138
141
|
responses = {}
|
139
142
|
request_body = nil
|
140
143
|
|
141
|
-
if %i[post put
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
144
|
+
if %i[post put
|
145
|
+
patch].include?(action_config) && path_config[:actions][action_config][:params].keys.count.positive?
|
146
|
+
schema = path_config[:actions][action_config][:params]
|
147
|
+
schema_ref = escape_operation_id("#{action_config}_#{path}")
|
148
|
+
examples = process_examples(path_config[:actions][action_config][:statuses])
|
149
|
+
request_body = process_request_body schema: schema, ref: schema_ref, examples: examples
|
148
150
|
end
|
149
151
|
|
150
152
|
path_config[:actions][action_config][:statuses].each do |status_key, status|
|
@@ -190,7 +192,7 @@ module RSpec
|
|
190
192
|
|
191
193
|
response[:content] = {
|
192
194
|
'application/json': {
|
193
|
-
examples: { default: { value: JSON.
|
195
|
+
examples: { default: { value: JSON.parse(content) } },
|
194
196
|
},
|
195
197
|
}
|
196
198
|
|
@@ -220,7 +222,7 @@ module RSpec
|
|
220
222
|
string.downcase.gsub(/[^\w]+/, '_')
|
221
223
|
end
|
222
224
|
|
223
|
-
def api_infos
|
225
|
+
def api_infos
|
224
226
|
@api_infos = {
|
225
227
|
title: @api_title || 'Some sample app',
|
226
228
|
version: @api_version || '1.0',
|
@@ -11,7 +11,7 @@ module RSpec
|
|
11
11
|
path.split('.').inject(hash) do |sub_hash, key|
|
12
12
|
return nil unless sub_hash.is_a?(Hash) && sub_hash.key?(key.to_sym)
|
13
13
|
|
14
|
-
sub_hash[key.to_sym]
|
14
|
+
sub_hash[key.to_sym] # rubocop:disable Lint/UnmodifiedReduceAccumulator
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -27,7 +27,7 @@ module RSpec
|
|
27
27
|
hash
|
28
28
|
end
|
29
29
|
|
30
|
-
def self.check_value_type(type, value)
|
30
|
+
def self.check_value_type(type, value)
|
31
31
|
return true if type == :boolean && (value.is_a?(TrueClass) || value.is_a?(FalseClass))
|
32
32
|
return true if type == :array && value.is_a?(Array)
|
33
33
|
|
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.3.
|
4
|
+
version: 0.3.4
|
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: 2021-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|