rswag-specs 2.8.0 → 2.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cfedb2177ee21788aa710db72fbc573230a51c84877bd90edff99b8a1fc9967c
4
- data.tar.gz: 842d0dba7c2dcd4aa59ec015928c825da6ef1cf892859e492589d540b003c181
3
+ metadata.gz: fa8f8005ed229944c19cb2e33e09eaebb95b8e32b9bef505a5e6b64b237bcbdc
4
+ data.tar.gz: 7eebf43807f0252c3168e08283b716c3dd9356f5d79fde1fcfc275377b5bc522
5
5
  SHA512:
6
- metadata.gz: 5640b7930547aa45a3b2662f8fad08508063d1c9726c2f72d6e2f15f6eab32408472e7645230b30a5eec74ae223cfae5e87e9d26311cc609aa543c90d8234aef
7
- data.tar.gz: 98e797ce8b1babf942ba387cffbe6eec52994047543c669b9293631bc08bfc1695b9d3c1ca572f3ec9357e7649bf601f0df81bf28590ee605b501f7546aae8f1
6
+ metadata.gz: e99187485ac197dad84d0f28b9bdec67c0e11b10efb5f2561a939e48852a6fc28505d2c92feb49a2969dd6a5a7919279986a05d9c3d09db2dc15581b085908ed
7
+ data.tar.gz: 1da746e08c42864094b13f36b72587f1d05b55922106ac1888accf16ac1bfae84c5fafb28dfa5952c47b477742b592bfff915743842523104f28e416859c1889
@@ -6,13 +6,14 @@ require 'rails/generators'
6
6
  module Rspec
7
7
  class SwaggerGenerator < ::Rails::Generators::NamedBase
8
8
  source_root File.expand_path('templates', __dir__)
9
+ class_option :spec_path, type: :string, default: 'requests'
9
10
 
10
11
  def setup
11
12
  @routes = Rswag::RouteParser.new(controller_path).routes
12
13
  end
13
14
 
14
15
  def create_spec_file
15
- template 'spec.rb', File.join('spec', 'requests', "#{controller_path}_spec.rb")
16
+ template 'spec.rb', File.join('spec', options['spec_path'], "#{controller_path}_spec.rb")
16
17
  end
17
18
 
18
19
  private
@@ -55,6 +55,10 @@ module Rswag
55
55
  doc = get_swagger_doc(name)
56
56
  doc[:openapi] || doc[:swagger]
57
57
  end
58
+
59
+ def swagger_strict_schema_validation
60
+ @swagger_strict_schema_validation ||= (@rspec_config.swagger_strict_schema_validation || false)
61
+ end
58
62
  end
59
63
 
60
64
  class ConfigurationError < StandardError; end
@@ -56,16 +56,16 @@ module Rswag
56
56
  end
57
57
 
58
58
 
59
- def request_body_example(value:, summary: nil, name: nil)
60
- if metadata.key?(:operation)
59
+ def request_body_example(value:, summary: nil, name: nil)
60
+ if metadata.key?(:operation)
61
61
  metadata[:operation][:request_examples] ||= []
62
- example = { value: value }
63
- example[:summary] = summary if summary
62
+ example = { value: value }
63
+ example[:summary] = summary if summary
64
64
  # We need the examples to have a unique name for a set of examples, so just make the name the length if one isn't provided.
65
65
  example[:name] = name || metadata[:operation][:request_examples].length()
66
66
  metadata[:operation][:request_examples] << example
67
- end
68
- end
67
+ end
68
+ end
69
69
 
70
70
  def response(code, description, metadata = {}, &block)
71
71
  metadata[:response] = { code: code, description: description }
@@ -115,14 +115,22 @@ module Rswag
115
115
  )
116
116
  end
117
117
 
118
- def run_test!(&block)
118
+ #
119
+ # Perform request and assert response matches swagger definitions
120
+ #
121
+ # @param options [Hash] options to pass to the `it` method
122
+ # @param &block [Proc] you can make additional assertions within that block
123
+ # @return [void]
124
+ def run_test!(**options, &block)
125
+ options[:rswag] = true unless options.key?(:rswag)
126
+
119
127
  if RSPEC_VERSION < 3
120
128
  ActiveSupport::Deprecation.warn('Rswag::Specs: WARNING: Support for RSpec 2.X will be dropped in v3.0')
121
129
  before do
