spec/grape/middleware/formatter_spec.rb in grape-0.1.5 vs spec/grape/middleware/formatter_spec.rb in grape-0.2.0
- old
+ new
@@ -1,90 +1,128 @@
require 'spec_helper'
describe Grape::Middleware::Formatter do
- subject{ Grape::Middleware::Formatter.new(app, :default_format => :json)}
+ subject{ Grape::Middleware::Formatter.new(app) }
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'})
+ status, headers, bodies = *subject.call({'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json'})
bodies.each{|b| b.should == MultiJson.encode(@body) }
end
-
+
it 'should call #to_json first if it is available' do
- @body = "string"
+ @body = ['foo']
@body.instance_eval do
def to_json
"\"bar\""
end
end
-
- subject.call({'PATH_INFO' => '/somewhere'}).last.each{|b| b.should == '"bar"'}
+
+ subject.call({'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json'}).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, SimpleExample.new]
+
+ subject.call({'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json'}).last.each{|b| b.should == '[{"abc":"def"},{"abc":"def"}]'}
+ end
+
+ it 'should serialize multiple objects that respond to #serializable_hash' 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"}'}
+
+ subject.call({'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json'}).last.each{|b| b.should == '{"abc":"def"}'}
end
+
+ it 'should call #to_xml if the content type is xml' do
+ @body = "string"
+ @body.instance_eval do
+ def to_xml
+ "<bar/>"
+ end
+ end
+
+ subject.call({'PATH_INFO' => '/somewhere.xml', 'HTTP_ACCEPT' => 'application/json'}).last.each{|b| b.should == '<bar/>'}
+ 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 == :txt
+ end
+
+ it 'should use the requested format if provided in headers' do
+ subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json'})
subject.env['api.format'].should == :json
end
+
+ it 'should use the file extension format if provided before headers' do
+ subject.call({'PATH_INFO' => '/info.txt', 'HTTP_ACCEPT' => 'application/json'})
+ subject.env['api.format'].should == :txt
+ 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.call({'PATH_INFO' => '/info', 'HTTP_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.call({'PATH_INFO' => '/info', 'http_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.call({'PATH_INFO' => '/info', 'HTTP_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.call({'PATH_INFO' => '/info', 'HTTP_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.call({'PATH_INFO' => '/info', 'HTTP_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.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json; abc=2.3; q=1.0,application/xml; q=0.7'})
subject.env['api.format'].should == :json
end
+
+ it 'should properly parse headers with vendor and api version' do
+ subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/vnd.test-v1+xml'})
+ subject.env['api.format'].should == :xml
+ end
end
context 'Content-type' do
it 'should be set for json' do
_, headers, _ = subject.call({'PATH_INFO' => '/info.json'})
@@ -111,16 +149,32 @@
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 = ['blah']
_, _, body = subject.call({'PATH_INFO' => '/info.json'})
- body.body.should == ['"blah"']
+ 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
+
+ context 'Input' do
+ it 'should parse the body from a POST/PUT and put the contents into rack.request.form_hash' do
+ subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json', 'rack.input' => StringIO.new('{"is_boolean":true,"string":"thing"}')})
+ subject.env['rack.request.form_hash']['is_boolean'].should be_true
+ subject.env['rack.request.form_hash']['string'].should == 'thing'
+ end
+ it 'should parse the body from an xml POST/PUT and put the contents into rack.request.from_hash' do
+ subject.call({'PATH_INFO' => '/info.xml', 'HTTP_ACCEPT' => 'application/xml', 'rack.input' => StringIO.new('<thing><name>Test</name></thing>')})
+ subject.env['rack.request.form_hash']['thing']['name'].should == 'Test'
+ end
+ it 'should be able to fail gracefully if the body is regular POST content' do
+ subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json', 'rack.input' => StringIO.new('name=Other+Test+Thing')})
+ subject.env['rack.request.form_hash'].should be_nil
end
end
end