mirror of
https://github.com/ditkrg/rswag.git
synced 2026-01-23 06:16:42 +00:00
More useful error messages in rswag-specs
This commit is contained in:
parent
f1850bc6d0
commit
b81b2927be
@ -2,6 +2,7 @@ require 'rspec/core'
|
||||
require 'rswag/specs/version'
|
||||
require 'rswag/specs/example_group_helpers'
|
||||
require 'rswag/specs/example_helpers'
|
||||
require 'rswag/specs/configuration'
|
||||
require 'rswag/specs/railtie' if defined?(Rails::Railtie)
|
||||
|
||||
module Rswag
|
||||
@ -15,6 +16,10 @@ module Rswag
|
||||
c.include ExampleHelpers, type: :request
|
||||
end
|
||||
|
||||
def self.config
|
||||
@config ||= Configuration.new(RSpec.configuration)
|
||||
end
|
||||
|
||||
# Support Rails 3+ and RSpec 2+ (sigh!)
|
||||
RAILS_VERSION = Rails::VERSION::MAJOR
|
||||
RSPEC_VERSION = RSpec::Core::Version::STRING.split('.').first.to_i
|
||||
|
||||
37
rswag-specs/lib/rswag/specs/configuration.rb
Normal file
37
rswag-specs/lib/rswag/specs/configuration.rb
Normal file
@ -0,0 +1,37 @@
|
||||
module Rswag
|
||||
module Specs
|
||||
|
||||
class Configuration
|
||||
|
||||
def initialize(rspec_config)
|
||||
@rspec_config = rspec_config
|
||||
end
|
||||
|
||||
def swagger_root
|
||||
@swagger_root ||= begin
|
||||
if @rspec_config.swagger_root.nil?
|
||||
raise ConfigurationError, 'No swagger_root provided. See swagger_helper.rb'
|
||||
end
|
||||
@rspec_config.swagger_root
|
||||
end
|
||||
end
|
||||
|
||||
def swagger_docs
|
||||
@swagger_docs ||= begin
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
class ConfigurationError < StandardError; end
|
||||
end
|
||||
end
|
||||
@ -6,7 +6,7 @@ module Rswag
|
||||
module ExampleHelpers
|
||||
|
||||
def submit_request(api_metadata)
|
||||
factory = RequestFactory.new(api_metadata, global_metadata(api_metadata[:swagger_doc]))
|
||||
factory = RequestFactory.new(api_metadata, config.get_swagger_doc(api_metadata[:swagger_doc]))
|
||||
|
||||
if RAILS_VERSION < 5
|
||||
send(
|
||||
@ -28,15 +28,14 @@ module Rswag
|
||||
end
|
||||
|
||||
def assert_response_matches_metadata(api_metadata)
|
||||
validator = ResponseValidator.new(api_metadata, global_metadata(api_metadata[:swagger_doc]))
|
||||
validator = ResponseValidator.new(api_metadata, config.get_swagger_doc(api_metadata[:swagger_doc]))
|
||||
validator.validate!(response)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def global_metadata(swagger_doc)
|
||||
swagger_docs = ::RSpec.configuration.swagger_docs
|
||||
swagger_doc.nil? ? swagger_docs.values.first : swagger_docs[swagger_doc]
|
||||
def config
|
||||
::Rswag::Specs.config
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
require 'active_support/core_ext/hash/deep_merge'
|
||||
require 'rspec/core/formatters/base_text_formatter'
|
||||
require 'swagger_helper'
|
||||
|
||||
module Rswag
|
||||
@ -11,12 +10,9 @@ module Rswag
|
||||
::RSpec::Core::Formatters.register self, :example_group_finished, :stop
|
||||
end
|
||||
|
||||
def initialize(output)
|
||||
def initialize(output, config = Rswag::Specs.config)
|
||||
@output = output
|
||||
@swagger_root = ::RSpec.configuration.swagger_root
|
||||
raise ConfigurationError, 'Missing swagger_root. See swagger_helper.rb' if @swagger_root.nil?
|
||||
@swagger_docs = ::RSpec.configuration.swagger_docs || []
|
||||
raise ConfigurationError, 'Missing swagger_docs. See swagger_helper.rb' if @swagger_docs.empty?
|
||||
@config = config
|
||||
|
||||
@output.puts 'Generating Swagger docs ...'
|
||||
end
|
||||
@ -30,13 +26,13 @@ module Rswag
|
||||
end
|
||||
|
||||
return unless metadata.has_key?(:response)
|
||||
swagger_doc = get_swagger_doc(metadata[:swagger_doc])
|
||||
swagger_doc = @config.get_swagger_doc(metadata[:swagger_doc])
|
||||
swagger_doc.deep_merge!(metadata_to_swagger(metadata))
|
||||
end
|
||||
|
||||
def stop(notification=nil)
|
||||
@swagger_docs.each do |url_path, doc|
|
||||
file_path = File.join(@swagger_root, url_path)
|
||||
@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)
|
||||
|
||||
@ -50,12 +46,6 @@ module Rswag
|
||||
|
||||
private
|
||||
|
||||
def get_swagger_doc(tag)
|
||||
return @swagger_docs.values.first if tag.nil?
|
||||
raise ConfigurationError, "Unknown swagger_doc '#{tag}'" unless @swagger_docs.has_key?(tag)
|
||||
@swagger_docs[tag]
|
||||
end
|
||||
|
||||
def metadata_to_swagger(metadata)
|
||||
response_code = metadata[:response][:code]
|
||||
response = metadata[:response].reject { |k,v| k == :code }
|
||||
@ -73,7 +63,5 @@ module Rswag
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class ConfigurationError < StandardError; end
|
||||
end
|
||||
end
|
||||
|
||||
77
rswag-specs/spec/rswag/specs/configuration_spec.rb
Normal file
77
rswag-specs/spec/rswag/specs/configuration_spec.rb
Normal file
@ -0,0 +1,77 @@
|
||||
require 'rswag/specs/configuration'
|
||||
|
||||
module Rswag
|
||||
module Specs
|
||||
|
||||
describe Configuration do
|
||||
subject { described_class.new(rspec_config) }
|
||||
|
||||
let(:rspec_config) { OpenStruct.new(swagger_root: swagger_root, swagger_docs: swagger_docs) }
|
||||
let(:swagger_root) { 'foobar' }
|
||||
let(:swagger_docs) do
|
||||
{
|
||||
'v1/swagger.json' => { info: { title: 'v1' } },
|
||||
'v2/swagger.json' => { info: { title: 'v2' } }
|
||||
}
|
||||
end
|
||||
|
||||
describe '#swagger_root' do
|
||||
let(:response) { subject.swagger_root }
|
||||
|
||||
context 'provided in rspec config' do
|
||||
it { expect(response).to eq('foobar') }
|
||||
end
|
||||
|
||||
context 'not provided' do
|
||||
let(:swagger_root) { nil }
|
||||
it { expect { response }.to raise_error ConfigurationError }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#swagger_docs' do
|
||||
let(:response) { subject.swagger_docs }
|
||||
|
||||
context 'provided in rspec config' do
|
||||
it { expect(response).to be_an_instance_of(Hash) }
|
||||
end
|
||||
|
||||
context 'not provided' do
|
||||
let(:swagger_docs) { nil }
|
||||
it { expect { response }.to raise_error ConfigurationError }
|
||||
end
|
||||
|
||||
context 'provided but empty' do
|
||||
let(:swagger_docs) { {} }
|
||||
it { expect { response }.to raise_error ConfigurationError }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_swagger_doc(tag=nil)' do
|
||||
let(:swagger_doc) { subject.get_swagger_doc(tag) }
|
||||
|
||||
context 'no tag provided' do
|
||||
let(:tag) { nil }
|
||||
|
||||
it 'returns the first doc in rspec config' do
|
||||
expect(swagger_doc).to eq(info: { title: 'v1' })
|
||||
end
|
||||
end
|
||||
|
||||
context 'tag provided' do
|
||||
context 'matching doc' do
|
||||
let(:tag) { 'v2/swagger.json' }
|
||||
|
||||
it 'returns the matching doc in rspec config' do
|
||||
expect(swagger_doc).to eq(info: { title: 'v2' })
|
||||
end
|
||||
end
|
||||
|
||||
context 'no matching doc' do
|
||||
let(:tag) { 'foobar' }
|
||||
it { expect { swagger_doc }.to raise_error ConfigurationError }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -5,13 +5,14 @@ module Rswag
|
||||
|
||||
describe ExampleGroupHelpers do
|
||||
subject { double('example_group') }
|
||||
let(:api_metadata) { {} }
|
||||
|
||||
before do
|
||||
subject.extend ExampleGroupHelpers
|
||||
allow(subject).to receive(:describe)
|
||||
allow(subject).to receive(:context)
|
||||
allow(subject).to receive(:metadata).and_return(api_metadata)
|
||||
end
|
||||
let(:api_metadata) { {} }
|
||||
|
||||
describe '#path(path)' do
|
||||
before { subject.path('/blogs') }
|
||||
@ -34,7 +35,6 @@ module Rswag
|
||||
end
|
||||
|
||||
describe '#tags|description|operationId|consumes|produces|schemes|deprecated(value)' do
|
||||
let(:api_metadata) { { operation: {} } }
|
||||
before do
|
||||
subject.tags('Blogs', 'Admin')
|
||||
subject.description('Some description')
|
||||
@ -44,6 +44,7 @@ module Rswag
|
||||
subject.schemes('http', 'https')
|
||||
subject.deprecated(true)
|
||||
end
|
||||
let(:api_metadata) { { operation: {} } }
|
||||
|
||||
it "adds to the 'operation' metadata" do
|
||||
expect(api_metadata[:operation]).to match(
|
||||
@ -59,7 +60,6 @@ module Rswag
|
||||
end
|
||||
|
||||
describe '#tags|description|operationId|consumes|produces|schemes|deprecated|security(value)' do
|
||||
let(:api_metadata) { { operation: {} } }
|
||||
before do
|
||||
subject.tags('Blogs', 'Admin')
|
||||
subject.description('Some description')
|
||||
@ -70,6 +70,7 @@ module Rswag
|
||||
subject.deprecated(true)
|
||||
subject.security(api_key: [])
|
||||
end
|
||||
let(:api_metadata) { { operation: {} } }
|
||||
|
||||
it "adds to the 'operation' metadata" do
|
||||
expect(api_metadata[:operation]).to match(
|
||||
@ -120,8 +121,8 @@ module Rswag
|
||||
end
|
||||
|
||||
describe '#schema(value)' do
|
||||
let(:api_metadata) { { response: {} } }
|
||||
before { subject.schema(type: 'object') }
|
||||
let(:api_metadata) { { response: {} } }
|
||||
|
||||
it "adds to the 'response' metadata" do
|
||||
expect(api_metadata[:response][:schema]).to match(type: 'object')
|
||||
@ -129,8 +130,8 @@ module Rswag
|
||||
end
|
||||
|
||||
describe '#header(name, attributes)' do
|
||||
let(:api_metadata) { { response: {} } }
|
||||
before { subject.header('Date', type: 'string') }
|
||||
let(:api_metadata) { { response: {} } }
|
||||
|
||||
it "adds to the 'response headers' metadata" do
|
||||
expect(api_metadata[:response][:headers]).to match(
|
||||
|
||||
@ -4,6 +4,16 @@ module Rswag
|
||||
module Specs
|
||||
|
||||
describe ExampleHelpers do
|
||||
subject { double('example') }
|
||||
|
||||
before do
|
||||
subject.extend ExampleHelpers
|
||||
# Mock out some infrastructure
|
||||
stub_const('Rails::VERSION::MAJOR', 3)
|
||||
config = double('config')
|
||||
allow(config).to receive(:get_swagger_doc).and_return(global_metadata)
|
||||
allow(subject).to receive(:config).and_return(config)
|
||||
end
|
||||
let(:api_metadata) do
|
||||
{
|
||||
path: '/blogs/{blog_id}/comments/{id}',
|
||||
@ -34,22 +44,14 @@ module Rswag
|
||||
}
|
||||
end
|
||||
|
||||
subject { double('example') }
|
||||
|
||||
before do
|
||||
subject.extend ExampleHelpers
|
||||
allow(subject).to receive(:blog_id).and_return(1)
|
||||
allow(subject).to receive(:id).and_return(2)
|
||||
allow(subject).to receive(:q1).and_return('foo')
|
||||
allow(subject).to receive(:api_key).and_return('fookey')
|
||||
allow(subject).to receive(:blog).and_return(text: 'Some comment')
|
||||
allow(subject).to receive(:global_metadata).and_return(global_metadata)
|
||||
allow(subject).to receive(:put)
|
||||
end
|
||||
|
||||
describe '#submit_request(api_metadata)' do
|
||||
before do
|
||||
stub_const('Rails::VERSION::MAJOR', 3)
|
||||
allow(subject).to receive(:blog_id).and_return(1)
|
||||
allow(subject).to receive(:id).and_return(2)
|
||||
allow(subject).to receive(:q1).and_return('foo')
|
||||
allow(subject).to receive(:api_key).and_return('fookey')
|
||||
allow(subject).to receive(:blog).and_return(text: 'Some comment')
|
||||
allow(subject).to receive(:put)
|
||||
subject.submit_request(api_metadata)
|
||||
end
|
||||
|
||||
|
||||
@ -4,6 +4,12 @@ module Rswag
|
||||
module Specs
|
||||
|
||||
describe RequestFactory do
|
||||
subject { RequestFactory.new(api_metadata, global_metadata) }
|
||||
|
||||
before do
|
||||
allow(example).to receive(:blog_id).and_return(1)
|
||||
allow(example).to receive(:id).and_return('2')
|
||||
end
|
||||
let(:api_metadata) do
|
||||
{
|
||||
path: '/blogs/{blog_id}/comments/{id}',
|
||||
@ -18,14 +24,7 @@ module Rswag
|
||||
}
|
||||
end
|
||||
let(:global_metadata) { {} }
|
||||
|
||||
subject { RequestFactory.new(api_metadata, global_metadata) }
|
||||
|
||||
let(:example) { double('example') }
|
||||
before do
|
||||
allow(example).to receive(:blog_id).and_return(1)
|
||||
allow(example).to receive(:id).and_return('2')
|
||||
end
|
||||
|
||||
describe '#build_fullpath(example)' do
|
||||
let(:path) { subject.build_fullpath(example) }
|
||||
|
||||
@ -4,11 +4,11 @@ module Rswag
|
||||
module Specs
|
||||
|
||||
describe ResponseValidator do
|
||||
subject { ResponseValidator.new(api_metadata, global_metadata) }
|
||||
|
||||
let(:api_metadata) { { response: { code: 200 } } }
|
||||
let(:global_metadata) { {} }
|
||||
|
||||
subject { ResponseValidator.new(api_metadata, global_metadata) }
|
||||
|
||||
describe '#validate!(response)' do
|
||||
let(:call) { subject.validate!(response) }
|
||||
|
||||
|
||||
@ -5,33 +5,23 @@ module Rswag
|
||||
module Specs
|
||||
|
||||
describe SwaggerFormatter do
|
||||
# Mock infrastructure - output, RSpec.configuration etc.
|
||||
subject { described_class.new(output, config) }
|
||||
|
||||
# Mock out some infrastructure
|
||||
before do
|
||||
allow(config).to receive(:swagger_root).and_return(swagger_root)
|
||||
end
|
||||
let(:config) { double('config') }
|
||||
let(:output) { double('output').as_null_object }
|
||||
let(:swagger_root) { File.expand_path('../tmp', __FILE__) }
|
||||
let(:swagger_docs) do
|
||||
{
|
||||
'v1/swagger.json' => { info: { version: 'v1' } }
|
||||
}
|
||||
end
|
||||
let(:config) { OpenStruct.new(swagger_root: swagger_root, swagger_docs: swagger_docs) }
|
||||
before { allow(RSpec).to receive(:configuration).and_return(config) }
|
||||
|
||||
subject { described_class.new(output) }
|
||||
|
||||
describe '::new(output)' do
|
||||
context 'swagger_root not configured' do
|
||||
let(:swagger_root) { nil }
|
||||
it { expect { subject }.to raise_error ConfigurationError }
|
||||
end
|
||||
|
||||
context 'swagger_docs not configured' do
|
||||
let(:swagger_docs) { nil }
|
||||
it { expect { subject }.to raise_error ConfigurationError }
|
||||
end
|
||||
end
|
||||
let(:swagger_root) { File.expand_path('../tmp/swagger', __FILE__) }
|
||||
|
||||
describe '#example_group_finished(notification)' do
|
||||
# Mock notification parameter
|
||||
before do
|
||||
allow(config).to receive(:get_swagger_doc).and_return(swagger_doc)
|
||||
subject.example_group_finished(notification)
|
||||
end
|
||||
let(:swagger_doc) { {} }
|
||||
let(:notification) { OpenStruct.new(group: OpenStruct.new(metadata: api_metadata)) }
|
||||
let(:api_metadata) do
|
||||
{
|
||||
path: '/blogs',
|
||||
@ -39,78 +29,35 @@ module Rswag
|
||||
response: { code: '201', description: 'blog created' }
|
||||
}
|
||||
end
|
||||
let(:notification) { OpenStruct.new(group: OpenStruct.new(metadata: api_metadata)) }
|
||||
|
||||
let(:call) { subject.example_group_finished(notification) }
|
||||
|
||||
context 'single swagger_doc' do
|
||||
before { call }
|
||||
|
||||
it 'converts metadata to swagger and merges into the doc' do
|
||||
expect(swagger_docs.values.first).to match(
|
||||
info: { version: 'v1' },
|
||||
paths: {
|
||||
'/blogs' => {
|
||||
post: {
|
||||
summary: 'Creates a blog',
|
||||
responses: {
|
||||
'201' => { description: 'blog created' }
|
||||
}
|
||||
it 'converts to swagger and merges into the corresponding swagger doc' do
|
||||
expect(swagger_doc).to match(
|
||||
paths: {
|
||||
'/blogs' => {
|
||||
post: {
|
||||
summary: 'Creates a blog',
|
||||
responses: {
|
||||
'201' => { description: 'blog created' }
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'multiple swagger_docs' do
|
||||
let(:swagger_docs) do
|
||||
{
|
||||
'v1/swagger.json' => {},
|
||||
'v2/swagger.json' => {}
|
||||
}
|
||||
end
|
||||
|
||||
context "no 'swagger_doc' tag" do
|
||||
before { call }
|
||||
|
||||
it 'merges into the first doc' do
|
||||
expect(swagger_docs.values.first).to have_key(:paths)
|
||||
end
|
||||
end
|
||||
|
||||
context "matching 'swagger_doc' tag" do
|
||||
before do
|
||||
api_metadata[:swagger_doc] = 'v2/swagger.json'
|
||||
call
|
||||
end
|
||||
|
||||
it 'merges into the matched doc' do
|
||||
expect(swagger_docs.values.last).to have_key(:paths)
|
||||
end
|
||||
end
|
||||
|
||||
context "non matching 'swagger_doc' tag" do
|
||||
before { api_metadata[:swagger_doc] = 'foobar' }
|
||||
it { expect { call }.to raise_error ConfigurationError }
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#stop' do
|
||||
let(:notification) { double('notification') }
|
||||
let(:swagger_docs) do
|
||||
{
|
||||
'v1/swagger.json' => { info: { version: 'v1' } },
|
||||
'v2/swagger.json' => { info: { version: 'v2' } },
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
FileUtils.rm_r(swagger_root) if File.exists?(swagger_root)
|
||||
allow(config).to receive(:swagger_docs).and_return(
|
||||
'v1/swagger.json' => { info: { version: 'v1' } },
|
||||
'v2/swagger.json' => { info: { version: 'v2' } }
|
||||
)
|
||||
subject.stop(notification)
|
||||
end
|
||||
|
||||
let(:notification) { double('notification') }
|
||||
|
||||
it 'writes the swagger_doc(s) to file' do
|
||||
expect(File).to exist("#{swagger_root}/v1/swagger.json")
|
||||
expect(File).to exist("#{swagger_root}/v2/swagger.json")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user