module ActionController::TestCase::Behavior
def build_request
def build_request TestRequest.new end
def build_request_uri(action, parameters)
def build_request_uri(action, parameters) unless @request.env["PATH_INFO"] options = @controller.respond_to?(:url_options) ? @controller.__send__(:url_options).merge(parameters) : parameters options.update( :action => action, :relative_url_root => nil, :_recall => @request.path_parameters) if route_name = options.delete(:use_route) ActiveSupport::Deprecation.warn <<-MSG.squish Passing the `use_route` option in functional tests are deprecated. Support for this option in the `process` method (and the related `get`, `head`, `post`, `patch`, `put` and `delete` helpers) will be removed in the next version without replacement. Functional tests are essentially unit tests for controllers and they should not require knowledge to how the application's routes are configured. Instead, you should explicitly pass the appropiate params to the `process` method. Previously the engines guide also contained an incorrect example that recommended using this option to test an engine's controllers within the dummy application. That recommendation was incorrect and has since been corrected. Instead, you should override the `@routes` variable in the test case with `Foo::Engine.routes`. See the updated engines guide for details. MSG end url, query_string = @routes.path_for(options, route_name).split("?", 2) @request.env["SCRIPT_NAME"] = @controller.config.relative_url_root @request.env["PATH_INFO"] = url @request.env["QUERY_STRING"] = query_string || "" end end
def build_response(klass)
def build_response(klass) klass.new end
def check_required_ivars
def check_required_ivars # Sanity check for required instance variables so we can give an # understandable error message. [:@routes, :@controller, :@request, :@response].each do |iv_name| if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil? raise "#{iv_name} is nil: make sure you set it in your test's setup method." end end end
def delete(action, *args)
Simulate a DELETE request with the given parameters and set/volley the response.
def delete(action, *args) process(action, "DELETE", *args) end
def document_root_element
def document_root_element html_document.root end
def get(action, *args)
Note that the request method is not verified. The different methods are
+post+, +patch+, +put+, +delete+, and +head+.
You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
- +flash+: A hash of parameters to store in the flash. This may be +nil+.
- +session+: A hash of parameters to store in the session. This may be +nil+.
(application/x-www-form-urlencoded or multipart/form-data).
be +nil+, a hash, or a string that is appropriately encoded
- +parameters+: The HTTP parameters that you want to pass. This may
- +action+: The controller action to call.
Simulate a GET request with the given parameters.
def get(action, *args) process(action, "GET", *args) end
def head(action, *args)
Simulate a HEAD request with the given parameters and set/volley the response.
def head(action, *args) process(action, "HEAD", *args) end
def html_format?(parameters)
def html_format?(parameters) return true unless parameters.key?(:format) Mime.fetch(parameters[:format]) { Mime['html'] }.html? end
def paramify_values(hash_or_array_or_value)
def paramify_values(hash_or_array_or_value) case hash_or_array_or_value when Hash Hash[hash_or_array_or_value.map{|key, value| [key, paramify_values(value)] }] when Array hash_or_array_or_value.map {|i| paramify_values(i)} when Rack::Test::UploadedFile, ActionDispatch::Http::UploadedFile hash_or_array_or_value else hash_or_array_or_value.to_param end end
def patch(action, *args)
Simulate a PATCH request with the given parameters and set/volley the response.
def patch(action, *args) process(action, "PATCH", *args) end
def post(action, *args)
Simulate a POST request with the given parameters and set/volley the response.
def post(action, *args) process(action, "POST", *args) end
def process(action, http_method = 'GET', *args)
respectively which will make tests more expressive.
prefer using #get, #post, #patch, #put, #delete and #head methods
To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE+ and +HEAD+ requests
process :view, 'GET', { id: 7 }, nil, { notice: 'This is flash message' }
Example sending parameters, +nil+ session and setting a flash message:
process :create, 'POST', user: { name: 'Gaurish Sharma', email: 'user@example.com' }
Example calling +create+ action and sending two params:
- +flash+: A hash of parameters to store in the flash. This may be +nil+.
- +session+: A hash of parameters to store in the session. This may be +nil+.
or +multipart/form-data+).
string that is appropriately encoded (+application/x-www-form-urlencoded+
- +parameters+: The HTTP parameters. This may be +nil+, a hash, or a
are +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, +HEAD+. Defaults to +GET+.
- +http_method+: Request method used to send the http request. Possible values
- +action+: The controller action to call.
parameters and set/volley the response.
Simulate a HTTP request to +action+ by specifying request method,
def process(action, http_method = 'GET', *args) check_required_ivars if args.first.is_a?(String) && http_method != 'HEAD' @request.env['RAW_POST_DATA'] = args.shift end parameters, session, flash = args parameters ||= {} # Ensure that numbers and symbols passed as params are converted to # proper params, as is the case when engaging rack. parameters = paramify_values(parameters) if html_format?(parameters) @html_document = nil unless @controller.respond_to?(:recycle!) @controller.extend(Testing::Functional) end @request.recycle! @response.recycle! @controller.recycle! @request.env['REQUEST_METHOD'] = http_method controller_class_name = @controller.class.anonymous? ? "anonymous" : @controller.class.controller_path @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters) @request.session.update(session) if session @request.flash.update(flash || {}) @controller.request = @request @controller.response = @response build_request_uri(action, parameters) name = @request.parameters[:action] @controller.recycle! @controller.process(name) if cookies = @request.env['action_dispatch.cookies'] unless @response.committed? cookies.write(@response) end end @response.prepare! @assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {} if flash_value = @request.flash.to_session_value @request.session['flash'] = flash_value end @response end
def put(action, *args)
Simulate a PUT request with the given parameters and set/volley the response.
def put(action, *args) process(action, "PUT", *args) end
def setup_controller_request_and_response
def setup_controller_request_and_response @controller = nil unless defined? @controller response_klass = TestResponse if klass = self.class.controller_class if klass < ActionController::Live response_klass = LiveTestResponse end unless @controller begin @controller = klass.new rescue warn "could not construct controller #{klass}" if $VERBOSE end end end @request = build_request @response = build_response response_klass @response.request = @request if @controller @controller.request = @request @controller.params = {} end end
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil) @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' @request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ') __send__(request_method, action, parameters, session, flash).tap do @request.env.delete 'HTTP_X_REQUESTED_WITH' @request.env.delete 'HTTP_ACCEPT' end end