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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 74591eecb7e2b200f536ca31e72097ed9921da563a87490288f536edec32f728
4
- data.tar.gz: a5ec7199c37b2bf493eec385b3f294561acfa409c46dac9d744f1d7679a37f30
3
+ metadata.gz: 9090792ade8b44f18851585ce025a354fab47ff9cb7903ae61982507c34302bf
4
+ data.tar.gz: 26551e11739758d40987f7026cc556e475952f79419cb24abf5df4207ba40364
5
5
  SHA512:
6
- metadata.gz: 4922b2a7257f432048f37cb9d73faf8b0b15a7750760429f3f29b657d282b5e556e9b380813843574d5be116ed040bd71a91ddb2301f0d65df6f38b70981204d
7
- data.tar.gz: b82d1c509e096f1ac04bebe56dbed7a4ed9e49a9de47b525cae0bba2355033ed61a727a17fb9691701f10dc0ba36be4c00a9b62531c2621b302910a25d200511
6
+ metadata.gz: 4bc1803ab38dc596f0fbf3993da2f860e22849f1d2e9c68be91e860b36684ee3bf0129a98972afca1d7f65869531c6cc8aa0f36d66aa91d97f92ebbad69cfff1
7
+ data.tar.gz: b96392b596dd83d1de832b62a72d54afbed0f0a556c36bbf7627ed2fbec7c36d59c4d1d935186e3de62f72524243bf75f92a6429bc492cf559ebb22751e74dcc
data/.rubocop.yml CHANGED
@@ -7,6 +7,7 @@ AllCops:
7
7
  Exclude:
8
8
  - dummy/**/*
9
9
  - vendor/bundle/**/*
10
+ NewCops: enable
10
11
 
11
12
  Layout/LineLength:
12
13
  Max: 120
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 "-> #{status_code} - #{description}" do
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, description:, attributes: nil, of: nil)
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 = if attributes.is_a? Hash
43
+ @attributes = case attributes
44
+ when Hash
44
45
  @attributes = EntityConfig.new attributes
45
- elsif attributes.is_a? Symbol
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 Metrics/LineLength
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 Metrics/LineLength
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, Metrics/MethodLength, Style/GuardClause
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
- raise 'No resource declared' unless @current_resource
133
- end
134
- if scope.include?(:method)
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 = %i[array object].include?(field[:type]) || PARAM_TYPES.key?(field[: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].to_s,
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 %i[yaml json].include? type
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 %i[get post put patch delete].include? action
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, Metrics/AbcSize
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 patch].include? action_config
142
- if path_config[:actions][action_config][:params].keys.count.positive?
143
- schema = path_config[:actions][action_config][:params]
144
- schema_ref = escape_operation_id("#{action_config}_#{path}")
145
- examples = process_examples(path_config[:actions][action_config][:statuses])
146
- request_body = process_request_body schema: schema, ref: schema_ref, examples: examples
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.pretty_generate(JSON.parse(content)) } },
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 # rubocop:disable Metrics/CyclomaticComplexity
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) # rubocop:disable Metrics/CyclomaticComplexity
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
 
@@ -3,7 +3,7 @@
3
3
  module RSpec
4
4
  module Rails
5
5
  module Api
6
- VERSION = '0.3.0'
6
+ VERSION = '0.3.4'
7
7
  end
8
8
  end
9
9
  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.3.0
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: 2019-12-30 00:00:00.000000000 Z
11
+ date: 2021-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport