aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb83
-rw-r--r--actionpack/test/controller/integration_test.rb43
2 files changed, 122 insertions, 4 deletions
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 6f51accee7..61bd39c186 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -321,7 +321,9 @@ module ActionDispatch
end
# Performs the actual request.
- def process(method, path, params: nil, headers: nil, env: nil, xhr: false)
+ def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: nil)
+ request_encoder = RequestEncoder.encoder(as)
+
if path =~ %r{://}
location = URI.parse(path)
https! URI::HTTPS === location if location.scheme
@@ -330,14 +332,17 @@ module ActionDispatch
url_host += ":#{location.port}" if default != location.port
host! url_host
end
- path = location.query ? "#{location.path}?#{location.query}" : location.path
+ path = request_encoder.append_format_to location.path
+ path = location.query ? "#{path}?#{location.query}" : path
+ else
+ path = request_encoder.append_format_to path
end
hostname, port = host.split(':')
request_env = {
:method => method,
- :params => params,
+ :params => request_encoder.encode_params(params),
"SERVER_NAME" => hostname,
"SERVER_PORT" => port || (https? ? "443" : "80"),
@@ -347,7 +352,7 @@ module ActionDispatch
"REQUEST_URI" => path,
"HTTP_HOST" => host,
"REMOTE_ADDR" => remote_addr,
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
+ "CONTENT_TYPE" => request_encoder.content_type,
"HTTP_ACCEPT" => accept
}
@@ -387,6 +392,48 @@ module ActionDispatch
def build_full_uri(path, env)
"#{env['rack.url_scheme']}://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{path}"
end
+
+ class RequestEncoder # :nodoc:
+ @encoders = {}
+
+ def initialize(mime_name, param_encoder, url_encoded_form = false)
+ @mime = Mime[mime_name]
+
+ unless @mime
+ raise ArgumentError, "Can't register a request encoder for " \
+ "unregistered MIME Type: #{mime_name}. See `Mime::Type.register`."
+ end
+
+ @url_encoded_form = url_encoded_form
+ @path_format = ".#{@mime.symbol}" unless @url_encoded_form
+ @param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc
+ end
+
+ def append_format_to(path)
+ path << @path_format unless @url_encoded_form
+ path
+ end
+
+ def content_type
+ @mime.to_s
+ end
+
+ def encode_params(params)
+ @param_encoder.call(params)
+ end
+
+ def self.encoder(name)
+ @encoders[name] || WWWFormEncoder
+ end
+
+ def self.register_encoder(mime_name, &param_encoder)
+ @encoders[mime_name] = new(mime_name, param_encoder)
+ end
+
+ register_encoder :json
+
+ WWWFormEncoder = new(:url_encoded_form, -> params { params }, true)
+ end
end
module Runner
@@ -643,6 +690,30 @@ module ActionDispatch
# end
# end
#
+ # You can also test your JSON API easily by setting what the request should
+ # be encoded as:
+ #
+ # require 'test_helper'
+ #
+ # class ApiTest < ActionDispatch::IntegrationTest
+ # test "creates articles" do
+ # assert_difference -> { Article.count } do
+ # post articles_path, params: { article: { title: 'Ahoy!' } }, as: :json
+ # end
+ #
+ # assert_response :success
+ # end
+ # end
+ #
+ # The `as` option sets the format to JSON, sets the content type to
+ # 'application/json' and encodes the parameters as JSON.
+ #
+ # 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
+ #
# Consult the Rails Testing Guide for more.
class IntegrationTest < ActiveSupport::TestCase
@@ -671,5 +742,9 @@ module ActionDispatch
def document_root_element
html_document.root
end
+
+ def self.register_encoder(*args, &param_encoder)
+ Integration::Session::RequestEncoder.register_encoder(*args, &param_encoder)
+ end
end
end
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index d0a1d1285f..296bc1baad 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -1126,3 +1126,46 @@ class IntegrationRequestsWithSessionSetup < ActionDispatch::IntegrationTest
assert_equal({"user_name"=>"david"}, cookies.to_hash)
end
end
+
+class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest
+ class FooController < ActionController::Base
+ def foos
+ render plain: 'ok'
+ end
+ end
+
+ def test_encoding_as_json
+ assert_encoded_as :json, content_type: 'application/json'
+ end
+
+ def test_encoding_as_without_mime_registration
+ assert_raise ArgumentError do
+ ActionDispatch::IntegrationTest.register_encoder :wibble
+ end
+ end
+
+ def test_registering_custom_encoder
+ Mime::Type.register 'text/wibble', :wibble
+
+ ActionDispatch::IntegrationTest.register_encoder(:wibble, &:itself)
+
+ assert_encoded_as :wibble, content_type: 'text/wibble',
+ parsed_parameters: Hash.new # Unregistered MIME Type can't be parsed
+ ensure
+ Mime::Type.unregister :wibble
+ end
+
+ private
+ def assert_encoded_as(format, content_type:, parsed_parameters: { 'foo' => 'fighters' })
+ with_routing do |routes|
+ routes.draw { post ':action' => FooController }
+
+ post '/foos', params: { foo: 'fighters' }, as: format
+
+ assert_response :success
+ assert_match "foos.#{format}", request.path
+ assert_equal content_type, request.content_type
+ assert_equal parsed_parameters, request.request_parameters
+ end
+ end
+end