122
130
  submit_request(example.metadata)
123
131
  end
124
132
 
125
- it "returns a #{metadata[:response][:code]} response", rswag: true do
133
+ it "returns a #{metadata[:response][:code]} response", **options do
126
134
  assert_response_matches_metadata(metadata)
127
135
  block.call(response) if block_given?
128
136
  end
@@ -131,7 +139,7 @@ module Rswag
131
139
  submit_request(example.metadata)
132
140
  end
133
141
 
134
- it "returns a #{metadata[:response][:code]} response", rswag: true do |example|
142
+ it "returns a #{metadata[:response][:code]} response", **options do |example|
135
143
  assert_response_matches_metadata(example.metadata, &block)
136
144
  example.instance_exec(response, &block) if block_given?
137
145
  end
@@ -34,7 +34,7 @@ module Rswag
34
34
  (operation_params + path_item_params + security_params)
35
35
  .map { |p| p['$ref'] ? resolve_parameter(p['$ref'], swagger_doc) : p }
36
36
  .uniq { |p| p[:name] }
37
- .reject { |p| p[:required] == false && !example.respond_to?(p[:name]) }
37
+ .reject { |p| p[:required] == false && !example.respond_to?(extract_getter(p)) }
38
38
  end
39
39
 
40
40
  def derive_security_params(metadata, swagger_doc)
@@ -106,7 +106,7 @@ module Rswag
106
106
  server = swagger_doc[:servers].first
107
107
  variables = {}
108
108
  server.fetch(:variables, {}).each_pair { |k,v| variables[k] = v[use_server] }
109
- base_path = server[:url].gsub(/\{(.*?)\}/) { |name| variables[name.to_sym] }
109
+ base_path = server[:url].gsub(/\{(.*?)\}/) { variables[$1.to_sym] }
110
110
  URI(base_path).path
111
111
  end
112
112
 
@@ -126,16 +126,16 @@ module Rswag
126
126
 
127
127
  request[:path] = template.tap do |path_template|
128
128
  parameters.select { |p| p[:in] == :path }.each do |p|
129
- unless example.respond_to?(p[:name])
129
+ unless example.respond_to?(extract_getter(p))
130
130
  raise ArgumentError.new("`#{p[:name].to_s}` parameter key present, but not defined within example group"\
131
131
  "(i. e `it` or `let` block)")
132
132
  end
133
- path_template.gsub!("{#{p[:name]}}", example.send(p[:name]).to_s)
133
+ path_template.gsub!("{#{p[:name]}}", example.send(extract_getter(p)).to_s)
134
134
  end
135
135
 
136
136
  parameters.select { |p| p[:in] == :query }.each_with_index do |p, i|
137
137
  path_template.concat(i.zero? ? '?' : '&')
138
- path_template.concat(build_query_string_part(p, example.send(p[:name]), swagger_doc))
138
+ path_template.concat(build_query_string_part(p, example.send(extract_getter(p)), swagger_doc))
139
139
  end
140
140
  end
141
141
  end
@@ -197,7 +197,7 @@ module Rswag
197
197
  def add_headers(request, metadata, swagger_doc, parameters, example)
198
198
  tuples = parameters
199
199
  .select { |p| p[:in] == :header }
200
- .map { |p| [p[:name], example.send(p[:name]).to_s] }
200
+ .map { |p| [p[:name], example.send(extract_getter(p)).to_s] }
201
201
 
202
202
  # Accept header
203
203
  produces = metadata[:operation][:produces] || swagger_doc[:produces]
@@ -255,7 +255,7 @@ module Rswag
255
255
  # PROS: simple to implement, CONS: serialization/deserialization is bypassed in test
256
256
  tuples = parameters
257
257
  .select { |p| p[:in] == :formData }
258
- .map { |p| [p[:name], example.send(p[:name])] }
258
+ .map { |p| [p[:name], example.send(extract_getter(p))] }
259
259
  Hash[tuples]
260
260
  end
261
261
 
@@ -272,6 +272,10 @@ module Rswag
272
272
  def doc_version(doc)
273
273
  doc[:openapi] || doc[:swagger] || '3'
274
274
  end
275
+
276
+ def extract_getter(parameter)
277
+ parameter[:getter] || parameter[:name]
278
+ end
275
279
  end
276
280
 
277
281
  class MissingParameterError < StandardError
