diff --git a/rswag-specs/lib/generators/rspec/swagger/USAGE b/rswag-specs/lib/generators/rspec/USAGE similarity index 100% rename from rswag-specs/lib/generators/rspec/swagger/USAGE rename to rswag-specs/lib/generators/rspec/USAGE diff --git a/rswag-specs/lib/generators/rspec/swagger/swagger_generator.rb b/rswag-specs/lib/generators/rspec/swagger/swagger_generator.rb deleted file mode 100644 index 48f92aa..0000000 --- a/rswag-specs/lib/generators/rspec/swagger/swagger_generator.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'rspec/rails/swagger/route_parser' -require 'rails/generators' - -module Rspec - module Generators - class SwaggerGenerator < ::Rails::Generators::NamedBase - source_root File.expand_path('../templates', __FILE__) - - def setup - @routes = RSpec::Rails::Swagger::RouteParser.new(controller_path).routes - end - - def create_spec_file - template 'spec.rb', File.join('spec/requests', "#{controller_path}_spec.rb") - end - - private - - def controller_path - file_path.chomp('_controller') - end - end - end -end diff --git a/rswag-specs/lib/generators/rspec/swagger_generator.rb b/rswag-specs/lib/generators/rspec/swagger_generator.rb new file mode 100644 index 0000000..ddb862c --- /dev/null +++ b/rswag-specs/lib/generators/rspec/swagger_generator.rb @@ -0,0 +1,22 @@ +require 'rswag/route_parser' +require 'rails/generators' + +module Rspec + class SwaggerGenerator < ::Rails::Generators::NamedBase + source_root File.expand_path('../templates', __FILE__) + + def setup + @routes = Rswag::RouteParser.new(controller_path).routes + end + + def create_spec_file + template 'spec.rb', File.join('spec', 'requests', "#{controller_path}_spec.rb") + end + + private + + def controller_path + file_path.chomp('_controller') + end + end +end diff --git a/rswag-specs/lib/generators/rspec/swagger/templates/spec.rb b/rswag-specs/lib/generators/rspec/templates/spec.rb similarity index 51% rename from rswag-specs/lib/generators/rspec/swagger/templates/spec.rb rename to rswag-specs/lib/generators/rspec/templates/spec.rb index 75ff7b3..346e348 100644 --- a/rswag-specs/lib/generators/rspec/swagger/templates/spec.rb +++ b/rswag-specs/lib/generators/rspec/templates/spec.rb @@ -1,22 +1,22 @@ require 'swagger_helper' RSpec.describe '<%= controller_path %>', type: :request do - <% @routes.each do | template, path_item | %> +<% @routes.each do | template, path_item | %> path '<%= template %>' do -<% unless path_item[:params].empty? -%> +<% unless path_item[:params].empty? -%> # You'll want to customize the parameter types... - <% path_item[:params].each do |param| -%> - parameter '<%= param %>', in: :body, type: :string - <% end -%> -<% end -%> -<% path_item[:actions].each do | action, details | -%> +<% path_item[:params].each do |param| -%> + parameter name: '<%= param %>', in: :path, type: :string, description: '<%= param %>' +<% end -%> +<% end -%> +<% path_item[:actions].each do | action, details | %> <%= action %>('<%= details[:summary] %>') do response(200, 'successful') do -<% unless path_item[:params].empty? -%> - <% path_item[:params].each do |param| -%> +<% unless path_item[:params].empty? -%> +<% path_item[:params].each do |param| -%> let(:<%= param %>) { '123' } - <% end -%> -<% end -%> +<% end -%> +<% end -%> after do |example| example.metadata[:response][:examples] = { 'application/json' => JSON.parse(response.body, symbolize_names: true) } @@ -24,7 +24,7 @@ RSpec.describe '<%= controller_path %>', type: :request do run_test! end end -<% end -%> +<% end -%> end -<% end -%> +<% end -%> end diff --git a/rswag-specs/lib/rspec/rails/swagger/route_parser.rb b/rswag-specs/lib/rspec/rails/swagger/route_parser.rb deleted file mode 100644 index 9ab9513..0000000 --- a/rswag-specs/lib/rspec/rails/swagger/route_parser.rb +++ /dev/null @@ -1,62 +0,0 @@ -module RSpec - module Rails - module Swagger - class RouteParser - attr_reader :controller - - def initialize(controller) - @controller = controller - end - - def routes - ::Rails.application.routes.routes.select do |route| - route.defaults[:controller] == controller - end.reduce({}) do |tree, route| - path = path_from(route) - verb = verb_from(route) - tree[path] ||= { params: params_from(route), actions: {} } - tree[path][:actions][verb] = { summary: summary_from(route) } - tree - end - end - - private - - def path_from(route) - route.path.spec.to_s - .chomp('(.:format)') # Ignore any format suffix - .gsub(/:([^\/.?]+)/, '{\1}') # Convert :id to {id} - end - - def verb_from(route) - verb = route.verb - if verb.kind_of? String - verb.downcase - else - verb.source.gsub(/[$^]/, '').downcase - end - end - - def summary_from(route) - verb = route.requirements[:action] - noun = route.requirements[:controller].split('/').last.singularize - - # Apply a few customizations to make things more readable - case verb - when 'index' - verb = 'list' - noun = noun.pluralize - when 'destroy' - verb = 'delete' - end - - "#{verb} #{noun}" - end - - def params_from(route) - route.segments - ['format'] - end - end - end - end -end diff --git a/rswag-specs/lib/rswag/route_parser.rb b/rswag-specs/lib/rswag/route_parser.rb new file mode 100644 index 0000000..523b36b --- /dev/null +++ b/rswag-specs/lib/rswag/route_parser.rb @@ -0,0 +1,58 @@ +module Rswag + class RouteParser + attr_reader :controller + + def initialize(controller) + @controller = controller + end + + def routes + ::Rails.application.routes.routes.select do |route| + route.defaults[:controller] == controller + end.reduce({}) do |tree, route| + path = path_from(route) + verb = verb_from(route) + tree[path] ||= { params: params_from(route), actions: {} } + tree[path][:actions][verb] = { summary: summary_from(route) } + tree + end + end + + private + + def path_from(route) + route.path.spec.to_s + .chomp('(.:format)') # Ignore any format suffix + .gsub(/:([^\/.?]+)/, '{\1}') # Convert :id to {id} + end + + def verb_from(route) + verb = route.verb + if verb.kind_of? String + verb.downcase + else + verb.source.gsub(/[$^]/, '').downcase + end + end + + def summary_from(route) + verb = route.requirements[:action] + noun = route.requirements[:controller].split('/').last.singularize + + # Apply a few customizations to make things more readable + case verb + when 'index' + verb = 'list' + noun = noun.pluralize + when 'destroy' + verb = 'delete' + end + + "#{verb} #{noun}" + end + + def params_from(route) + route.segments - ['format'] + end + end +end diff --git a/rswag-specs/lib/rswag/specs/extended_schema.rb b/rswag-specs/lib/rswag/specs/extended_schema.rb index 62eb4ee..29888f8 100644 --- a/rswag-specs/lib/rswag/specs/extended_schema.rb +++ b/rswag-specs/lib/rswag/specs/extended_schema.rb @@ -3,7 +3,7 @@ require 'json-schema' module Rswag module Specs class ExtendedSchema < JSON::Schema::Draft4 - + def initialize super @attributes['type'] = ExtendedTypeAttribute @@ -13,7 +13,7 @@ module Rswag end class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute - + def self.validate(current_schema, data, fragments, processor, validator, options={}) return if data.nil? && current_schema.schema['x-nullable'] == true super diff --git a/rswag-specs/lib/rswag/specs/railtie.rb b/rswag-specs/lib/rswag/specs/railtie.rb index 43e2302..994a8a4 100644 --- a/rswag-specs/lib/rswag/specs/railtie.rb +++ b/rswag-specs/lib/rswag/specs/railtie.rb @@ -5,7 +5,7 @@ module Rswag rake_tasks do load File.expand_path('../../../tasks/rswag-specs_tasks.rake', __FILE__) end - + generators do require 'generators/rspec/swagger/swagger_generator.rb' end diff --git a/rswag-specs/lib/rswag/specs/request_factory.rb b/rswag-specs/lib/rswag/specs/request_factory.rb index 7106015..14b1edc 100644 --- a/rswag-specs/lib/rswag/specs/request_factory.rb +++ b/rswag-specs/lib/rswag/specs/request_factory.rb @@ -54,7 +54,7 @@ module Rswag definitions[key] end - def add_verb(request, metadata) + def add_verb(request, metadata) request[:verb] = metadata[:operation][:verb] end @@ -104,7 +104,7 @@ module Rswag 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 ] diff --git a/rswag-specs/spec/generators/rspec/fixtures/spec/.gitkeep b/rswag-specs/spec/generators/rspec/fixtures/spec/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rswag-specs/spec/generators/rspec/swagger_generator_spec.rb b/rswag-specs/spec/generators/rspec/swagger_generator_spec.rb new file mode 100644 index 0000000..f11ea65 --- /dev/null +++ b/rswag-specs/spec/generators/rspec/swagger_generator_spec.rb @@ -0,0 +1,44 @@ +require 'generator_spec' +require 'generators/rspec/swagger_generator' +require 'tmpdir' + +module Rspec + describe SwaggerGenerator do + include GeneratorSpec::TestCase + destination Dir.mktmpdir + + before(:all) do + prepare_destination + fixtures_dir = File.expand_path('../fixtures', __FILE__) + FileUtils.cp_r("#{fixtures_dir}/spec", destination_root) + end + + after(:all) do + + end + + it 'installs the swagger_helper for rspec' do + allow_any_instance_of(Rswag::RouteParser).to receive(:routes).and_return(fake_routes) + run_generator ['Posts::CommentsController'] + + assert_file('spec/requests/posts/comments_spec.rb') do |content| + assert_match(/parameter name: 'post_id', in: :path, type: :string/, content) + assert_match(/patch\('update_comments comment'\)/, content) + end + end + + private + + def fake_routes + { + "/posts/{post_id}/comments/{id}" => { + :params => ["post_id", "id"], + :actions => { + "get" => { :summary=>"show comment" }, + "patch" => { :summary=>"update_comments comment" } + } + } + } + end + end +end