aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/testing
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/testing')
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb3
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb154
-rw-r--r--actionpack/lib/action_dispatch/testing/test_process.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/test_response.rb6
4 files changed, 139 insertions, 25 deletions
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 78ef860548..44ad2c10d8 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -86,6 +86,7 @@ module ActionDispatch
end
# Load routes.rb if it hasn't been loaded.
+ options = options.clone
generated_path, query_string_keys = @routes.generate_extras(options, defaults)
found_extras = options.reject { |k, _| ! query_string_keys.include? k }
@@ -116,7 +117,7 @@ module ActionDispatch
# # Tests a route, providing a defaults hash
# assert_routing 'controller/action/9', {id: "9", item: "square"}, {controller: "controller", action: "action"}, {}, {item: "square"}
#
- # # Tests a route with a HTTP method
+ # # Tests a route with an HTTP method
# assert_routing({ method: 'put', path: '/product/321' }, { controller: "product", action: "update", id: "321" })
def assert_routing(path, options, defaults={}, extras={}, message=nil)
assert_recognizes(options, path, extras, message)
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 711ca10419..60c562d7cd 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -71,7 +71,7 @@ module ActionDispatch
end
# Performs an XMLHttpRequest request with the given parameters, mirroring
- # a request from the Prototype library.
+ # an AJAX request made from JavaScript.
#
# The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or
# +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart
@@ -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
}
@@ -376,6 +381,7 @@ module ActionDispatch
response = _mock_session.last_response
@response = ActionDispatch::TestResponse.from_response(response)
@response.request = @request
+ @response.response_parser = RequestEncoder.parser(@response.content_type)
@html_document = nil
@url_options = nil
@@ -387,6 +393,56 @@ module ActionDispatch
def build_full_uri(path, env)
"#{env['rack.url_scheme']}://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{path}"
end
+
+ class RequestEncoder # :nodoc:
+ @encoders = {}
+
+ attr_reader :response_parser
+
+ def initialize(mime_name, param_encoder, response_parser, 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
+ @response_parser = response_parser || -> body { body }
+ @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.parser(content_type)
+ mime = Mime::Type.lookup(content_type)
+ encoder(mime ? mime.ref : nil).response_parser
+ end
+
+ def self.encoder(name)
+ @encoders[name] || WWWFormEncoder
+ end
+
+ 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, response_parser: -> body { JSON.parse(body) }
+
+ WWWFormEncoder = new(:url_encoded_form, -> params { params }, nil, true)
+ end
end
module Runner
@@ -643,33 +699,85 @@ 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
+ # 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,
+ # 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 through
+ # `parsed_body`.
+ #
# Consult the Rails Testing Guide for more.
class IntegrationTest < ActiveSupport::TestCase
- include Integration::Runner
- include ActionController::TemplateAssertions
- include ActionDispatch::Routing::UrlFor
+ module UrlOptions
+ extend ActiveSupport::Concern
+ def url_options
+ integration_session.url_options
+ end
+ end
- @@app = nil
+ module Behavior
+ extend ActiveSupport::Concern
- def self.app
- @@app || ActionDispatch.test_app
- end
+ include Integration::Runner
+ include ActionController::TemplateAssertions
- def self.app=(app)
- @@app = app
- end
+ included do
+ include ActionDispatch::Routing::UrlFor
+ include UrlOptions # don't let UrlFor override the url_options method
+ ActiveSupport.run_load_hooks(:action_dispatch_integration_test, self)
+ @@app = nil
+ end
- def app
- super || self.class.app
- end
+ module ClassMethods
+ def app
+ defined?(@@app) ? @@app : ActionDispatch.test_app
+ end
- def url_options
- integration_session.url_options
- end
+ def app=(app)
+ @@app = app
+ end
- def document_root_element
- html_document.root
+ def register_encoder(*args)
+ Integration::Session::RequestEncoder.register_encoder(*args)
+ end
+ end
+
+ def app
+ super || self.class.app
+ end
+
+ def document_root_element
+ html_document.root
+ end
end
+
+ include Behavior
end
end
diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb
index eca0439909..1ecd7d14a7 100644
--- a/actionpack/lib/action_dispatch/testing/test_process.rb
+++ b/actionpack/lib/action_dispatch/testing/test_process.rb
@@ -1,6 +1,5 @@
require 'action_dispatch/middleware/cookies'
require 'action_dispatch/middleware/flash'
-require 'active_support/core_ext/hash/indifferent_access'
module ActionDispatch
module TestProcess
diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb
index 4b79a90242..9d4b73a43d 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
+ @parsed_body ||= @response_parser.call(body)
+ end
end
end