@@ -62,7 +62,9 @@ module Rswag
62
62
  .merge('$schema' => 'http://tempuri.org/rswag/specs/extended_schema')
63
63
  .merge(schemas)
64
64
 
65
- errors = JSON::Validator.fully_validate(validation_schema, body)
65
+ validation_options = validation_options_from(metadata)
66
+
67
+ errors = JSON::Validator.fully_validate(validation_schema, body, validation_options)
66
68
  return unless errors.any?
67
69
 
68
70
  raise UnexpectedResponse,
@@ -70,6 +72,15 @@ module Rswag
70
72
  "Response body: #{JSON.pretty_generate(JSON.parse(body))}"
71
73
  end
72
74
 
75
+ def validation_options_from(metadata)
76
+ is_strict = !!metadata.fetch(
77
+ :swagger_strict_schema_validation,
78
+ @config.swagger_strict_schema_validation
79
+ )
80
+
81
+ { strict: is_strict }
82
+ end
83
+
73
84
  def definitions_or_component_schemas(swagger_doc, version)
74
85
  if version.start_with?('2')
75
86
  swagger_doc.slice(:definitions)
@@ -58,6 +58,7 @@ module Rswag
58
58
  if is_hash && value[:parameters]
59
59
  schema_param = value[:parameters]&.find { |p| (p[:in] == :body || p[:in] == :formData) && p[:schema] }
60
60
  mime_list = value[:consumes] || doc[:consumes]
61
+
61
62
  if value && schema_param && mime_list
62
63
  value[:requestBody] = { content: {} } unless value.dig(:requestBody, :content)
63
64
  value[:requestBody][:required] = true if schema_param[:required]
@@ -147,7 +148,7 @@ module Rswag
147
148
 
148
149
  target_node[:content] ||= {}
149
150
  mime_list.each do |mime_type|
150
- # TODO upgrade to have content-type specific schema
151
+ # TODO: upgrade to have content-type specific schema
151
152
  (target_node[:content][mime_type] ||= {}).merge!(schema: schema)
152
153
  end
153
154
  end
@@ -207,10 +208,12 @@ module Rswag
207
208
  end
208
209
 
209
210
  def remove_invalid_operation_keys!(value)
210
- is_hash = value.is_a?(Hash)
211
- value.delete(:consumes) if is_hash && value[:consumes]
212
- value.delete(:produces) if is_hash && value[:produces]
213
- value.delete(:request_examples) if is_hash && value[:request_examples]
211
+ return unless value.is_a?(Hash)
212
+
213
+ value.delete(:consumes) if value[:consumes]
214
+ value.delete(:produces) if value[:produces]
215
+ value.delete(:request_examples) if value[:request_examples]
216
+ value[:parameters].each { |p| p.delete(:getter) } if value[:parameters]
214
217
  end
215
218
  end
216
219
  end
data/lib/rswag/specs.rb CHANGED
@@ -14,6 +14,7 @@ module Rswag
14
14
  c.add_setting :swagger_docs
15
15
  c.add_setting :swagger_dry_run
16
16
  c.add_setting :swagger_format
17
+ c.add_setting :swagger_strict_schema_validation
17
18
  c.extend ExampleGroupHelpers, type: :request
18
19
  c.include ExampleHelpers, type: :request
19
20
  end
@@ -16,11 +16,13 @@ namespace :rswag do
16
16
  ''
17
17
  )
18
18
 
19
+ t.rspec_opts = [additional_rspec_opts]
20
+
19
21
  if Rswag::Specs::RSPEC_VERSION > 2 && Rswag::Specs.config.swagger_dry_run
20
- t.rspec_opts = ['--format Rswag::Specs::SwaggerFormatter', '--dry-run', '--order defined'] << additional_rspec_opts
22
+ t.rspec_opts += ['--format Rswag::Specs::SwaggerFormatter', '--dry-run', '--order defined']
21
23
  else
22
24
  ActiveSupport::Deprecation.warn('Rswag::Specs: WARNING: Support for RSpec 2.X will be dropped in v3.0')
23
- t.rspec_opts = ['--format Rswag::Specs::SwaggerFormatter', '--order defined']
25
+ t.rspec_opts += ['--format Rswag::Specs::SwaggerFormatter', '--order defined']
24
26
  end
25
27
  end
26
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rswag-specs
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richie Morris
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-11-16 00:00:00.000000000 Z
13
+ date: 2023-04-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport