From eee3534b1a5614d824a34e2c761faaeab07c2eb4 Mon Sep 17 00:00:00 2001 From: Kasper Timm Hansen Date: Wed, 10 Feb 2016 21:46:51 +0100 Subject: Add `parsed_body` to spare writing out parsing routines. When testing: ```ruby post articles_path, params: { article: { title: 'Ahoy!' } }, as: :json ``` It's common to want to make assertions on the response body. Perhaps the server responded with JSON, so you write `JSON.parse(response.body)`. But that gets tedious real quick. Instead add `parsed_body` which will automatically parse the reponse body as what the last request was encoded `as`. --- .../lib/action_dispatch/testing/integration.rb | 38 +++++++++++++++------- .../lib/action_dispatch/testing/test_response.rb | 6 ++++ actionpack/test/controller/integration_test.rb | 35 +++++++++++++------- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 61bd39c186..742bce1ca6 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -381,6 +381,7 @@ module ActionDispatch response = _mock_session.last_response @response = ActionDispatch::TestResponse.from_response(response) @response.request = @request + @response.response_parser = request_encoder @html_document = nil @url_options = nil @@ -396,7 +397,7 @@ module ActionDispatch class RequestEncoder # :nodoc: @encoders = {} - def initialize(mime_name, param_encoder, url_encoded_form = false) + def initialize(mime_name, param_encoder, response_parser, url_encoded_form = false) @mime = Mime[mime_name] unless @mime @@ -406,7 +407,8 @@ module ActionDispatch @url_encoded_form = url_encoded_form @path_format = ".#{@mime.symbol}" unless @url_encoded_form - @param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc + @response_parser = response_parser || -> body { body } + @param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc end def append_format_to(path) @@ -422,17 +424,21 @@ module ActionDispatch @param_encoder.call(params) end + def parse_body(body) + @response_parser.call(body) + end + def self.encoder(name) @encoders[name] || WWWFormEncoder end - def self.register_encoder(mime_name, ¶m_encoder) - @encoders[mime_name] = new(mime_name, param_encoder) + def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil) + @encoders[mime_name] = new(mime_name, param_encoder, response_parser) end - register_encoder :json + register_encoder :json, response_parser: -> body { JSON.parse(body) } - WWWFormEncoder = new(:url_encoded_form, -> params { params }, true) + WWWFormEncoder = new(:url_encoded_form, -> params { params }, nil, true) end end @@ -696,23 +702,31 @@ module ActionDispatch # require 'test_helper' # # class ApiTest < ActionDispatch::IntegrationTest - # test "creates articles" do + # test 'creates articles' do # assert_difference -> { Article.count } do # post articles_path, params: { article: { title: 'Ahoy!' } }, as: :json # end # # assert_response :success + # assert_equal({ id: Arcticle.last.id, title: 'Ahoy!' }, response.parsed_body) # end # end # # The `as` option sets the format to JSON, sets the content type to # 'application/json' and encodes the parameters as JSON. # + # Calling `parsed_body` on the response parses the response body as what + # the last request was encoded as. If the request wasn't encoded `as` something, + # it's the same as calling `body`. + # # For any custom MIME Types you've registered, you can even add your own encoders with: # - # ActionDispatch::IntegrationTest.register_encoder :wibble do |params| - # params.to_wibble - # end + # ActionDispatch::IntegrationTest.register_encoder :wibble, + # param_encoder: -> params { params.to_wibble }, + # response_parser: -> body { body } + # + # Where `param_encoder` defines how the params should be encoded and + # `response_parser` defines how the response body should be parsed. # # Consult the Rails Testing Guide for more. @@ -743,8 +757,8 @@ module ActionDispatch html_document.root end - def self.register_encoder(*args, ¶m_encoder) - Integration::Session::RequestEncoder.register_encoder(*args, ¶m_encoder) + def self.register_encoder(*args) + Integration::Session::RequestEncoder.register_encoder(*args) end end end diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb index 4b79a90242..58d3e6eb0f 100644 --- a/actionpack/lib/action_dispatch/testing/test_response.rb +++ b/actionpack/lib/action_dispatch/testing/test_response.rb @@ -18,5 +18,11 @@ module ActionDispatch # Was there a server-side error? alias_method :error?, :server_error? + + attr_writer :response_parser # :nodoc: + + def parsed_body + @response_parser.parse_body(body) + end end end diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 296bc1baad..cb524bacb2 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -1129,13 +1129,23 @@ end class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest class FooController < ActionController::Base - def foos + def foos_json + render json: params.permit(:foo) + end + + def foos_wibble render plain: 'ok' end end def test_encoding_as_json - assert_encoded_as :json, content_type: 'application/json' + post_to_foos as: :json do + assert_response :success + assert_match 'foos_json.json', request.path + assert_equal 'application/json', request.content_type + assert_equal({ 'foo' => 'fighters' }, request.request_parameters) + assert_equal({ 'foo' => 'fighters' }, response.parsed_body) + end end def test_encoding_as_without_mime_registration @@ -1147,25 +1157,28 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest def test_registering_custom_encoder Mime::Type.register 'text/wibble', :wibble - ActionDispatch::IntegrationTest.register_encoder(:wibble, &:itself) + ActionDispatch::IntegrationTest.register_encoder(:wibble, + param_encoder: -> params { params }) - assert_encoded_as :wibble, content_type: 'text/wibble', - parsed_parameters: Hash.new # Unregistered MIME Type can't be parsed + post_to_foos as: :wibble do + assert_response :success + assert_match 'foos_wibble.wibble', request.path + assert_equal 'text/wibble', request.content_type + assert_equal Hash.new, request.request_parameters # Unregistered MIME Type can't be parsed. + assert_equal 'ok', response.parsed_body + end ensure Mime::Type.unregister :wibble end private - def assert_encoded_as(format, content_type:, parsed_parameters: { 'foo' => 'fighters' }) + def post_to_foos(as:) with_routing do |routes| routes.draw { post ':action' => FooController } - post '/foos', params: { foo: 'fighters' }, as: format + post "/foos_#{as}", params: { foo: 'fighters' }, as: as - assert_response :success - assert_match "foos.#{format}", request.path - assert_equal content_type, request.content_type - assert_equal parsed_parameters, request.request_parameters + yield end end end -- cgit v1.2.3 From c85b17773e943a227d6b559736aeb40a3b214b71 Mon Sep 17 00:00:00 2001 From: Kasper Timm Hansen Date: Wed, 10 Feb 2016 22:00:13 +0100 Subject: Add request encoding and response parsing to changelog. Forgot to add this in the original pull request. No biggie, just show some examples. --- actionpack/CHANGELOG.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 93e598e493..bf964d06e9 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,41 @@ +* Add request encoding and response parsing to integration tests. + + What previously was: + + ```ruby + require 'test_helper' + + class ApiTest < ActionDispatch::IntegrationTest + test 'creates articles' do + assert_difference -> { Article.count } do + post articles_path(format: :json), + params: { article: { title: 'Ahoy!' } }.to_json, + headers: { 'Content-Type' => 'application/json' } + end + + assert_equal({ id: Article.last.id, title: 'Ahoy!' }, JSON.parse(response.body)) + end + end + ``` + + Can now be written as: + + ```ruby + require 'test_helper' + + class ApiTest < ActionDispatch::IntegrationTest + test 'creates articles' do + assert_difference -> { Article.count } do + post articles_path, { article: { title: 'Ahoy!' } }, as: :json + end + + assert_equal({ id: Article.last.id, title: 'Ahoy!' }, response.parsed_body) + end + end + ``` + + *Kasper Timm Hansen* + * Add image/svg+xml as a default mime type. *DHH* -- cgit v1.2.3