2009-09-24 00:03:24 -04:00
require 'rack/session/abstract/id'
2010-04-14 20:06:11 -04:00
require 'active_support/core_ext/object/to_query'
2011-05-17 14:51:44 -04:00
require 'active_support/core_ext/module/anonymous'
2013-02-01 00:01:04 -05:00
require 'active_support/core_ext/hash/keys'
2007-10-25 22:21:21 -04:00
module ActionController
2010-03-17 17:19:42 -04:00
module TemplateAssertions
extend ActiveSupport :: Concern
included do
setup :setup_subscriptions
teardown :teardown_subscriptions
end
def setup_subscriptions
2012-09-30 04:54:50 -04:00
@_partials = Hash . new ( 0 )
@_templates = Hash . new ( 0 )
@_layouts = Hash . new ( 0 )
2013-02-27 10:44:25 -05:00
@_files = Hash . new ( 0 )
2010-03-17 19:28:05 -04:00
2013-04-07 15:23:16 -04:00
ActiveSupport :: Notifications . subscribe ( " render_template.action_view " ) do | _name , _start , _finish , _id , payload |
2010-03-17 19:28:05 -04:00
path = payload [ :layout ]
2012-04-11 01:55:51 -04:00
if path
2012-09-30 04:54:50 -04:00
@_layouts [ path ] += 1
2012-04-11 02:45:28 -04:00
if path =~ / ^layouts \/ (.*) /
2012-09-30 04:54:50 -04:00
@_layouts [ $1 ] += 1
2012-04-11 02:45:28 -04:00
end
2012-04-11 01:55:51 -04:00
end
2010-03-17 19:28:05 -04:00
end
2013-04-07 15:23:16 -04:00
ActiveSupport :: Notifications . subscribe ( " !render_template.action_view " ) do | _name , _start , _finish , _id , payload |
2010-03-17 17:19:42 -04:00
path = payload [ :virtual_path ]
next unless path
partial = path =~ / ^.* \/ _[^ \/ ]*$ /
2012-04-26 13:46:37 -04:00
2010-03-17 17:19:42 -04:00
if partial
2012-09-30 04:54:50 -04:00
@_partials [ path ] += 1
@_partials [ path . split ( " / " ) . last ] += 1
2010-03-17 17:19:42 -04:00
end
2012-04-26 13:46:37 -04:00
2012-09-30 04:54:50 -04:00
@_templates [ path ] += 1
2010-03-17 17:19:42 -04:00
end
2013-02-27 10:44:25 -05:00
2013-04-07 15:23:16 -04:00
ActiveSupport :: Notifications . subscribe ( " !render_template.action_view " ) do | _name , _start , _finish , _id , payload |
2013-02-27 10:44:25 -05:00
next if payload [ :virtual_path ] # files don't have virtual path
2013-03-10 18:36:27 -04:00
path = payload [ :identifier ]
2013-02-27 10:44:25 -05:00
if path
@_files [ path ] += 1
@_files [ path . split ( " / " ) . last ] += 1
end
end
2010-03-17 17:19:42 -04:00
end
def teardown_subscriptions
2010-04-28 00:16:06 -04:00
ActiveSupport :: Notifications . unsubscribe ( " render_template.action_view " )
ActiveSupport :: Notifications . unsubscribe ( " !render_template.action_view " )
2010-03-17 17:19:42 -04:00
end
2010-10-18 04:57:51 -04:00
def process ( * args )
2012-09-30 04:54:50 -04:00
@_partials = Hash . new ( 0 )
@_templates = Hash . new ( 0 )
@_layouts = Hash . new ( 0 )
2010-10-18 04:57:51 -04:00
super
end
2010-06-22 02:40:22 -04:00
# Asserts that the request was rendered with the appropriate template file or partials.
2010-03-17 17:19:42 -04:00
#
# # assert that the "new" view template was rendered
# assert_template "new"
#
2012-03-10 19:25:12 -05:00
# # assert that the exact template "admin/posts/new" was rendered
# assert_template %r{\Aadmin/posts/new\Z}
#
2012-04-11 02:45:28 -04:00
# # assert that the layout 'admin' was rendered
2012-10-27 16:05:27 -04:00
# assert_template layout: 'admin'
# assert_template layout: 'layouts/admin'
# assert_template layout: :admin
2012-04-11 02:45:28 -04:00
#
# # assert that no layout was rendered
2012-10-27 16:05:27 -04:00
# assert_template layout: nil
# assert_template layout: false
2012-04-11 02:45:28 -04:00
#
2010-03-17 17:19:42 -04:00
# # assert that the "_customer" partial was rendered twice
2012-10-27 16:05:27 -04:00
# assert_template partial: '_customer', count: 2
2010-03-17 17:19:42 -04:00
#
# # assert that no partials were rendered
2012-10-27 16:05:27 -04:00
# assert_template partial: false
2010-03-17 17:19:42 -04:00
#
2010-06-22 02:40:22 -04:00
# In a view test case, you can also assert that specific locals are passed
# to partials:
#
# # assert that the "_customer" partial was rendered with a specific object
2012-10-27 16:05:27 -04:00
# assert_template partial: '_customer', locals: { customer: @customer }
2010-03-17 17:19:42 -04:00
def assert_template ( options = { } , message = nil )
2013-01-17 06:20:02 -05:00
# Force body to be read in case the template is being streamed.
2012-03-05 14:21:04 -05:00
response . body
2010-03-17 17:19:42 -04:00
case options
2012-04-06 23:27:47 -04:00
when NilClass , Regexp , String , Symbol
2010-04-29 09:18:47 -04:00
options = options . to_s if Symbol === options
2012-09-30 04:54:50 -04:00
rendered = @_templates
2012-01-06 14:52:26 -05:00
msg = message || sprintf ( " expecting <%s> but rendering with <%s> " ,
2012-03-10 19:25:12 -05:00
options . inspect , rendered . keys )
2012-09-29 23:21:51 -04:00
matches_template =
2012-04-06 23:27:47 -04:00
case options
when String
2012-11-23 16:10:18 -05:00
! options . empty? && rendered . any? do | t , num |
options_splited = options . split ( File :: SEPARATOR )
t_splited = t . split ( File :: SEPARATOR )
t_splited . last ( options_splited . size ) == options_splited
2012-04-06 23:27:47 -04:00
end
when Regexp
2010-03-17 17:19:42 -04:00
rendered . any? { | t , num | t . match ( options ) }
2012-04-06 23:27:47 -04:00
when NilClass
rendered . blank?
2010-03-17 17:19:42 -04:00
end
2012-05-17 16:17:17 -04:00
assert matches_template , msg
2010-03-17 17:19:42 -04:00
when Hash
2013-02-27 10:44:25 -05:00
options . assert_valid_keys ( :layout , :partial , :locals , :count , :file )
2012-11-25 21:39:08 -05:00
2012-04-11 01:55:51 -04:00
if options . key? ( :layout )
expected_layout = options [ :layout ]
2012-01-06 14:52:26 -05:00
msg = message || sprintf ( " expecting layout <%s> but action rendered <%s> " ,
2012-09-30 04:54:50 -04:00
expected_layout , @_layouts . keys )
2011-12-02 13:13:36 -05:00
case expected_layout
2012-04-11 02:45:28 -04:00
when String , Symbol
2012-09-30 04:54:50 -04:00
assert_includes @_layouts . keys , expected_layout . to_s , msg
2011-12-02 13:13:36 -05:00
when Regexp
2012-09-30 04:54:50 -04:00
assert ( @_layouts . keys . any? { | l | l =~ expected_layout } , msg )
2012-04-11 02:45:28 -04:00
when nil , false
2012-09-30 04:54:50 -04:00
assert ( @_layouts . empty? , msg )
2011-12-02 13:13:36 -05:00
end
end
2013-02-27 10:44:25 -05:00
if options [ :file ]
assert_includes @_files . keys , options [ :file ]
end
2010-03-17 17:19:42 -04:00
if expected_partial = options [ :partial ]
2010-06-22 02:40:22 -04:00
if expected_locals = options [ :locals ]
2012-10-09 15:14:11 -04:00
if defined? ( @_rendered_views )
2012-12-15 14:21:40 -05:00
view = expected_partial . to_s . sub ( / ^_ / , '' ) . sub ( / \/ _(?=[^ \/ ]+ \ z) / , '/' )
2012-12-15 14:20:34 -05:00
partial_was_not_rendered_msg = " expected %s to be rendered but it was not. " % view
assert_includes @_rendered_views . rendered_views , view , partial_was_not_rendered_msg
2012-10-08 16:22:47 -04:00
msg = 'expecting %s to be rendered with %s but was with %s' % [ expected_partial ,
expected_locals ,
2012-10-09 15:14:11 -04:00
@_rendered_views . locals_for ( view ) ]
assert ( @_rendered_views . view_rendered? ( view , options [ :locals ] ) , msg )
2012-10-04 14:55:02 -04:00
else
warn " the :locals option to # assert_template is only supported in a ActionView::TestCase "
2010-06-22 02:40:22 -04:00
end
elsif expected_count = options [ :count ]
2012-09-30 04:54:50 -04:00
actual_count = @_partials [ expected_partial ]
2012-01-06 14:52:26 -05:00
msg = message || sprintf ( " expecting %s to be rendered %s time(s) but rendered %s time(s) " ,
2010-03-17 17:19:42 -04:00
expected_partial , expected_count , actual_count )
assert ( actual_count == expected_count . to_i , msg )
else
2012-01-06 14:52:26 -05:00
msg = message || sprintf ( " expecting partial <%s> but action rendered <%s> " ,
2012-09-30 04:54:50 -04:00
options [ :partial ] , @_partials . keys )
assert_includes @_partials , expected_partial , msg
2010-03-17 17:19:42 -04:00
end
2012-04-11 01:28:19 -04:00
elsif options . key? ( :partial )
2012-09-30 04:54:50 -04:00
assert @_partials . empty? ,
2010-03-17 17:19:42 -04:00
" Expected no partials to be rendered "
end
2012-03-10 19:25:12 -05:00
else
raise ArgumentError , " assert_template only accepts a String, Symbol, Hash, Regexp, or nil "
2010-03-17 17:19:42 -04:00
end
end
end
2009-09-24 00:03:24 -04:00
class TestRequest < ActionDispatch :: TestRequest #:nodoc:
2012-07-03 20:37:47 -04:00
DEFAULT_ENV = ActionDispatch :: TestRequest :: DEFAULT_ENV . dup
DEFAULT_ENV . delete 'PATH_INFO'
2009-09-24 00:03:24 -04:00
def initialize ( env = { } )
super
self . session = TestSession . new
2011-05-23 07:02:06 -04:00
self . session_options = TestSession :: DEFAULT_OPTIONS . merge ( :id = > SecureRandom . hex ( 16 ) )
2009-09-24 00:03:24 -04:00
end
2010-03-30 15:05:42 -04:00
def assign_parameters ( routes , controller_path , action , parameters = { } )
2009-09-24 00:03:24 -04:00
parameters = parameters . symbolize_keys . merge ( :controller = > controller_path , :action = > action )
2010-03-30 15:05:42 -04:00
extra_keys = routes . extra_keys ( parameters )
2009-09-24 00:03:24 -04:00
non_path_parameters = get? ? query_parameters : request_parameters
parameters . each do | key , value |
2012-04-29 05:13:59 -04:00
if value . is_a? ( Array ) && ( value . frozen? || value . any? ( & :frozen? ) )
value = value . map { | v | v . duplicable? ? v . dup : v }
elsif value . is_a? ( Hash ) && ( value . frozen? || value . any? { | k , v | v . frozen? } )
value = Hash [ value . map { | k , v | [ k , v . duplicable? ? v . dup : v ] } ]
elsif value . frozen? && value . duplicable?
2011-02-07 23:08:35 -05:00
value = value . dup
2009-09-24 00:03:24 -04:00
end
if extra_keys . include? ( key . to_sym )
non_path_parameters [ key ] = value
else
2012-04-29 05:13:59 -04:00
if value . is_a? ( Array )
2012-07-03 19:35:07 -04:00
value = value . map ( & :to_param )
2012-04-29 05:13:59 -04:00
else
value = value . to_param
end
2009-09-24 00:03:24 -04:00
path_parameters [ key . to_s ] = value
end
end
2010-06-06 15:07:40 -04:00
# Clear the combined params hash in case it was already referenced.
@env . delete ( " action_dispatch.request.parameters " )
2009-09-24 00:03:24 -04:00
2010-06-06 15:07:40 -04:00
params = self . request_parameters . dup
2009-09-24 00:03:24 -04:00
%w( controller action only_path ) . each do | k |
params . delete ( k )
params . delete ( k . to_sym )
end
data = params . to_query
2010-06-06 15:07:40 -04:00
2009-09-24 00:03:24 -04:00
@env [ 'CONTENT_LENGTH' ] = data . length . to_s
@env [ 'rack.input' ] = StringIO . new ( data )
end
def recycle!
@formats = nil
@env . delete_if { | k , v | k =~ / ^(action_dispatch|rack) \ .request / }
@env . delete_if { | k , v | k =~ / ^action_dispatch \ .rescue / }
2010-08-24 10:05:26 -04:00
@symbolized_path_params = nil
2010-06-04 13:27:21 -04:00
@method = @request_method = nil
2011-08-23 08:12:41 -04:00
@fullpath = @ip = @remote_ip = @protocol = nil
2009-09-24 00:03:24 -04:00
@env [ 'action_dispatch.request.query_parameters' ] = { }
2011-06-05 07:34:27 -04:00
@set_cookies || = { }
@set_cookies . update ( Hash [ cookie_jar . instance_variable_get ( " @set_cookies " ) . map { | k , o | [ k , o [ :value ] ] } ] )
deleted_cookies = cookie_jar . instance_variable_get ( " @delete_cookies " )
@set_cookies . reject! { | k , v | deleted_cookies . include? ( k ) }
cookie_jar . update ( rack_cookies )
cookie_jar . update ( cookies )
cookie_jar . update ( @set_cookies )
cookie_jar . recycle!
2009-09-24 00:03:24 -04:00
end
2012-07-03 20:37:47 -04:00
private
def default_env
DEFAULT_ENV
end
2009-09-24 00:03:24 -04:00
end
class TestResponse < ActionDispatch :: TestResponse
def recycle!
2012-07-29 17:39:03 -04:00
initialize
2009-09-24 00:03:24 -04:00
end
end
2013-01-10 22:34:52 -05:00
# Methods #destroy and #load! are overridden to avoid calling methods on the
# @store object, which does not exist for the TestSession class.
2010-09-20 04:18:44 -04:00
class TestSession < Rack :: Session :: Abstract :: SessionHash #:nodoc:
DEFAULT_OPTIONS = Rack :: Session :: Abstract :: ID :: DEFAULT_OPTIONS
2009-09-24 00:03:24 -04:00
def initialize ( session = { } )
2011-06-19 20:59:45 -04:00
super ( nil , nil )
2013-01-10 22:34:52 -05:00
@id = SecureRandom . hex ( 16 )
@data = stringify_keys ( session )
2009-09-24 00:03:24 -04:00
@loaded = true
end
2010-06-22 09:55:50 -04:00
2010-09-20 04:18:44 -04:00
def exists?
true
end
2013-01-10 22:34:52 -05:00
2013-01-25 15:25:47 -05:00
def keys
@data . keys
end
def values
@data . values
end
2013-01-10 22:34:52 -05:00
def destroy
clear
end
private
def load!
@id
end
2009-09-24 00:03:24 -04:00
end
2008-07-28 07:26:59 -04:00
# Superclass for ActionController functional tests. Functional tests allow you to
# test a single controller action per test method. This should not be confused with
2010-09-24 20:15:52 -04:00
# integration tests (see ActionDispatch::IntegrationTest), which are more like
2010-06-11 06:15:34 -04:00
# "stories" that can involve multiple controllers and multiple actions (i.e. multiple
2008-07-28 07:26:59 -04:00
# different HTTP requests).
2008-07-16 08:00:36 -04:00
#
2008-07-28 07:26:59 -04:00
# == Basic example
#
# Functional tests are written as follows:
2011-05-06 17:03:55 -04:00
# 1. First, one uses the +get+, +post+, +patch+, +put+, +delete+ or +head+ method to simulate
2008-07-28 07:26:59 -04:00
# an HTTP request.
# 2. Then, one asserts whether the current state is as expected. "State" can be anything:
# the controller's HTTP response, the database contents, etc.
#
# For example:
#
# class BooksControllerTest < ActionController::TestCase
# def test_create
# # Simulate a POST response with the given HTTP parameters.
2012-10-27 16:05:27 -04:00
# post(:create, book: { title: "Love Hina" })
2008-07-28 07:26:59 -04:00
#
# # Assert that the controller tried to redirect us to
# # the created book's URI.
# assert_response :found
#
# # Assert that the controller really put the book in the database.
2013-04-02 15:09:15 -04:00
# assert_not_nil Book.find_by(title: "Love Hina")
2008-07-16 08:00:36 -04:00
# end
# end
#
2011-12-28 08:12:21 -05:00
# You can also send a real document in the simulated HTTP request.
#
# def test_create
2012-10-27 16:05:27 -04:00
# json = {book: { title: "Love Hina" }}.to_json
2011-12-28 08:12:21 -05:00
# post :create, json
2012-01-09 22:45:42 -05:00
# end
2011-12-28 08:12:21 -05:00
#
2008-07-28 07:26:59 -04:00
# == Special instance variables
#
# ActionController::TestCase will also automatically provide the following instance
# variables for use in the tests:
#
# <b>@controller</b>::
# The controller instance that will be tested.
# <b>@request</b>::
# An ActionController::TestRequest, representing the current HTTP
# request. You can modify this object before sending the HTTP request. For example,
# you might want to set some session properties before sending a GET request.
# <b>@response</b>::
# An ActionController::TestResponse object, representing the response
# of the last HTTP response. In the above example, <tt>@response</tt> becomes valid
# after calling +post+. If the various assert methods are not sufficient, then you
# may use this object to inspect the HTTP response in detail.
#
2010-08-26 17:10:00 -04:00
# (Earlier versions of \Rails required each functional test to subclass
2008-07-28 07:26:59 -04:00
# Test::Unit::TestCase and define @controller, @request, @response in +setup+.)
2008-07-16 08:00:36 -04:00
#
2008-07-28 07:26:59 -04:00
# == Controller is automatically inferred
2008-07-16 08:00:36 -04:00
#
2008-07-28 07:26:59 -04:00
# ActionController::TestCase will automatically infer the controller under test
# from the test class name. If the controller cannot be inferred from the test
2009-07-25 11:03:58 -04:00
# class name, you can explicitly set it with +tests+.
2008-07-16 08:00:36 -04:00
#
# class SpecialEdgeCaseWidgetsControllerTest < ActionController::TestCase
# tests WidgetController
# end
2008-11-07 13:27:06 -05:00
#
2010-08-26 17:10:00 -04:00
# == \Testing controller internals
2008-11-07 13:27:06 -05:00
#
# In addition to these specific assertions, you also have easy access to various collections that the regular test/unit assertions
# can be used against. These collections are:
#
# * assigns: Instance variables assigned in the action that are available for the view.
# * session: Objects being saved in the session.
# * flash: The flash objects currently in the session.
2010-08-26 17:10:00 -04:00
# * cookies: \Cookies being sent to the user on this request.
2008-11-07 13:27:06 -05:00
#
# These collections can be used just like any other hash:
#
# assert_not_nil assigns(:person) # makes sure that a @person instance variable was set
# assert_equal "Dave", cookies[:name] # makes sure that a cookie called :name was set as "Dave"
# assert flash.empty? # makes sure that there's nothing in the flash
#
2011-12-14 17:38:15 -05:00
# For historic reasons, the assigns hash uses string-based keys. So <tt>assigns[:person]</tt> won't work, but <tt>assigns["person"]</tt> will. To
2008-11-07 13:27:06 -05:00
# appease our yearning for symbols, though, an alternative accessor has been devised using a method call instead of index referencing.
2011-12-14 17:38:15 -05:00
# So <tt>assigns(:person)</tt> will work just like <tt>assigns["person"]</tt>, but again, <tt>assigns[:person]</tt> will not work.
2008-11-07 13:27:06 -05:00
#
2011-12-14 17:38:15 -05:00
# On top of the collections, you have the complete url that a given action redirected to available in <tt>redirect_to_url</tt>.
2008-11-07 13:27:06 -05:00
#
# For redirects within the same controller, you can even call follow_redirect and the redirect will be followed, triggering another
# action call which can then be asserted against.
#
2011-03-29 19:46:27 -04:00
# == Manipulating session and cookie variables
2008-11-07 13:27:06 -05:00
#
2011-03-29 19:46:27 -04:00
# Sometimes you need to set up the session and cookie variables for a test.
# To do this just assign a value to the session or cookie collection:
2008-11-07 13:27:06 -05:00
#
2011-03-29 19:46:27 -04:00
# session[:key] = "value"
# cookies[:key] = "value"
2011-03-06 07:49:44 -05:00
#
2011-03-29 19:46:27 -04:00
# To clear the cookies for a test just clear the cookie collection:
2011-03-06 07:49:44 -05:00
#
2011-03-29 19:46:27 -04:00
# cookies.clear
2008-11-07 13:27:06 -05:00
#
2010-08-26 17:10:00 -04:00
# == \Testing named routes
2008-11-07 13:27:06 -05:00
#
# If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case.
#
2012-10-27 16:05:27 -04:00
# assert_redirected_to page_url(title: 'foo')
2007-10-25 22:21:21 -04:00
class TestCase < ActiveSupport :: TestCase
2010-04-25 17:04:22 -04:00
module Behavior
extend ActiveSupport :: Concern
include ActionDispatch :: TestProcess
2012-09-25 18:04:09 -04:00
include ActiveSupport :: Testing :: ConstantLookup
2009-01-07 16:23:10 -05:00
2010-04-25 17:04:22 -04:00
attr_reader :response , :request
2010-04-08 19:28:19 -04:00
2010-04-25 17:04:22 -04:00
module ClassMethods
2009-09-24 00:03:24 -04:00
2010-04-25 17:04:22 -04:00
# Sets the controller class name. Useful if the name can't be inferred from test class.
2012-05-15 02:51:54 -04:00
# Normalizes +controller_class+ before using.
2011-10-03 02:19:15 -04:00
#
# tests WidgetController
# tests :widget
# tests 'widget'
2010-04-25 17:04:22 -04:00
def tests ( controller_class )
2011-10-03 02:19:15 -04:00
case controller_class
when String , Symbol
2012-01-31 05:44:34 -05:00
self . controller_class = " #{ controller_class . to_s . camelize } Controller " . constantize
2011-10-03 02:19:15 -04:00
when Class
self . controller_class = controller_class
else
raise ArgumentError , " controller class must be a String, Symbol, or Class "
end
2010-04-25 17:04:22 -04:00
end
2010-08-14 01:13:00 -04:00
2010-04-25 17:04:22 -04:00
def controller_class = ( new_class )
prepare_controller_class ( new_class ) if new_class
2010-11-19 12:29:33 -05:00
self . _controller_class = new_class
2010-04-25 17:04:22 -04:00
end
2009-09-24 00:03:24 -04:00
2010-04-25 17:04:22 -04:00
def controller_class
2010-11-19 12:29:33 -05:00
if current_controller_class = self . _controller_class
2010-04-25 17:04:22 -04:00
current_controller_class
else
self . controller_class = determine_default_controller_class ( name )
end
end
2009-09-24 00:03:24 -04:00
2010-04-25 17:04:22 -04:00
def determine_default_controller_class ( name )
2012-09-24 16:15:21 -04:00
determine_constant_from_test_name ( name ) do | constant |
Class === constant && constant < ActionController :: Metal
end
2010-04-25 17:04:22 -04:00
end
2009-09-24 00:03:24 -04:00
2010-04-25 17:04:22 -04:00
def prepare_controller_class ( new_class )
new_class . send :include , ActionController :: TestCase :: RaiseActionExceptions
end
2009-09-24 00:03:24 -04:00
end
2010-04-25 17:04:22 -04:00
2013-03-14 06:48:33 -04:00
# Simulate a GET request with the given parameters.
#
2013-03-15 08:34:58 -04:00
# - +action+: The controller action to call.
2013-03-14 06:48:33 -04:00
# - +parameters+: The HTTP parameters that you want to pass. This may
2013-03-15 08:34:58 -04:00
# be +nil+, a Hash, or a String that is appropriately encoded
# (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
# - +session+: A Hash of parameters to store in the session. This may be +nil+.
# - +flash+: A Hash of parameters to store in the flash. This may be +nil+.
2013-03-14 06:48:33 -04:00
#
# You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
# +#post+, +#patch+, +#put+, +#delete+, and +#head+.
# Note that the request method is not verified. The different methods are
# available to make the tests more expressive.
2011-12-28 08:12:21 -05:00
def get ( action , * args )
process ( action , " GET " , * args )
2009-09-24 00:03:24 -04:00
end
2013-03-14 06:48:33 -04:00
# Simulate a POST request with the given parameters and set/volley the response.
# See +#get+ for more details.
2011-12-28 08:12:21 -05:00
def post ( action , * args )
process ( action , " POST " , * args )
2010-04-25 17:04:22 -04:00
end
2009-09-24 00:03:24 -04:00
2013-03-14 06:48:33 -04:00
# Simulate a PATCH request with the given parameters and set/volley the response.
# See +#get+ for more details.
2011-05-06 17:03:55 -04:00
def patch ( action , * args )
process ( action , " PATCH " , * args )
end
2013-03-14 06:48:33 -04:00
# Simulate a PUT request with the given parameters and set/volley the response.
# See +#get+ for more details.
2011-12-28 08:12:21 -05:00
def put ( action , * args )
process ( action , " PUT " , * args )
2010-04-25 17:04:22 -04:00
end
2008-11-07 13:27:06 -05:00
2013-03-14 06:48:33 -04:00
# Simulate a DELETE request with the given parameters and set/volley the response.
# See +#get+ for more details.
2011-12-28 08:12:21 -05:00
def delete ( action , * args )
process ( action , " DELETE " , * args )
2009-02-03 01:39:02 -05:00
end
2008-04-27 20:42:13 -04:00
2013-03-14 06:48:33 -04:00
# Simulate a HEAD request with the given parameters and set/volley the response.
# See +#get+ for more details.
2012-07-04 08:57:31 -04:00
def head ( action , * args )
process ( action , " HEAD " , * args )
end
2013-03-14 06:48:33 -04:00
# Simulate a OPTIONS request with the given parameters and set/volley the response.
# See +#get+ for more details.
2012-07-04 08:57:31 -04:00
def options ( action , * args )
process ( action , " OPTIONS " , * args )
2010-04-25 17:04:22 -04:00
end
2009-01-07 17:39:47 -05:00
2010-04-25 17:04:22 -04:00
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 ( ', ' )
2010-07-25 04:21:16 -04:00
__send__ ( request_method , action , parameters , session , flash ) . tap do
2010-04-25 17:04:22 -04:00
@request . env . delete 'HTTP_X_REQUESTED_WITH'
@request . env . delete 'HTTP_ACCEPT'
end
end
alias xhr :xml_http_request
2011-05-22 08:11:54 -04:00
def paramify_values ( hash_or_array_or_value )
2011-05-22 02:47:54 -04:00
case hash_or_array_or_value
when Hash
2011-08-23 06:07:37 -04:00
Hash [ hash_or_array_or_value . map { | key , value | [ key , paramify_values ( value ) ] } ]
2011-05-22 02:47:54 -04:00
when Array
2011-05-22 08:11:54 -04:00
hash_or_array_or_value . map { | i | paramify_values ( i ) }
2012-06-21 04:16:28 -04:00
when Rack :: Test :: UploadedFile , ActionDispatch :: Http :: UploadedFile
2011-05-22 02:47:54 -04:00
hash_or_array_or_value
2011-05-22 08:11:54 -04:00
else
hash_or_array_or_value . to_param
2011-05-22 02:47:54 -04:00
end
end
2011-12-28 08:12:21 -05:00
def process ( action , http_method = 'GET' , * args )
check_required_ivars
2012-10-29 11:22:59 -04:00
http_method , args = handle_old_process_api ( http_method , args , caller )
2012-01-05 17:38:36 -05:00
2012-01-09 23:57:35 -05:00
if args . first . is_a? ( String ) && http_method != 'HEAD'
2011-12-28 08:12:21 -05:00
@request . env [ 'RAW_POST_DATA' ] = args . shift
end
2012-01-05 17:38:36 -05:00
2011-12-28 08:12:21 -05:00
parameters , session , flash = args
2012-01-05 17:38:36 -05:00
2011-05-22 02:47:54 -04:00
# Ensure that numbers and symbols passed as params are converted to
2011-05-22 08:11:54 -04:00
# proper params, as is the case when engaging rack.
2012-04-29 05:13:59 -04:00
parameters = paramify_values ( parameters ) if html_format? ( parameters )
2011-05-22 02:47:54 -04:00
2012-07-03 20:29:46 -04:00
@html_document = nil
2012-07-03 20:18:31 -04:00
unless @controller . respond_to? ( :recycle! )
@controller . extend ( Testing :: Functional )
@controller . class . class_eval { include Testing }
end
2010-04-25 17:04:22 -04:00
@request . recycle!
@response . recycle!
2012-07-03 20:18:31 -04:00
@controller . recycle!
2008-01-05 08:34:15 -05:00
2010-04-25 17:04:22 -04:00
@request . env [ 'REQUEST_METHOD' ] = http_method
2008-01-05 08:34:15 -05:00
2012-07-05 18:46:14 -04:00
parameters || = { }
2011-05-17 14:51:44 -04:00
controller_class_name = @controller . class . anonymous? ?
2012-04-29 12:30:57 -04:00
" anonymous " :
2011-05-17 14:51:44 -04:00
@controller . class . name . underscore . sub ( / _controller$ / , '' )
2011-05-17 06:55:03 -04:00
@request . assign_parameters ( @routes , controller_class_name , action . to_s , parameters )
2007-10-25 22:21:21 -04:00
2012-04-28 17:23:58 -04:00
@request . session . update ( session ) if session
2012-10-23 15:15:53 -04:00
@request . flash . update ( flash || { } )
2007-10-25 22:21:21 -04:00
2012-07-02 17:29:19 -04:00
@controller . request = @request
@controller . response = @response
2010-04-25 17:04:22 -04:00
build_request_uri ( action , parameters )
2012-07-03 20:13:04 -04:00
2012-07-02 17:43:56 -04:00
name = @request . parameters [ :action ]
2012-07-02 18:14:55 -04:00
2012-07-02 17:43:56 -04:00
@controller . process ( name )
2012-07-02 18:14:55 -04:00
if cookies = @request . env [ 'action_dispatch.cookies' ]
cookies . write ( @response )
end
@response . prepare!
2010-11-06 19:07:20 -04:00
@assigns = @controller . respond_to? ( :view_assigns ) ? @controller . view_assigns : { }
2012-10-23 15:15:53 -04:00
@request . session [ 'flash' ] = @request . flash . to_session_value
2010-04-25 17:04:22 -04:00
@request . session . delete ( 'flash' ) if @request . session [ 'flash' ] . blank?
@response
2007-10-25 22:21:21 -04:00
end
2010-04-25 17:04:22 -04:00
def setup_controller_request_and_response
2012-07-29 22:23:19 -04:00
@request = build_request
@response = build_response
2012-07-03 20:29:46 -04:00
@response . request = @request
2007-10-25 22:21:21 -04:00
2012-07-28 23:40:27 -04:00
@controller = nil unless defined? @controller
2010-04-25 17:04:22 -04:00
if klass = self . class . controller_class
2012-07-28 23:40:27 -04:00
unless @controller
begin
@controller = klass . new
rescue
warn " could not construct controller #{ klass } " if $VERBOSE
end
end
2010-04-25 17:04:22 -04:00
end
2007-10-25 22:21:21 -04:00
2012-07-28 23:40:27 -04:00
if @controller
2010-04-25 17:04:22 -04:00
@controller . request = @request
@controller . params = { }
end
2008-11-07 15:42:34 -05:00
end
2012-07-29 22:23:19 -04:00
def build_request
TestRequest . new
end
def build_response
TestResponse . new
end
2010-04-25 17:04:22 -04:00
included do
include ActionController :: TemplateAssertions
include ActionDispatch :: Assertions
2010-11-19 12:29:33 -05:00
class_attribute :_controller_class
2010-04-25 17:04:22 -04:00
setup :setup_controller_request_and_response
end
2009-09-24 00:03:24 -04:00
2012-07-03 20:18:31 -04:00
private
2011-12-28 08:12:21 -05:00
def check_required_ivars
# Sanity check for required instance variables so we can give an
# understandable error message.
2012-01-07 06:44:47 -05:00
[ :@routes , :@controller , :@request , :@response ] . each do | iv_name |
if ! instance_variable_defined? ( iv_name ) || instance_variable_get ( iv_name ) . nil?
2011-12-28 08:12:21 -05:00
raise " #{ iv_name } is nil: make sure you set it in your test's setup method. "
end
end
end
2012-01-05 17:38:36 -05:00
2012-10-29 11:22:59 -04:00
def handle_old_process_api ( http_method , args , callstack )
2012-01-05 17:52:49 -05:00
# 4.0: Remove this method.
if http_method . is_a? ( Hash )
2012-10-29 11:22:59 -04:00
ActiveSupport :: Deprecation . warn ( " TestCase # process now expects the HTTP method as second argument: process(action, http_method, params, session, flash) " , callstack )
2012-01-05 17:52:49 -05:00
args . unshift ( http_method )
http_method = args . last . is_a? ( String ) ? args . last : " GET "
end
[ http_method , args ]
end
2010-03-09 21:50:35 -05:00
def build_request_uri ( action , parameters )
unless @request . env [ " PATH_INFO " ]
2010-11-06 19:00:26 -04:00
options = @controller . respond_to? ( :url_options ) ? @controller . __send__ ( :url_options ) . merge ( parameters ) : parameters
2010-03-09 21:50:35 -05:00
options . update (
:only_path = > true ,
:action = > action ,
:relative_url_root = > nil ,
2012-08-04 07:55:00 -04:00
:_recall = > @request . symbolized_path_parameters )
2010-03-09 21:50:35 -05:00
2010-03-30 15:05:42 -04:00
url , query_string = @routes . url_for ( options ) . split ( " ? " , 2 )
2010-03-09 21:50:35 -05:00
@request . env [ " SCRIPT_NAME " ] = @controller . config . relative_url_root
@request . env [ " PATH_INFO " ] = url
@request . env [ " QUERY_STRING " ] = query_string || " "
end
2009-09-24 00:03:24 -04:00
end
2012-04-29 05:13:59 -04:00
def html_format? ( parameters )
return true unless parameters . is_a? ( Hash )
2012-07-03 20:51:27 -04:00
Mime . fetch ( parameters [ :format ] ) { Mime [ 'html' ] } . html?
2012-04-29 05:13:59 -04:00
end
2010-03-02 21:57:02 -05:00
end
2010-04-25 17:04:22 -04:00
# When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
2010-06-11 06:15:34 -04:00
# (skipping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
2010-04-25 17:04:22 -04:00
# rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
# than 0.0.0.0.
#
# The exception is stored in the exception accessor for further inspection.
module RaiseActionExceptions
2012-06-22 17:29:59 -04:00
def self . included ( base ) #:nodoc:
2010-09-28 16:08:43 -04:00
unless base . method_defined? ( :exception ) && base . method_defined? ( :exception = )
base . class_eval do
attr_accessor :exception
protected :exception , :exception =
end
2010-04-25 17:04:22 -04:00
end
end
protected
def rescue_action_without_handler ( e )
self . exception = e
if request . remote_addr == " 0.0.0.0 "
raise ( e )
else
super ( e )
end
end
end
include Behavior
end
2008-07-28 07:26:59 -04:00
end