require 'spec_helper' describe Grape::Middleware::Formatter do subject{ Grape::Middleware::Formatter.new(app, :default_format => :json)} before{ subject.stub!(:dup).and_return(subject) } let(:app){ lambda{|env| [200, {}, [@body]]} } context 'serialization' do it 'should look at the bodies for possibly serializable data' do @body = {"abc" => "def"} status, headers, bodies = *subject.call({'PATH_INFO' => '/somewhere'}) bodies.each{|b| b.should == MultiJson.encode(@body) } end it 'should call #to_json first if it is available' do @body = "string" @body.instance_eval do def to_json "\"bar\"" end end subject.call({'PATH_INFO' => '/somewhere'}).last.each{|b| b.should == '"bar"'} end it 'should serialize the #serializable_hash if that is available' do class SimpleExample def serializable_hash {:abc => 'def'} end end @body = SimpleExample.new subject.call({'PATH_INFO' => '/somewhere'}).last.each{|b| b.should == '{"abc":"def"}'} end end context 'detection' do it 'should use the extension if one is provided' do subject.call({'PATH_INFO' => '/info.xml'}) subject.env['api.format'].should == :xml subject.call({'PATH_INFO' => '/info.json'}) subject.env['api.format'].should == :json end it 'should use the default format if none is provided' do subject.call({'PATH_INFO' => '/info'}) subject.env['api.format'].should == :json end it 'should throw an error on an unrecognized format' do err = catch(:error){ subject.call({'PATH_INFO' => '/info.barklar'}) } err.should == {:status => 406, :message => "The requested format is not supported."} end end context 'Accept header detection' do it 'should detect from the Accept header' do subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/xml'}) subject.env['api.format'].should == :xml end it 'should look for case-indifferent headers' do subject.call({'PATH_INFO' => '/info', 'accept' => 'application/xml'}) subject.env['api.format'].should == :xml end it 'should use quality rankings to determine formats' do subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json; q=0.3,application/xml; q=1.0'}) subject.env['api.format'].should == :xml subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json; q=1.0,application/xml; q=0.3'}) subject.env['api.format'].should == :json end it 'should handle quality rankings mixed with nothing' do subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json,application/xml; q=1.0'}) subject.env['api.format'].should == :xml end it 'should properly parse headers with other attributes' do subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json; abc=2.3; q=1.0,application/xml; q=0.7'}) subject.env['api.format'].should == :json end end context 'Content-type' do it 'should be set for json' do _, headers, _ = subject.call({'PATH_INFO' => '/info.json'}) headers['Content-type'].should == 'application/json' end it 'should be set for xml' do _, headers, _ = subject.call({'PATH_INFO' => '/info.xml'}) headers['Content-type'].should == 'application/xml' end it 'should be set for txt' do _, headers, _ = subject.call({'PATH_INFO' => '/info.txt'}) headers['Content-type'].should == 'text/plain' end it 'should be set for custom' do subject.options[:content_types][:custom] = 'application/x-custom' _, headers, _ = subject.call({'PATH_INFO' => '/info.custom'}) headers['Content-type'].should == 'application/x-custom' end end context 'Format' do it 'should use custom formatter' do subject.options[:content_types][:custom] = "don't care" subject.options[:formatters][:custom] = lambda { |obj| 'CUSTOM FORMAT' } _, _, body = subject.call({'PATH_INFO' => '/info.custom'}) body.body.should == ['CUSTOM FORMAT'] end it 'should use default json formatter' do @body = 'blah' _, _, body = subject.call({'PATH_INFO' => '/info.json'}) body.body.should == ['"blah"'] end it 'should use custom json formatter' do subject.options[:formatters][:json] = lambda { |obj| 'CUSTOM JSON FORMAT' } _, _, body = subject.call({'PATH_INFO' => '/info.json'}) body.body.should == ['CUSTOM JSON FORMAT'] end end end