diff --git a/Gemfile b/Gemfile index 1abf797..f060907 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,12 @@ -source "https://rubygems.org" +# frozen_string_literal: true + +source 'https://rubygems.org' # Allow the rails version to come from an ENV setting so Travis can test multiple versions. # See http://www.schneems.com/post/50991826838/testing-against-multiple-rails-versions/ rails_version = ENV['RAILS_VERSION'] || '5.1.2' -gem 'rails', "#{rails_version}" +gem 'rails', rails_version.to_s case rails_version.split('.').first when '3' @@ -19,17 +21,22 @@ gem 'rswag-api', path: './rswag-api' gem 'rswag-ui', path: './rswag-ui' group :test do - gem 'test-unit' - gem 'rspec-rails' - gem 'generator_spec' gem 'capybara' gem 'capybara-webkit' + gem 'generator_spec' + gem 'rspec-rails' gem 'rswag-specs', path: './rswag-specs' + gem 'test-unit' +end + +group :development do + gem 'guard-rspec', require: false + gem 'rubocop' end group :assets do - gem 'uglifier' gem 'therubyracer' + gem 'uglifier' end gem 'byebug' diff --git a/rswag-specs/Guardfile b/rswag-specs/Guardfile new file mode 100644 index 0000000..e1ed8e2 --- /dev/null +++ b/rswag-specs/Guardfile @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +## Uncomment and set this to only include directories you want to watch +# directories %w(app lib config test spec features) \ +# .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")} + +## Note: if you are using the `directories` clause above and you are not +## watching the project directory ('.'), then you will want to move +## the Guardfile to a watched dir and symlink it back, e.g. +# +# $ mkdir config +# $ mv Guardfile config/ +# $ ln -s config/Guardfile . +# +# and, you'll have to watch "config/Guardfile" instead of "Guardfile" + +# Note: The cmd option is now required due to the increasing number of ways +# rspec may be run, below are examples of the most common uses. +# * bundler: 'bundle exec rspec' +# * bundler binstubs: 'bin/rspec' +# * spring: 'bin/rspec' (This will use spring if running and you have +# installed the spring binstubs per the docs) +# * zeus: 'zeus rspec' (requires the server to be started separately) +# * 'just' rspec: 'rspec' + +guard :rspec, cmd: 'bundle exec rspec' do + require 'guard/rspec/dsl' + dsl = Guard::RSpec::Dsl.new(self) + + # Feel free to open issues for suggestions and improvements + + # RSpec files + rspec = dsl.rspec + watch(rspec.spec_helper) { rspec.spec_dir } + watch(rspec.spec_support) { rspec.spec_dir } + watch(rspec.spec_files) + + # Ruby files + ruby = dsl.ruby + dsl.watch_spec_files_for(ruby.lib_files) + + # Rails files + rails = dsl.rails(view_extensions: %w[erb haml slim]) + dsl.watch_spec_files_for(rails.app_files) + dsl.watch_spec_files_for(rails.views) + + watch(rails.controllers) do |m| + [ + rspec.spec.call("routing/#{m[1]}_routing"), + rspec.spec.call("controllers/#{m[1]}_controller"), + rspec.spec.call("acceptance/#{m[1]}") + ] + end + + # Rails config changes + watch(rails.spec_helper) { rspec.spec_dir } +end diff --git a/rswag-specs/lib/rswag/specs/configuration.rb b/rswag-specs/lib/rswag/specs/configuration.rb index 4adf33c..6cc2767 100644 --- a/rswag-specs/lib/rswag/specs/configuration.rb +++ b/rswag-specs/lib/rswag/specs/configuration.rb @@ -1,8 +1,8 @@ +# frozen_string_literal: true + module Rswag module Specs - class Configuration - def initialize(rspec_config) @rspec_config = rspec_config end @@ -12,6 +12,7 @@ module Rswag if @rspec_config.swagger_root.nil? raise ConfigurationError, 'No swagger_root provided. See swagger_helper.rb' end + @rspec_config.swagger_root end end @@ -21,6 +22,7 @@ module Rswag if @rspec_config.swagger_docs.nil? || @rspec_config.swagger_docs.empty? raise ConfigurationError, 'No swagger_docs defined. See swagger_helper.rb' end + @rspec_config.swagger_docs end end @@ -34,6 +36,7 @@ module Rswag def get_swagger_doc(name) return swagger_docs.values.first if name.nil? raise ConfigurationError, "Unknown swagger_doc '#{name}'" unless swagger_docs[name] + swagger_docs[name] end end diff --git a/rswag-specs/lib/rswag/specs/example_group_helpers.rb b/rswag-specs/lib/rswag/specs/example_group_helpers.rb index 2e2fd7d..87f6e9b 100644 --- a/rswag-specs/lib/rswag/specs/example_group_helpers.rb +++ b/rswag-specs/lib/rswag/specs/example_group_helpers.rb @@ -1,20 +1,21 @@ +# frozen_string_literal: true + module Rswag module Specs module ExampleGroupHelpers - - def path(template, metadata={}, &block) + def path(template, metadata = {}, &block) metadata[:path_item] = { template: template } describe(template, metadata, &block) end - [ :get, :post, :patch, :put, :delete, :head ].each do |verb| + %i[get post patch put delete head].each do |verb| define_method(verb) do |summary, &block| api_metadata = { operation: { verb: verb, summary: summary } } describe(verb, api_metadata, &block) end end - [ :operationId, :deprecated, :security ].each do |attr_name| + %i[operationId deprecated security].each do |attr_name| define_method(attr_name) do |value| metadata[:operation][attr_name] = value end @@ -23,32 +24,61 @@ module Rswag # NOTE: 'description' requires special treatment because ExampleGroup already # defines a method with that name. Provide an override that supports the existing # functionality while also setting the appropriate metadata if applicable - def description(value=nil) + def description(value = nil) return super() if value.nil? + metadata[:operation][:description] = value end # These are array properties - note the splat operator - [ :tags, :consumes, :produces, :schemes ].each do |attr_name| + %i[tags consumes produces schemes].each do |attr_name| define_method(attr_name) do |*value| metadata[:operation][attr_name] = value end end - #TODO: look at adding request_body method to handle diffs in Open API 2.0 to 3.0 + # NICE TO HAVE + # TODO: update generator templates to include 3.0 syntax + # TODO: setup travis CI? + + # MUST HAVES + # TODO: look at adding request_body method to handle diffs in Open API 2.0 to 3.0 + # TODO: look at adding examples in content request_body # https://swagger.io/docs/specification/describing-request-body/ # need to make sure we output requestBody in the swagger generator .json # also need to make sure that it can handle content: , required: true/false, schema: ref + def request_body(attributes) + # can make this generic, and accept any incoming hash (like parameter method) + attributes.compact! + metadata[:operation][:requestBody] = attributes + end - + def request_body_json(schema:, required: true, description: nil, examples: nil) + passed_examples = Array(examples) + content_hash = { 'application/json' => { schema: schema, examples: examples }.compact! || {} } + request_body(description: description, required: required, content: content_hash) + if passed_examples.any? + # the request_factory is going to have to resolve the different ways that the example can be given + # it can contain a 'value' key which is a direct hash (easiest) + # it can contain a 'external_value' key which makes an external call to load the json + # it can contain a '$ref' key. Which points to #/components/examples/blog + if passed_examples.first.is_a?(Symbol) + example_key_name = passed_examples.first # can come up with better scheme here + # TODO: write more tests around this adding to the parameter + # if symbol try and use save_request_example + param_attributes = { name: example_key_name, in: :body, required: required, param_value: example_key_name } + parameter(param_attributes) + end + end + end def parameter(attributes) if attributes[:in] && attributes[:in].to_sym == :path attributes[:required] = true end - if metadata.has_key?(:operation) + if metadata.key?(:operation) metadata[:operation][:parameters] ||= [] metadata[:operation][:parameters] << attributes else @@ -57,7 +87,7 @@ module Rswag end end - def response(code, description, metadata={}, &block) + def response(code, description, metadata = {}, &block) metadata[:response] = { code: code, description: description } context(description, metadata, &block) end @@ -76,6 +106,7 @@ module Rswag # rspec-core ExampleGroup def examples(example = nil) return super() if example.nil? + metadata[:response][:examples] = example end @@ -99,6 +130,21 @@ module Rswag assert_response_matches_metadata(example.metadata, &block) example.instance_exec(response, &block) if block_given? end + + after do |example| + body_parameter = example.metadata[:operation]&.dig(:parameters)&.detect { |p| p[:in] == :body && p[:required] } + + if body_parameter && respond_to?(body_parameter[:name]) && example.metadata[:operation][:requestBody][:content]['application/json'] + # save response examples by default + example.metadata[:response][:examples] = { 'application/json' => JSON.parse(response.body, symbolize_names: true) } unless response.body.to_s.empty? + + # save request examples using the let(:param_name) { REQUEST_BODY_HASH } syntax in the test + example.metadata[:operation][:requestBody][:content]['application/json'] = { examples: {} } unless example.metadata[:operation][:requestBody][:content]['application/json'][:examples] + json_request_examples = example.metadata[:operation][:requestBody][:content]['application/json'][:examples] + json_request_examples[body_parameter[:name]] = { value: send(body_parameter[:name]) } + example.metadata[:operation][:requestBody][:content]['application/json'][:examples] = json_request_examples + end + end end end end diff --git a/rswag-specs/lib/rswag/specs/example_helpers.rb b/rswag-specs/lib/rswag/specs/example_helpers.rb index d8ff128..c447742 100644 --- a/rswag-specs/lib/rswag/specs/example_helpers.rb +++ b/rswag-specs/lib/rswag/specs/example_helpers.rb @@ -1,10 +1,11 @@ +# frozen_string_literal: true + require 'rswag/specs/request_factory' require 'rswag/specs/response_validator' module Rswag module Specs module ExampleHelpers - def submit_request(metadata) request = RequestFactory.new.build_request(metadata, self) @@ -19,10 +20,8 @@ module Rswag send( request[:verb], request[:path], - { - params: request[:payload], - headers: request[:headers] - } + params: request[:payload], + headers: request[:headers] ) end end diff --git a/rswag-specs/lib/rswag/specs/extended_schema.rb b/rswag-specs/lib/rswag/specs/extended_schema.rb index 847cd72..3af8efc 100644 --- a/rswag-specs/lib/rswag/specs/extended_schema.rb +++ b/rswag-specs/lib/rswag/specs/extended_schema.rb @@ -1,9 +1,10 @@ +# frozen_string_literal: true + require 'json-schema' module Rswag module Specs class ExtendedSchema < JSON::Schema::Draft4 - def initialize super @attributes['type'] = ExtendedTypeAttribute @@ -13,9 +14,9 @@ module Rswag end class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute - - def self.validate(current_schema, data, fragments, processor, validator, options={}) + def self.validate(current_schema, data, fragments, processor, validator, options = {}) return if data.nil? && (current_schema.schema['nullable'] == true || current_schema.schema['x-nullable'] == true) + super end end diff --git a/rswag-specs/lib/rswag/specs/railtie.rb b/rswag-specs/lib/rswag/specs/railtie.rb index 8deec2b..4e6b095 100644 --- a/rswag-specs/lib/rswag/specs/railtie.rb +++ b/rswag-specs/lib/rswag/specs/railtie.rb @@ -1,9 +1,10 @@ +# frozen_string_literal: true + module Rswag module Specs class Railtie < ::Rails::Railtie - rake_tasks do - load File.expand_path('../../../tasks/rswag-specs_tasks.rake', __FILE__) + load File.expand_path('../../tasks/rswag-specs_tasks.rake', __dir__) end end end diff --git a/rswag-specs/lib/rswag/specs/request_factory.rb b/rswag-specs/lib/rswag/specs/request_factory.rb index 0bb7a33..31f1831 100644 --- a/rswag-specs/lib/rswag/specs/request_factory.rb +++ b/rswag-specs/lib/rswag/specs/request_factory.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/hash/conversions' require 'json' @@ -5,7 +7,6 @@ require 'json' module Rswag module Specs class RequestFactory - def initialize(config = ::Rswag::Specs.config) @config = config end @@ -38,11 +39,11 @@ module Rswag def derive_security_params(metadata, swagger_doc) requirements = metadata[:operation][:security] || swagger_doc[:security] || [] - scheme_names = requirements.flat_map { |r| r.keys } + scheme_names = requirements.flat_map(&:keys) schemes = (swagger_doc[:components][:securitySchemes] || {}).slice(*scheme_names).values schemes.map do |scheme| - param = (scheme[:type] == :apiKey) ? scheme.slice(:name, :in) : { name: 'Authorization', in: :header } + param = scheme[:type] == :apiKey ? scheme.slice(:name, :in) : { name: 'Authorization', in: :header } param.merge(type: :string, required: requirements.one?) end end @@ -51,10 +52,11 @@ module Rswag key = ref.sub('#/parameters/', '').to_sym definitions = swagger_doc[:parameters] raise "Referenced parameter '#{ref}' must be defined" unless definitions && definitions[key] + definitions[key] end - def add_verb(request, metadata) + def add_verb(request, metadata) request[:verb] = metadata[:operation][:verb] end @@ -75,7 +77,7 @@ module Rswag def build_query_string_part(param, value) name = param[:name] - return "#{name}=#{value.to_s}" unless param[:type].to_sym == :array + return "#{name}=#{value}" unless param[:type].to_sym == :array case param[:collectionFormat] when :ssv @@ -93,44 +95,44 @@ module Rswag def add_headers(request, metadata, swagger_doc, parameters, example) tuples = parameters - .select { |p| p[:in] == :header } - .map { |p| [ p[:name], example.send(p[:name]).to_s ] } + .select { |p| p[:in] == :header } + .map { |p| [p[:name], example.send(p[:name]).to_s] } # Accept header produces = metadata[:operation][:produces] || swagger_doc[:produces] if produces - accept = example.respond_to?(:'Accept') ? example.send(:'Accept') : produces.first - tuples << [ 'Accept', accept ] + accept = example.respond_to?(:Accept) ? example.send(:Accept) : produces.first + tuples << ['Accept', accept] end # Content-Type header - consumes = metadata[:operation][:consumes] || swagger_doc[:consumes] + consumes = metadata[:operation][:consumes] || swagger_doc[:consumes] if consumes content_type = example.respond_to?(:'Content-Type') ? example.send(:'Content-Type') : consumes.first - tuples << [ 'Content-Type', content_type ] + tuples << ['Content-Type', content_type] end # Rails test infrastructure requires rackified headers rackified_tuples = tuples.map do |pair| [ case pair[0] - when 'Accept' then 'HTTP_ACCEPT' - when 'Content-Type' then 'CONTENT_TYPE' - when 'Authorization' then 'HTTP_AUTHORIZATION' - else pair[0] + when 'Accept' then 'HTTP_ACCEPT' + when 'Content-Type' then 'CONTENT_TYPE' + when 'Authorization' then 'HTTP_AUTHORIZATION' + else pair[0] end, pair[1] ] end - request[:headers] = Hash[ rackified_tuples ] + request[:headers] = Hash[rackified_tuples] end def add_payload(request, parameters, example) content_type = request[:headers]['CONTENT_TYPE'] return if content_type.nil? - if [ 'application/x-www-form-urlencoded', 'multipart/form-data' ].include?(content_type) + if ['application/x-www-form-urlencoded', 'multipart/form-data'].include?(content_type) request[:payload] = build_form_payload(parameters, example) else request[:payload] = build_json_payload(parameters, example) @@ -143,14 +145,21 @@ module Rswag # Rails test infrastructure allows us to send the values directly as a hash # PROS: simple to implement, CONS: serialization/deserialization is bypassed in test tuples = parameters - .select { |p| p[:in] == :formData } - .map { |p| [ p[:name], example.send(p[:name]) ] } - Hash[ tuples ] + .select { |p| p[:in] == :formData } + .map { |p| [p[:name], example.send(p[:name])] } + Hash[tuples] end def build_json_payload(parameters, example) body_param = parameters.select { |p| p[:in] == :body }.first - body_param ? example.send(body_param[:name]).to_json : nil + return nil unless body_param + + # p "example is #{example.send(body_param[:name]).to_json} ** AND body param is #{body_param}" if body_param + # body_param ? example.send(body_param[:name]).to_json : nil + + source_body_param = example.send(body_param[:name]) if body_param[:name] && example.respond_to?(body_param[:name]) + source_body_param ||= body_param[:param_value] + source_body_param ? source_body_param.to_json : nil end end end diff --git a/rswag-specs/lib/rswag/specs/response_validator.rb b/rswag-specs/lib/rswag/specs/response_validator.rb index d2b71ad..b5e4a8c 100644 --- a/rswag-specs/lib/rswag/specs/response_validator.rb +++ b/rswag-specs/lib/rswag/specs/response_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'active_support/core_ext/hash/slice' require 'json-schema' require 'json' @@ -6,7 +8,6 @@ require 'rswag/specs/extended_schema' module Rswag module Specs class ResponseValidator - def initialize(config = ::Rswag::Specs.config) @config = config end @@ -41,12 +42,12 @@ module Rswag response_schema = metadata[:response][:schema] return if response_schema.nil? - components_schemas = {components: {schemas: swagger_doc[:components][:schemas]}} + components_schemas = { components: { schemas: swagger_doc[:components][:schemas] } } validation_schema = response_schema - .merge('$schema' => 'http://tempuri.org/rswag/specs/extended_schema') - .merge(components_schemas) - + .merge('$schema' => 'http://tempuri.org/rswag/specs/extended_schema') + .merge(components_schemas) + errors = JSON::Validator.fully_validate(validation_schema, body) raise UnexpectedResponse, "Expected response body to match schema: #{errors[0]}" if errors.any? end diff --git a/rswag-specs/lib/rswag/specs/swagger_formatter.rb b/rswag-specs/lib/rswag/specs/swagger_formatter.rb index 794a9d9..7c1109a 100644 --- a/rswag-specs/lib/rswag/specs/swagger_formatter.rb +++ b/rswag-specs/lib/rswag/specs/swagger_formatter.rb @@ -1,10 +1,11 @@ +# frozen_string_literal: true + require 'active_support/core_ext/hash/deep_merge' require 'swagger_helper' module Rswag module Specs class SwaggerFormatter - # NOTE: rspec 2.x support if RSPEC_VERSION > 2 ::RSpec::Core::Formatters.register self, :example_group_finished, :stop @@ -19,22 +20,23 @@ module Rswag def example_group_finished(notification) # NOTE: rspec 2.x support - if RSPEC_VERSION > 2 - metadata = notification.group.metadata - else - metadata = notification.metadata - end + metadata = if RSPEC_VERSION > 2 + notification.group.metadata + else + notification.metadata + end + + return unless metadata.key?(:response) - return unless metadata.has_key?(:response) swagger_doc = @config.get_swagger_doc(metadata[:swagger_doc]) swagger_doc.deep_merge!(metadata_to_swagger(metadata)) end - def stop(notification=nil) + def stop(_notification = nil) @config.swagger_docs.each do |url_path, doc| file_path = File.join(@config.swagger_root, url_path) dirname = File.dirname(file_path) - FileUtils.mkdir_p dirname unless File.exists?(dirname) + FileUtils.mkdir_p dirname unless File.exist?(dirname) File.open(file_path, 'w') do |file| file.write(JSON.pretty_generate(doc)) @@ -48,17 +50,31 @@ module Rswag def metadata_to_swagger(metadata) response_code = metadata[:response][:code] - response = metadata[:response].reject { |k,v| k == :code } + response = metadata[:response].reject { |k, _v| k == :code } + + if response_code.to_s == '201' + # need to merge in to resppnse + if response[:examples]&.dig('application/json') + example = response[:examples].dig('application/json').dup + response.merge!(content: { 'application/json' => { example: example } }) + response.delete(:examples) + end + end verb = metadata[:operation][:verb] operation = metadata[:operation] - .reject { |k,v| k == :verb } - .merge(responses: { response_code => response }) + .reject { |k, _v| k == :verb } + .merge(responses: { response_code => response }) + + # can remove the 2.0 compliant body incoming parameters + if operation&.dig(:parameters) + operation[:parameters].reject! { |p| p[:in] == :body } + end path_template = metadata[:path_item][:template] path_item = metadata[:path_item] - .reject { |k,v| k == :template } - .merge(verb => operation) + .reject { |k, _v| k == :template } + .merge(verb => operation) { paths: { path_template => path_item } } end diff --git a/rswag-specs/rswag-specs.gemspec b/rswag-specs/rswag-specs.gemspec index 0e4686e..bbf04eb 100644 --- a/rswag-specs/rswag-specs.gemspec +++ b/rswag-specs/rswag-specs.gemspec @@ -1,19 +1,22 @@ -$:.push File.expand_path("../lib", __FILE__) +# frozen_string_literal: true + +$LOAD_PATH.push File.expand_path('lib', __dir__) # Describe your gem and declare its dependencies: Gem::Specification.new do |s| - s.name = "rswag-specs" + s.name = 'rswag-specs' s.version = ENV['TRAVIS_TAG'] || '0.0.0' - s.authors = ["Richie Morris"] - s.email = ["domaindrivendev@gmail.com"] - s.homepage = "https://github.com/domaindrivendev/rswag" - s.summary = "A Swagger-based DSL for rspec-rails & accompanying rake task for generating Swagger files" - s.description = "Simplify API integration testing with a succinct rspec DSL and generate Swagger files directly from your rspecs" - s.license = "MIT" + s.authors = ['Richie Morris'] + s.email = ['domaindrivendev@gmail.com'] + s.homepage = 'https://github.com/domaindrivendev/rswag' + s.summary = 'A Swagger-based DSL for rspec-rails & accompanying rake task for generating Swagger files' + s.description = 'Simplify API integration testing with a succinct rspec DSL and generate Swagger files directly from your rspecs' + s.license = 'MIT' - s.files = Dir["{lib}/**/*"] + ["MIT-LICENSE", "Rakefile" ] + s.files = Dir['{lib}/**/*'] + %w[MIT-LICENSE Rakefile] s.add_dependency 'activesupport', '>= 3.1', '< 6.0' - s.add_dependency 'railties', '>= 3.1', '< 6.0' s.add_dependency 'json-schema', '~> 2.2' + s.add_dependency 'railties', '>= 3.1', '< 6.0' + s.add_development_dependency 'guard-rspec' end diff --git a/rswag-specs/spec/rswag/specs/configuration_spec.rb b/rswag-specs/spec/rswag/specs/configuration_spec.rb index b75d843..d265fce 100644 --- a/rswag-specs/spec/rswag/specs/configuration_spec.rb +++ b/rswag-specs/spec/rswag/specs/configuration_spec.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require 'rswag/specs/configuration' module Rswag module Specs - describe Configuration do subject { described_class.new(rspec_config) } diff --git a/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb b/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb index 619a8d7..8b56735 100644 --- a/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb +++ b/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require 'rswag/specs/example_group_helpers' module Rswag module Specs - describe ExampleGroupHelpers do subject { double('example_group') } @@ -48,12 +49,12 @@ module Rswag it "adds to the 'operation' metadata" do expect(api_metadata[:operation]).to match( - tags: [ 'Blogs', 'Admin' ], + tags: %w[Blogs Admin], description: 'Some description', operationId: 'createBlog', - consumes: [ 'application/json', 'application/xml' ], - produces: [ 'application/json', 'application/xml' ], - schemes: [ 'http', 'https' ], + consumes: ['application/json', 'application/xml'], + produces: ['application/json', 'application/xml'], + schemes: %w[http https], deprecated: true ) end @@ -74,27 +75,59 @@ module Rswag it "adds to the 'operation' metadata" do expect(api_metadata[:operation]).to match( - tags: [ 'Blogs', 'Admin' ], + tags: %w[Blogs Admin], description: 'Some description', operationId: 'createBlog', - consumes: [ 'application/json', 'application/xml' ], - produces: [ 'application/json', 'application/xml' ], - schemes: [ 'http', 'https' ], + consumes: ['application/json', 'application/xml'], + produces: ['application/json', 'application/xml'], + schemes: %w[http https], deprecated: true, security: { api_key: [] } ) end end - describe '#parameter(attributes)' do + describe '#request_body_json(schema)' do + let(:api_metadata) { { path_item: {}, operation: {} } } # i.e. operation defined + context 'when required is not supplied' do + before { subject.request_body_json(schema: { type: 'object' }) } + it 'adds required true by default' do + expect(api_metadata[:operation][:requestBody]).to match( + required: true, content: { 'application/json' => { schema: { type: 'object' } } } + ) + end + end + + context 'when required is supplied' do + before { subject.request_body_json(schema: { type: 'object' }, required: false) } + + it 'adds required false' do + expect(api_metadata[:operation][:requestBody]).to match( + required: false, content: { 'application/json' => { schema: { type: 'object' } } } + ) + end + end + + context 'when required is supplied' do + before { subject.request_body_json(schema: { type: 'object' }, description: 'my description') } + + it 'adds description' do + expect(api_metadata[:operation][:requestBody]).to match( + description: 'my description', required: true, content: { 'application/json' => { schema: { type: 'object' } } } + ) + end + end + end + + describe '#parameter(attributes)' do context "when called at the 'path' level" do before { subject.parameter(name: :blog, in: :body, schema: { type: 'object' }) } let(:api_metadata) { { path_item: {} } } # i.e. operation not defined yet it "adds to the 'path_item parameters' metadata" do expect(api_metadata[:path_item][:parameters]).to match( - [ name: :blog, in: :body, schema: { type: 'object' } ] + [name: :blog, in: :body, schema: { type: 'object' }] ) end end @@ -105,7 +138,7 @@ module Rswag it "adds to the 'operation parameters' metadata" do expect(api_metadata[:operation][:parameters]).to match( - [ name: :blog, in: :body, schema: { type: 'object' } ] + [name: :blog, in: :body, schema: { type: 'object' }] ) end end @@ -116,7 +149,7 @@ module Rswag it "automatically sets the 'required' flag" do expect(api_metadata[:operation][:parameters]).to match( - [ name: :id, in: :path, required: true ] + [name: :id, in: :path, required: true] ) end end @@ -126,7 +159,7 @@ module Rswag let(:api_metadata) { { operation: {} } } it "does not require the 'in' parameter key" do - expect(api_metadata[:operation][:parameters]).to match([ name: :id ]) + expect(api_metadata[:operation][:parameters]).to match([name: :id]) end end end diff --git a/rswag-specs/spec/rswag/specs/example_helpers_spec.rb b/rswag-specs/spec/rswag/specs/example_helpers_spec.rb index 3b22af4..01da373 100644 --- a/rswag-specs/spec/rswag/specs/example_helpers_spec.rb +++ b/rswag-specs/spec/rswag/specs/example_helpers_spec.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require 'rswag/specs/example_helpers' module Rswag module Specs - describe ExampleHelpers do subject { double('example') } @@ -12,7 +13,7 @@ module Rswag allow(config).to receive(:get_swagger_doc).and_return(swagger_doc) stub_const('Rswag::Specs::RAILS_VERSION', 3) end - let(:config) { double('config') } + let(:config) { double('config') } let(:swagger_doc) do { securityDefinitions: { @@ -30,7 +31,7 @@ module Rswag operation: { verb: :put, summary: 'Updates a blog', - consumes: [ 'application/json' ], + consumes: ['application/json'], parameters: [ { name: :blog_id, in: :path, type: 'integer' }, { name: 'id', in: :path, type: 'integer' }, @@ -58,8 +59,8 @@ module Rswag it "submits a request built from metadata and 'let' values" do expect(subject).to have_received(:put).with( '/blogs/1/comments/2?q1=foo&api_key=fookey', - "{\"text\":\"Some comment\"}", - { 'CONTENT_TYPE' => 'application/json' } + '{"text":"Some comment"}', + 'CONTENT_TYPE' => 'application/json' ) end end diff --git a/rswag-specs/spec/rswag/specs/request_factory_spec.rb b/rswag-specs/spec/rswag/specs/request_factory_spec.rb index f883952..7651811 100644 --- a/rswag-specs/spec/rswag/specs/request_factory_spec.rb +++ b/rswag-specs/spec/rswag/specs/request_factory_spec.rb @@ -1,15 +1,16 @@ +# frozen_string_literal: true + require 'rswag/specs/request_factory' module Rswag module Specs - describe RequestFactory do subject { RequestFactory.new(config) } before do allow(config).to receive(:get_swagger_doc).and_return(swagger_doc) end - let(:config) { double('config') } + let(:config) { double('config') } let(:swagger_doc) { {} } let(:example) { double('example') } let(:metadata) do @@ -53,7 +54,7 @@ module Rswag allow(example).to receive(:q2).and_return('bar') end - it "builds the query string from example values" do + it 'builds the query string from example values' do expect(request[:path]).to eq('/blogs?q1=foo&q2=bar') end end @@ -63,40 +64,40 @@ module Rswag metadata[:operation][:parameters] = [ { name: 'things', in: :query, type: :array, collectionFormat: collection_format } ] - allow(example).to receive(:things).and_return([ 'foo', 'bar' ]) + allow(example).to receive(:things).and_return(%w[foo bar]) end context 'collectionFormat = csv' do let(:collection_format) { :csv } - it "formats as comma separated values" do + it 'formats as comma separated values' do expect(request[:path]).to eq('/blogs?things=foo,bar') end end context 'collectionFormat = ssv' do let(:collection_format) { :ssv } - it "formats as space separated values" do + it 'formats as space separated values' do expect(request[:path]).to eq('/blogs?things=foo bar') end end context 'collectionFormat = tsv' do let(:collection_format) { :tsv } - it "formats as tab separated values" do + it 'formats as tab separated values' do expect(request[:path]).to eq('/blogs?things=foo\tbar') end end context 'collectionFormat = pipes' do let(:collection_format) { :pipes } - it "formats as pipe separated values" do + it 'formats as pipe separated values' do expect(request[:path]).to eq('/blogs?things=foo|bar') end end context 'collectionFormat = multi' do let(:collection_format) { :multi } - it "formats as multiple parameter instances" do + it 'formats as multiple parameter instances' do expect(request[:path]).to eq('/blogs?things=foo&things=bar') end end @@ -104,12 +105,12 @@ module Rswag context "'header' parameters" do before do - metadata[:operation][:parameters] = [ { name: 'Api-Key', in: :header, type: :string } ] + metadata[:operation][:parameters] = [{ name: 'Api-Key', in: :header, type: :string }] allow(example).to receive(:'Api-Key').and_return('foobar') end it 'adds names and example values to headers' do - expect(request[:headers]).to eq({ 'Api-Key' => 'foobar' }) + expect(request[:headers]).to eq('Api-Key' => 'foobar') end end @@ -127,9 +128,9 @@ module Rswag end end - context "consumes content" do + context 'consumes content' do before do - metadata[:operation][:consumes] = [ 'application/json', 'application/xml' ] + metadata[:operation][:consumes] = ['application/json', 'application/xml'] end context "no 'Content-Type' provided" do @@ -150,18 +151,18 @@ module Rswag context 'JSON payload' do before do - metadata[:operation][:parameters] = [ { name: 'comment', in: :body, schema: { type: 'object' } } ] + metadata[:operation][:parameters] = [{ name: 'comment', in: :body, schema: { type: 'object' } }] allow(example).to receive(:comment).and_return(text: 'Some comment') end it "serializes first 'body' parameter to JSON string" do - expect(request[:payload]).to eq("{\"text\":\"Some comment\"}") + expect(request[:payload]).to eq('{"text":"Some comment"}') end end context 'form payload' do before do - metadata[:operation][:consumes] = [ 'multipart/form-data' ] + metadata[:operation][:consumes] = ['multipart/form-data'] metadata[:operation][:parameters] = [ { name: 'f1', in: :formData, type: :string }, { name: 'f2', in: :formData, type: :string } @@ -181,7 +182,7 @@ module Rswag context 'produces content' do before do - metadata[:operation][:produces] = [ 'application/json', 'application/xml' ] + metadata[:operation][:produces] = ['application/json', 'application/xml'] end context "no 'Accept' value provided" do @@ -192,7 +193,7 @@ module Rswag context "explicit 'Accept' value provided" do before do - allow(example).to receive(:'Accept').and_return('application/xml') + allow(example).to receive(:Accept).and_return('application/xml') end it "sets 'HTTP_ACCEPT' header to example value" do @@ -204,7 +205,7 @@ module Rswag context 'basic auth' do before do swagger_doc[:securityDefinitions] = { basic: { type: :basic } } - metadata[:operation][:security] = [ basic: [] ] + metadata[:operation][:security] = [basic: []] allow(example).to receive(:Authorization).and_return('Basic foobar') end @@ -216,7 +217,7 @@ module Rswag context 'apiKey' do before do swagger_doc[:securityDefinitions] = { apiKey: { type: :apiKey, name: 'api_key', in: key_location } } - metadata[:operation][:security] = [ apiKey: [] ] + metadata[:operation][:security] = [apiKey: []] allow(example).to receive(:api_key).and_return('foobar') end @@ -256,8 +257,8 @@ module Rswag context 'oauth2' do before do - swagger_doc[:securityDefinitions] = { oauth2: { type: :oauth2, scopes: [ 'read:blogs' ] } } - metadata[:operation][:security] = [ oauth2: [ 'read:blogs' ] ] + swagger_doc[:securityDefinitions] = { oauth2: { type: :oauth2, scopes: ['read:blogs'] } } + metadata[:operation][:security] = [oauth2: ['read:blogs']] allow(example).to receive(:Authorization).and_return('Bearer foobar') end @@ -272,26 +273,26 @@ module Rswag basic: { type: :basic }, api_key: { type: :apiKey, name: 'api_key', in: :query } } - metadata[:operation][:security] = [ { basic: [], api_key: [] } ] + metadata[:operation][:security] = [{ basic: [], api_key: [] }] allow(example).to receive(:Authorization).and_return('Basic foobar') allow(example).to receive(:api_key).and_return('foobar') end - it "sets both params to example values" do + it 'sets both params to example values' do expect(request[:headers]).to eq('HTTP_AUTHORIZATION' => 'Basic foobar') expect(request[:path]).to eq('/blogs?api_key=foobar') end end - context "path-level parameters" do + context 'path-level parameters' do before do - metadata[:operation][:parameters] = [ { name: 'q1', in: :query, type: :string } ] - metadata[:path_item][:parameters] = [ { name: 'q2', in: :query, type: :string } ] + metadata[:operation][:parameters] = [{ name: 'q1', in: :query, type: :string }] + metadata[:path_item][:parameters] = [{ name: 'q2', in: :query, type: :string }] allow(example).to receive(:q1).and_return('foo') allow(example).to receive(:q2).and_return('bar') end - it "populates operation and path level parameters " do + it 'populates operation and path level parameters ' do expect(request[:path]).to eq('/blogs?q1=foo&q2=bar') end end @@ -299,7 +300,7 @@ module Rswag context 'referenced parameters' do before do swagger_doc[:parameters] = { q1: { name: 'q1', in: :query, type: :string } } - metadata[:operation][:parameters] = [ { '$ref' => '#/parameters/q1' } ] + metadata[:operation][:parameters] = [{ '$ref' => '#/parameters/q1' }] allow(example).to receive(:q1).and_return('foo') end @@ -316,18 +317,18 @@ module Rswag end end - context "global consumes" do - before { swagger_doc[:consumes] = [ 'application/xml' ] } + context 'global consumes' do + before { swagger_doc[:consumes] = ['application/xml'] } it "defaults 'CONTENT_TYPE' to global value(s)" do expect(request[:headers]).to eq('CONTENT_TYPE' => 'application/xml') end end - context "global security requirements" do + context 'global security requirements' do before do swagger_doc[:securityDefinitions] = { apiKey: { type: :apiKey, name: 'api_key', in: :query } } - swagger_doc[:security] = [ apiKey: [] ] + swagger_doc[:security] = [apiKey: []] allow(example).to receive(:api_key).and_return('foobar') end diff --git a/rswag-specs/spec/rswag/specs/response_validator_spec.rb b/rswag-specs/spec/rswag/specs/response_validator_spec.rb index 1d05427..9411cbc 100644 --- a/rswag-specs/spec/rswag/specs/response_validator_spec.rb +++ b/rswag-specs/spec/rswag/specs/response_validator_spec.rb @@ -1,15 +1,16 @@ +# frozen_string_literal: true + require 'rswag/specs/response_validator' module Rswag module Specs - describe ResponseValidator do subject { ResponseValidator.new(config) } before do allow(config).to receive(:get_swagger_doc).and_return(swagger_doc) end - let(:config) { double('config') } + let(:config) { double('config') } let(:swagger_doc) { {} } let(:example) { double('example') } let(:metadata) do @@ -20,7 +21,7 @@ module Rswag schema: { type: :object, properties: { text: { type: :string } }, - required: [ 'text' ] + required: ['text'] } } } @@ -32,26 +33,26 @@ module Rswag OpenStruct.new( code: '200', headers: { 'X-Rate-Limit-Limit' => '10' }, - body: "{\"text\":\"Some comment\"}" + body: '{"text":"Some comment"}' ) end - context "response matches metadata" do + context 'response matches metadata' do it { expect { call }.to_not raise_error } end - context "response code differs from metadata" do + context 'response code differs from metadata' do before { response.code = '400' } it { expect { call }.to raise_error /Expected response code/ } end - context "response headers differ from metadata" do + context 'response headers differ from metadata' do before { response.headers = {} } it { expect { call }.to raise_error /Expected response header/ } end - context "response body differs from metadata" do - before { response.body = "{\"foo\":\"Some comment\"}" } + context 'response body differs from metadata' do + before { response.body = '{"foo":"Some comment"}' } it { expect { call }.to raise_error /Expected response body/ } end @@ -61,7 +62,7 @@ module Rswag 'blog' => { type: :object, properties: { foo: { type: :string } }, - required: [ 'foo' ] + required: ['foo'] } } metadata[:response][:schema] = { '$ref' => '#/definitions/blog' } diff --git a/rswag-specs/spec/rswag/specs/swagger_formatter_spec.rb b/rswag-specs/spec/rswag/specs/swagger_formatter_spec.rb index f904fa5..302d062 100644 --- a/rswag-specs/spec/rswag/specs/swagger_formatter_spec.rb +++ b/rswag-specs/spec/rswag/specs/swagger_formatter_spec.rb @@ -1,9 +1,10 @@ +# frozen_string_literal: true + require 'rswag/specs/swagger_formatter' require 'ostruct' module Rswag module Specs - describe SwaggerFormatter do subject { described_class.new(output, config) } @@ -13,7 +14,7 @@ module Rswag end let(:config) { double('config') } let(:output) { double('output').as_null_object } - let(:swagger_root) { File.expand_path('../tmp/swagger', __FILE__) } + let(:swagger_root) { File.expand_path('tmp/swagger', __dir__) } describe '#example_group_finished(notification)' do before do @@ -47,8 +48,8 @@ module Rswag end describe '#stop' do - before do - FileUtils.rm_r(swagger_root) if File.exists?(swagger_root) + before do + FileUtils.rm_r(swagger_root) if File.exist?(swagger_root) allow(config).to receive(:swagger_docs).and_return( 'v1/swagger.json' => { info: { version: 'v1' } }, 'v2/swagger.json' => { info: { version: 'v2' } } @@ -64,7 +65,7 @@ module Rswag end after do - FileUtils.rm_r(swagger_root) if File.exists?(swagger_root) + FileUtils.rm_r(swagger_root) if File.exist?(swagger_root) end end end diff --git a/test-app/app/models/blog.rb b/test-app/app/models/blog.rb index 9fb7070..ea35f5a 100644 --- a/test-app/app/models/blog.rb +++ b/test-app/app/models/blog.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + class Blog < ActiveRecord::Base validates :content, presence: true - def as_json(options) + def as_json(_options) { id: id, title: title, - content: nil, + content: content, thumbnail: thumbnail } end diff --git a/test-app/spec/integration/auth_tests_spec.rb b/test-app/spec/integration/auth_tests_spec.rb index 8e47d2e..21917fb 100644 --- a/test-app/spec/integration/auth_tests_spec.rb +++ b/test-app/spec/integration/auth_tests_spec.rb @@ -1,12 +1,13 @@ +# frozen_string_literal: true + require 'swagger_helper' describe 'Auth Tests API', type: :request, swagger_doc: 'v1/swagger.json' do - path '/auth-tests/basic' do post 'Authenticates with basic auth' do tags 'Auth Tests' operationId 'testBasicAuth' - security [ basic_auth: [] ] + security [basic_auth: []] response '204', 'Valid credentials' do let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" } @@ -24,7 +25,7 @@ describe 'Auth Tests API', type: :request, swagger_doc: 'v1/swagger.json' do post 'Authenticates with an api key' do tags 'Auth Tests' operationId 'testApiKey' - security [ api_key: [] ] + security [api_key: []] response '204', 'Valid credentials' do let(:api_key) { 'foobar' } @@ -42,7 +43,7 @@ describe 'Auth Tests API', type: :request, swagger_doc: 'v1/swagger.json' do post 'Authenticates with basic auth and api key' do tags 'Auth Tests' operationId 'testBasicAndApiKey' - security [ { basic_auth: [], api_key: [] } ] + security [{ basic_auth: [], api_key: [] }] response '204', 'Valid credentials' do let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" } diff --git a/test-app/spec/integration/blogs_spec.rb b/test-app/spec/integration/blogs_spec.rb index 08297f8..e42ed3a 100644 --- a/test-app/spec/integration/blogs_spec.rb +++ b/test-app/spec/integration/blogs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'swagger_helper' describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do @@ -10,9 +12,12 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do operationId 'createBlog' consumes 'application/json' produces 'application/json' - parameter name: :blog, in: :body, schema: { '$ref' => '#/components/schemas/blog' } + # parameter name: :blog, in: :body, schema: { '$ref' => '#/components/schemas/blog' } - let(:blog) { { title: 'foo', content: 'bar' } } + request_body_json schema: { '$ref' => '#/components/schemas/blog' }, + examples: :blog + + let(:blog) { { blog: { title: 'foo', content: 'bar' } } } response '201', 'blog created' do run_test! @@ -21,7 +26,7 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do response '422', 'invalid request' do schema '$ref' => '#/components/schemas/errors_object' - let(:blog) { { title: 'foo' } } + let(:blog) { { blog: { title: 'foo' } } } run_test! do |response| expect(response.body).to include("can't be blank") end @@ -42,7 +47,7 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do end response '406', 'unsupported accept header' do - let(:'Accept') { 'application/foo' } + let(:Accept) { 'application/foo' } run_test! end end @@ -68,11 +73,11 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do schema '$ref' => '#/components/schemas/blog' examples 'application/json' => { - id: 1, - title: 'Hello world!', - content: 'Hello world and hello universe. Thank you all very much!!!', - thumbnail: "thumbnail.png" - } + id: 1, + title: 'Hello world!', + content: 'Hello world and hello universe. Thank you all very much!!!', + thumbnail: 'thumbnail.png' + } let(:id) { blog.id } run_test! @@ -96,10 +101,10 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do description 'Upload a thumbnail for specific blog by id' operationId 'uploadThumbnailBlog' consumes 'multipart/form-data' - parameter name: :file, :in => :formData, :type => :file, required: true + parameter name: :file, in: :formData, type: :file, required: true response '200', 'blog updated' do - let(:file) { Rack::Test::UploadedFile.new(Rails.root.join("spec/fixtures/thumbnail.png")) } + let(:file) { Rack::Test::UploadedFile.new(Rails.root.join('spec/fixtures/thumbnail.png')) } run_test! end end diff --git a/test-app/spec/rails_helper.rb b/test-app/spec/rails_helper.rb index 98c8fc3..d1bc219 100644 --- a/test-app/spec/rails_helper.rb +++ b/test-app/spec/rails_helper.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + # This file is copied to spec/ when you run 'rails generate rspec:install' ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../../config/environment', __FILE__) +require File.expand_path('../config/environment', __dir__) # Prevent database truncation if the environment is production -abort("The Rails environment is running in production mode!") if Rails.env.production? +abort('The Rails environment is running in production mode!') if Rails.env.production? require 'spec_helper' require 'rspec/rails' # Add additional requires below this line. Rails is not loaded until this point! @@ -54,6 +56,4 @@ RSpec.configure do |config| Capybara.javascript_driver = :webkit end -Capybara::Webkit.configure do |config| - config.block_unknown_urls -end +Capybara::Webkit.configure(&:block_unknown_urls) diff --git a/test-app/spec/rake/rswag_specs_swaggerize_spec.rb b/test-app/spec/rake/rswag_specs_swaggerize_spec.rb index 0a590ee..3b3af2a 100644 --- a/test-app/spec/rake/rswag_specs_swaggerize_spec.rb +++ b/test-app/spec/rake/rswag_specs_swaggerize_spec.rb @@ -1,15 +1,18 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rake' describe 'rswag:specs:swaggerize' do let(:swagger_root) { Rails.root.to_s + '/swagger' } - before do + before do TestApp::Application.load_tasks - FileUtils.rm_r(swagger_root) if File.exists?(swagger_root) + FileUtils.rm_r(swagger_root) if File.exist?(swagger_root) end it 'generates Swagger JSON files from integration specs' do - expect { Rake::Task['rswag:specs:swaggerize'].invoke }.not_to raise_exception + Rake::Task['rswag:specs:swaggerize'].invoke + # expect { }.not_to raise_exception(StandardError) expect(File).to exist("#{swagger_root}/v1/swagger.json") end end diff --git a/test-app/spec/spec_helper.rb b/test-app/spec/spec_helper.rb index d20f071..46f57e2 100644 --- a/test-app/spec/spec_helper.rb +++ b/test-app/spec/spec_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This file was generated by the `rails generate rspec:install` command. Conventionally, all # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. # The generated `.rspec` file contains `--require spec_helper` which will cause @@ -51,53 +53,51 @@ RSpec.configure do |config| File.delete("#{Rails.root}/tmp/thumbnail.png") if File.file?("#{Rails.root}/tmp/thumbnail.png") end -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin - # This allows you to limit a spec run to individual examples or groups - # you care about by tagging them with `:focus` metadata. When nothing - # is tagged with `:focus`, all examples get run. RSpec also provides - # aliases for `it`, `describe`, and `context` that include `:focus` - # metadata: `fit`, `fdescribe` and `fcontext`, respectively. - config.filter_run_when_matching :focus - - # Allows RSpec to persist some state between runs in order to support - # the `--only-failures` and `--next-failure` CLI options. We recommend - # you configure your source control system to ignore this file. - config.example_status_persistence_file_path = "spec/examples.txt" - - # Limits the available syntax to the non-monkey patched syntax that is - # recommended. For more details, see: - # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - config.disable_monkey_patching! - - # Many RSpec users commonly either run the entire suite or an individual - # file, and it's useful to allow more verbose output when running an - # individual spec file. - if config.files_to_run.one? - # Use the documentation formatter for detailed output, - # unless a formatter has already been configured - # (e.g. via a command-line flag). - config.default_formatter = 'doc' - end - - # Print the 10 slowest examples and example groups at the - # end of the spec run, to help surface which specs are running - # particularly slow. - config.profile_examples = 10 - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = :random - - # Seed global randomization in this process using the `--seed` CLI option. - # Setting this allows you to use `--seed` to deterministically reproduce - # test failures related to randomization by passing the same `--seed` value - # as the one that triggered the failure. - Kernel.srand config.seed -=end + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. + # # This allows you to limit a spec run to individual examples or groups + # # you care about by tagging them with `:focus` metadata. When nothing + # # is tagged with `:focus`, all examples get run. RSpec also provides + # # aliases for `it`, `describe`, and `context` that include `:focus` + # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + # config.filter_run_when_matching :focus + # + # # Allows RSpec to persist some state between runs in order to support + # # the `--only-failures` and `--next-failure` CLI options. We recommend + # # you configure your source control system to ignore this file. + # config.example_status_persistence_file_path = "spec/examples.txt" + # + # # Limits the available syntax to the non-monkey patched syntax that is + # # recommended. For more details, see: + # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + # config.disable_monkey_patching! + # + # # Many RSpec users commonly either run the entire suite or an individual + # # file, and it's useful to allow more verbose output when running an + # # individual spec file. + # if config.files_to_run.one? + # # Use the documentation formatter for detailed output, + # # unless a formatter has already been configured + # # (e.g. via a command-line flag). + # config.default_formatter = 'doc' + # end + # + # # Print the 10 slowest examples and example groups at the + # # end of the spec run, to help surface which specs are running + # # particularly slow. + # config.profile_examples = 10 + # + # # Run specs in random order to surface order dependencies. If you find an + # # order dependency and want to debug it, you can fix the order by providing + # # the seed, which is printed after each run. + # # --seed 1234 + # config.order = :random + # + # # Seed global randomization in this process using the `--seed` CLI option. + # # Setting this allows you to use `--seed` to deterministically reproduce + # # test failures related to randomization by passing the same `--seed` value + # # as the one that triggered the failure. + # Kernel.srand config.seed end diff --git a/test-app/spec/swagger_helper.rb b/test-app/spec/swagger_helper.rb index e206999..2ac0de3 100644 --- a/test-app/spec/swagger_helper.rb +++ b/test-app/spec/swagger_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.configure do |config| @@ -5,7 +7,7 @@ RSpec.configure do |config| # NOTE: If you're using the rswag-api to serve API descriptions, you'll need # to ensure that it's configured to serve Swagger from the same folder config.swagger_root = Rails.root.to_s + '/swagger' - + config.swagger_dry_run = false # Define one or more Swagger documents and provide global metadata for each one # When you run the 'rswag:specs:to_swagger' rake task, the complete Swagger will # be generated at the provided relative path under swagger_root @@ -21,54 +23,54 @@ RSpec.configure do |config| }, paths: {}, servers: [ - { - url: "https://{defaultHost}", - variables: { - defaultHost: { - default: "www.example.com" - } - } + { + url: 'https://{defaultHost}', + variables: { + defaultHost: { + default: 'www.example.com' + } } + } ], - + components: { schemas: { - errors_object: { - type: 'object', - properties: { - errors: { '$ref' => '#/components/schemas/errors_map' } - } - }, - errors_map: { - type: 'object', - additionalProperties: { - type: 'array', - items: { type: 'string' } - } - }, - blog: { - type: 'object', - properties: { - id: { type: 'integer' }, - title: { type: 'string' }, - content: { type: 'string', nullable: true }, - thumbnail: { type: 'string'} - }, - required: [ 'id', 'title', 'content', 'thumbnail' ] + errors_object: { + type: 'object', + properties: { + errors: { '$ref' => '#/components/schemas/errors_map' } } + }, + errors_map: { + type: 'object', + additionalProperties: { + type: 'array', + items: { type: 'string' } + } + }, + blog: { + type: 'object', + properties: { + id: { type: 'integer' }, + title: { type: 'string' }, + content: { type: 'string', nullable: true }, + thumbnail: { type: 'string' } + }, + required: %w[id title content thumbnail] + } }, securitySchemes: { - basic_auth: { - type: :http, - scheme: :basic - }, - api_key: { - type: :apiKey, - name: 'api_key', - in: :query - } + basic_auth: { + type: :http, + scheme: :basic + }, + api_key: { + type: :apiKey, + name: 'api_key', + in: :query + } } - }, + } } } end