require 'spec_helper' describe Grape::Middleware::Error do # raises a text exception module ExceptionSpec class ExceptionApp class << self def call(_env) raise 'rain!' end end end # raises a hash error class ErrorHashApp class << self def error!(message, status) throw :error, message: { error: message, detail: 'missing widget' }, status: status end def call(_env) error!('rain!', 401) end end end # raises an error! class AccessDeniedApp class << self def error!(message, status) throw :error, message: message, status: status end def call(_env) error!('Access Denied', 401) end end end # raises a custom error class CustomError < Grape::Exceptions::Base end class CustomErrorApp class << self def call(_env) raise CustomError, status: 400, message: 'failed validation' end end end end attr_reader :app it 'does not trap errors by default' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error run ExceptionSpec::ExceptionApp end expect { get '/' }.to raise_error(RuntimeError, 'rain!') end context 'with rescue_all set to true' do it 'sets the message appropriately' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true run ExceptionSpec::ExceptionApp end get '/' expect(last_response.body).to eq('rain!') end it 'defaults to a 500 status' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true run ExceptionSpec::ExceptionApp end get '/' expect(last_response.status).to eq(500) end it 'is possible to specify a different default status code' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true, default_status: 500 run ExceptionSpec::ExceptionApp end get '/' expect(last_response.status).to eq(500) end it 'is possible to return errors in json format' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true, format: :json run ExceptionSpec::ExceptionApp end get '/' expect(last_response.body).to eq('{"error":"rain!"}') end it 'is possible to return hash errors in json format' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true, format: :json run ExceptionSpec::ErrorHashApp end get '/' expect(['{"error":"rain!","detail":"missing widget"}', '{"detail":"missing widget","error":"rain!"}']).to include(last_response.body) end it 'is possible to return errors in jsonapi format' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true, format: :jsonapi run ExceptionSpec::ExceptionApp end get '/' expect(last_response.body).to eq('{"error":"rain!"}') end it 'is possible to return hash errors in jsonapi format' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true, format: :jsonapi run ExceptionSpec::ErrorHashApp end get '/' expect(['{"error":"rain!","detail":"missing widget"}', '{"detail":"missing widget","error":"rain!"}']).to include(last_response.body) end it 'is possible to return errors in xml format' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true, format: :xml run ExceptionSpec::ExceptionApp end get '/' expect(last_response.body).to eq("\n\n rain!\n\n") end it 'is possible to return hash errors in xml format' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true, format: :xml run ExceptionSpec::ErrorHashApp end get '/' expect(["\n\n missing widget\n rain!\n\n", "\n\n rain!\n missing widget\n\n"]).to include(last_response.body) end it 'is possible to specify a custom formatter' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: true, format: :custom, error_formatters: { custom: lambda do |message, _backtrace, _options, _env| { custom_formatter: message }.inspect end } run ExceptionSpec::ExceptionApp end get '/' expect(last_response.body).to eq('{:custom_formatter=>"rain!"}') end it 'does not trap regular error! codes' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error run ExceptionSpec::AccessDeniedApp end get '/' expect(last_response.status).to eq(401) end it 'responds to custom Grape exceptions appropriately' do @app ||= Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, rescue_all: false run ExceptionSpec::CustomErrorApp end get '/' expect(last_response.status).to eq(400) expect(last_response.body).to eq('failed validation') end end end