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 +4 -4
- data/lib/generators/rspec/swagger_generator.rb +2 -1
- data/lib/rswag/specs/configuration.rb +4 -0
- data/lib/rswag/specs/example_group_helpers.rb +17 -9
- data/lib/rswag/specs/request_factory.rb +11 -7
- data/lib/rswag/specs/response_validator.rb +12 -1
- data/lib/rswag/specs/swagger_formatter.rb +8 -5
- data/lib/rswag/specs.rb +1 -0
- data/lib/tasks/rswag-specs_tasks.rake +4 -2
- 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: fa8f8005ed229944c19cb2e33e09eaebb95b8e32b9bef505a5e6b64b237bcbdc
|
|
4
|
+
data.tar.gz: 7eebf43807f0252c3168e08283b716c3dd9356f5d79fde1fcfc275377b5bc522
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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', '
|
|
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
|
-
|
|
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",
|
|
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",
|
|
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
|
|
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(/\{(.*?)\}/) {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
value.delete(:
|
|
213
|
-
value.delete(:
|
|
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
|
@@ -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
|
|
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
|
|
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.
|
|
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:
|
|
13
|
+
date: 2023-04-24 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: activesupport
|