2016-08-06 12:51:43 -04:00
require " stringio "
require " uri "
require " active_support/core_ext/kernel/singleton_class "
require " active_support/core_ext/object/try "
require " active_support/core_ext/string/strip "
require " rack/test "
require " minitest "
2009-09-23 23:37:52 -04:00
2016-08-06 12:51:43 -04:00
require " action_dispatch/testing/request_encoder "
2016-07-10 16:02:12 -04:00
2009-09-23 23:37:52 -04:00
module ActionDispatch
2006-03-27 22:19:27 -05:00
module Integration #:nodoc:
2009-04-30 15:28:42 -04:00
module RequestHelpers
# Performs a GET request with the given parameters.
#
# - +path+: The URI (as a String) on which you want to perform a GET
# request.
2015-01-29 09:19:21 -05:00
# - +params+: The HTTP parameters that you want to pass. This may
2009-04-30 15:28:42 -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>).
2015-01-29 09:19:21 -05:00
# - +headers+: Additional headers to pass, as a Hash. The headers will be
2015-01-04 04:35:06 -05:00
# merged into the Rack env hash.
2015-01-29 09:19:21 -05:00
# - +env+: Additional env to pass, as a Hash. The headers will be
2012-05-25 08:58:43 -04:00
# merged into the Rack env hash.
2009-04-30 15:28:42 -04:00
#
2012-09-05 05:30:09 -04:00
# This method returns a Response object, which one can use to
2009-04-30 15:28:42 -04:00
# inspect the details of the response. Furthermore, if this method was
2009-09-23 23:37:52 -04:00
# called from an ActionDispatch::IntegrationTest object, then that
2009-04-30 15:28:42 -04:00
# object's <tt>@response</tt> instance variable will point to the same
# response object.
#
2011-05-06 17:03:55 -04:00
# You can also perform POST, PATCH, PUT, DELETE, and HEAD requests with
# +#post+, +#patch+, +#put+, +#delete+, and +#head+.
2015-01-04 04:35:06 -05:00
#
# Example:
#
# get '/feed', params: { since: 201501011400 }
2015-01-29 09:19:41 -05:00
# post '/profile', headers: { "X-Test-Header" => "testvalue" }
2015-01-04 04:35:06 -05:00
def get ( path , * args )
process_with_kwargs ( :get , path , * args )
2009-04-30 15:28:42 -04:00
end
2011-03-29 01:17:20 -04:00
# Performs a POST request with the given parameters. See +#get+ for more
2009-04-30 15:28:42 -04:00
# details.
2015-01-04 04:35:06 -05:00
def post ( path , * args )
process_with_kwargs ( :post , path , * args )
2009-04-30 15:28:42 -04:00
end
2011-05-06 17:03:55 -04:00
# Performs a PATCH request with the given parameters. See +#get+ for more
# details.
2015-01-04 04:35:06 -05:00
def patch ( path , * args )
process_with_kwargs ( :patch , path , * args )
2011-05-06 17:03:55 -04:00
end
2011-03-29 01:17:20 -04:00
# Performs a PUT request with the given parameters. See +#get+ for more
2009-04-30 15:28:42 -04:00
# details.
2015-01-04 04:35:06 -05:00
def put ( path , * args )
process_with_kwargs ( :put , path , * args )
2009-04-30 15:28:42 -04:00
end
2011-03-29 01:17:20 -04:00
# Performs a DELETE request with the given parameters. See +#get+ for
2009-04-30 15:28:42 -04:00
# more details.
2015-01-04 04:35:06 -05:00
def delete ( path , * args )
process_with_kwargs ( :delete , path , * args )
2009-04-30 15:28:42 -04:00
end
2011-03-29 01:17:20 -04:00
# Performs a HEAD request with the given parameters. See +#get+ for more
2009-04-30 15:28:42 -04:00
# details.
2015-01-04 04:35:06 -05:00
def head ( path , * args )
process_with_kwargs ( :head , path , * args )
2009-04-30 15:28:42 -04:00
end
# Performs an XMLHttpRequest request with the given parameters, mirroring
2016-02-02 20:55:02 -05:00
# an AJAX request made from JavaScript.
2009-04-30 15:28:42 -04:00
#
2011-05-06 17:03:55 -04:00
# The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or
# +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart
2012-05-25 08:58:43 -04:00
# string; the headers are a hash.
2015-01-04 04:35:06 -05:00
#
# Example:
#
# xhr :get, '/feed', params: { since: 201501011400 }
def xml_http_request ( request_method , path , * args )
2015-05-01 09:47:34 -04:00
if kwarg_request? ( args )
2015-01-04 04:35:06 -05:00
params , headers , env = args . first . values_at ( :params , :headers , :env )
else
params = args [ 0 ]
headers = args [ 1 ]
env = { }
if params . present? || headers . present?
non_kwarg_request_warning
end
end
2015-02-01 08:07:42 -05:00
ActiveSupport :: Deprecation . warn ( <<-MSG.strip_heredoc)
xhr and xml_http_request methods are deprecated in favor of
2016-04-10 10:18:06 -04:00
` get "/posts", xhr: true ` and ` post "/posts/1", xhr: true ` .
2015-02-01 08:07:42 -05:00
MSG
process ( request_method , path , params : params , headers : headers , xhr : true )
2009-04-30 15:28:42 -04:00
end
alias xhr :xml_http_request
# Follow a single redirect response. If the last response was not a
# redirect, an exception will be raised. Otherwise, the redirect is
# performed on the location header.
def follow_redirect!
raise " not a redirect! #{ status } #{ status_message } " unless redirect?
get ( response . location )
status
end
# Performs a request using the specified method, following any subsequent
# redirect. Note that the redirects are followed until the response is
# not a redirect--this means you may run into an infinite loop if your
# redirect loops back to itself.
2015-01-04 04:35:06 -05:00
#
# Example:
#
# request_via_redirect :post, '/welcome',
# params: { ref_id: 14 },
2015-01-29 09:19:41 -05:00
# headers: { "X-Test-Header" => "testvalue" }
2015-01-04 04:35:06 -05:00
def request_via_redirect ( http_method , path , * args )
2016-08-06 12:51:43 -04:00
ActiveSupport :: Deprecation . warn ( " `request_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior. " )
2015-01-04 04:35:06 -05:00
process_with_kwargs ( http_method , path , * args )
2009-04-30 15:28:42 -04:00
follow_redirect! while redirect?
status
end
# Performs a GET request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
2015-01-04 04:35:06 -05:00
def get_via_redirect ( path , * args )
2016-08-06 12:51:43 -04:00
ActiveSupport :: Deprecation . warn ( " `get_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior. " )
2015-01-04 04:35:06 -05:00
request_via_redirect ( :get , path , * args )
2009-04-30 15:28:42 -04:00
end
# Performs a POST request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
2015-01-04 04:35:06 -05:00
def post_via_redirect ( path , * args )
2016-08-06 12:51:43 -04:00
ActiveSupport :: Deprecation . warn ( " `post_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior. " )
2015-01-04 04:35:06 -05:00
request_via_redirect ( :post , path , * args )
2009-04-30 15:28:42 -04:00
end
2011-05-06 17:03:55 -04:00
# Performs a PATCH request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
2015-01-04 04:35:06 -05:00
def patch_via_redirect ( path , * args )
2016-08-06 12:51:43 -04:00
ActiveSupport :: Deprecation . warn ( " `patch_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior. " )
2015-01-04 04:35:06 -05:00
request_via_redirect ( :patch , path , * args )
2011-05-06 17:03:55 -04:00
end
2009-04-30 15:28:42 -04:00
# Performs a PUT request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
2015-01-04 04:35:06 -05:00
def put_via_redirect ( path , * args )
2016-08-06 12:51:43 -04:00
ActiveSupport :: Deprecation . warn ( " `put_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior. " )
2015-01-04 04:35:06 -05:00
request_via_redirect ( :put , path , * args )
2009-04-30 15:28:42 -04:00
end
# Performs a DELETE request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
2015-01-04 04:35:06 -05:00
def delete_via_redirect ( path , * args )
2016-08-06 12:51:43 -04:00
ActiveSupport :: Deprecation . warn ( " `delete_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior. " )
2015-01-04 04:35:06 -05:00
request_via_redirect ( :delete , path , * args )
2009-04-30 15:28:42 -04:00
end
end
2010-08-28 18:04:14 -04:00
# An instance of this class represents a set of requests and responses
# performed sequentially by a test process. Because you can instantiate
2006-02-28 13:15:46 -05:00
# multiple sessions and run them side-by-side, you can also mimic (to some
# limited extent) multiple simultaneous users interacting with your system.
#
2008-12-07 17:37:48 -05:00
# Typically, you will instantiate a new session using
# IntegrationTest#open_session, rather than instantiating
# Integration::Session directly.
2006-02-28 13:15:46 -05:00
class Session
2009-05-11 23:04:39 -04:00
DEFAULT_HOST = " www.example.com "
2013-12-18 02:51:24 -05:00
include Minitest :: Assertions
2009-12-12 19:09:44 -05:00
include TestProcess , RequestHelpers , Assertions
2006-02-28 13:15:46 -05:00
2009-04-30 15:28:42 -04:00
%w( status status_message headers body redirect? ) . each do | method |
delegate method , :to = > :response , :allow_nil = > true
end
2009-02-01 02:01:49 -05:00
2009-04-30 15:28:42 -04:00
%w( path ) . each do | method |
delegate method , :to = > :request , :allow_nil = > true
end
2006-02-28 13:15:46 -05:00
# The hostname used in the last request.
2010-04-05 18:01:33 -04:00
def host
@host || DEFAULT_HOST
end
attr_writer :host
2006-03-17 22:27:37 -05:00
# The remote_addr used in the last request.
attr_accessor :remote_addr
2006-02-28 13:15:46 -05:00
2006-03-18 10:09:27 -05:00
# The Accept header to send.
attr_accessor :accept
2006-02-28 13:15:46 -05:00
# A map of the cookies returned by the last response, and which will be
# sent with the next request.
2009-05-11 23:04:39 -04:00
def cookies
2010-04-05 18:01:33 -04:00
_mock_session . cookie_jar
2009-05-11 23:04:39 -04:00
end
2006-02-28 13:15:46 -05:00
# A reference to the controller instance used by the last request.
attr_reader :controller
# A reference to the request instance used by the last request.
attr_reader :request
# A reference to the response instance used by the last request.
attr_reader :response
2007-11-01 03:59:24 -04:00
# A running counter of the number of requests processed.
attr_accessor :request_count
2010-02-26 20:18:29 -05:00
include ActionDispatch :: Routing :: UrlFor
2008-05-25 07:29:00 -04:00
# Create and initialize a new Session instance.
2009-09-26 21:51:05 -04:00
def initialize ( app )
2010-09-29 05:28:38 -04:00
super ( )
2009-09-26 21:51:05 -04:00
@app = app
2010-02-26 20:18:29 -05:00
2006-02-28 13:15:46 -05:00
reset!
end
2012-05-10 15:28:53 -04:00
def url_options
@url_options || = default_url_options . dup . tap do | url_options |
url_options . reverse_merge! ( controller . url_options ) if controller
2014-07-15 21:19:11 -04:00
if @app . respond_to? ( :routes )
2012-05-10 15:28:53 -04:00
url_options . reverse_merge! ( @app . routes . default_url_options )
end
url_options . reverse_merge! ( :host = > host , :protocol = > https? ? " https " : " http " )
end
2010-02-26 20:18:29 -05:00
end
2006-02-28 13:15:46 -05:00
# Resets the instance. This can be used to reset the state information
# in an existing session instance, so it can be used from a clean-slate
# condition.
#
# session.reset!
def reset!
@https = false
@controller = @request = @response = nil
2010-04-05 18:01:33 -04:00
@_mock_session = nil
2007-11-01 03:59:24 -04:00
@request_count = 0
2012-05-10 15:28:53 -04:00
@url_options = nil
2007-05-21 05:15:16 -04:00
2009-05-11 23:04:39 -04:00
self . host = DEFAULT_HOST
2006-03-17 22:27:37 -05:00
self . remote_addr = " 127.0.0.1 "
2008-12-07 17:37:48 -05:00
self . accept = " text/xml,application/xml,application/xhtml+xml, " +
" text/html;q=0.9,text/plain;q=0.8,image/png, " +
" */*;q=0.5 "
2006-03-06 23:42:24 -05:00
2007-01-28 02:16:55 -05:00
unless defined? @named_routes_configured
2006-03-06 23:42:24 -05:00
# the helpers are made protected by default--we make them public for
# easier access during testing and troubleshooting.
@named_routes_configured = true
end
2006-02-28 13:15:46 -05:00
end
# Specify whether or not the session should mimic a secure HTTPS request.
#
# session.https!
# session.https!(false)
2008-12-07 17:37:48 -05:00
def https! ( flag = true )
2007-05-21 05:15:16 -04:00
@https = flag
2006-02-28 13:15:46 -05:00
end
2013-12-03 09:04:25 -05:00
# Returns +true+ if the session is mimicking a secure HTTPS request.
2006-02-28 13:15:46 -05:00
#
# if session.https?
# ...
# end
def https?
@https
end
# Set the host name to use in the next request.
#
2006-03-25 14:43:40 -05:00
# session.host! "www.example.com"
2010-11-30 23:04:31 -05:00
alias :host! :host =
2006-02-28 13:15:46 -05:00
private
2010-04-05 18:01:33 -04:00
def _mock_session
@_mock_session || = Rack :: MockSession . new ( @app , host )
end
2009-05-11 23:04:39 -04:00
2015-01-04 04:35:06 -05:00
def process_with_kwargs ( http_method , path , * args )
2015-05-01 09:47:34 -04:00
if kwarg_request? ( args )
2015-01-04 04:35:06 -05:00
process ( http_method , path , * args )
else
2015-05-31 18:51:33 -04:00
non_kwarg_request_warning if args . any?
2015-01-04 04:35:06 -05:00
process ( http_method , path , { params : args [ 0 ] , headers : args [ 1 ] } )
end
end
2016-05-27 04:43:31 -04:00
REQUEST_KWARGS = % i ( params headers env xhr as )
2015-05-01 09:47:34 -04:00
def kwarg_request? ( args )
2015-01-04 04:35:06 -05:00
args [ 0 ] . respond_to? ( :keys ) && args [ 0 ] . keys . any? { | k | REQUEST_KWARGS . include? ( k ) }
end
def non_kwarg_request_warning
ActiveSupport :: Deprecation . warn ( <<-MSG.strip_heredoc)
2015-02-13 06:03:35 -05:00
ActionDispatch :: IntegrationTest HTTP request methods will accept only
2015-02-13 02:30:13 -05:00
the following keyword arguments in future Rails versions :
#{REQUEST_KWARGS.join(', ')}
2015-01-04 04:35:06 -05:00
Examples :
get '/profile' ,
params : { id : 1 } ,
headers : { 'X-Extra-Header' = > '123' } ,
2015-02-13 13:25:13 -05:00
env : { 'action_dispatch.custom' = > 'custom' } ,
2016-05-27 04:43:31 -04:00
xhr : true ,
as : :json
2015-01-04 04:35:06 -05:00
MSG
end
2006-02-28 13:15:46 -05:00
# Performs the actual request.
2015-09-18 18:11:18 -04:00
def process ( method , path , params : nil , headers : nil , env : nil , xhr : false , as : nil )
request_encoder = RequestEncoder . encoder ( as )
2016-08-05 14:20:21 -04:00
headers || = { }
if method == :get && as == :json && params
2016-08-06 12:51:43 -04:00
headers [ " X-Http-Method-Override " ] = " GET "
2016-08-05 14:20:21 -04:00
method = :post
end
2015-09-18 18:11:18 -04:00
2009-04-30 15:28:42 -04:00
if path =~ %r{ :// }
2016-06-25 05:13:42 -04:00
path = build_expanded_path ( path , request_encoder ) do | location |
https! URI :: HTTPS === location if location . scheme
if url_host = location . host
default = Rack :: Request :: DEFAULT_PORTS [ location . scheme ]
url_host += " : #{ location . port } " if default != location . port
host! url_host
end
2015-08-06 20:22:22 -04:00
end
2016-06-25 05:05:38 -04:00
elsif as
2016-06-25 05:13:42 -04:00
path = build_expanded_path ( path , request_encoder )
2009-04-30 15:28:42 -04:00
end
2006-02-28 13:15:46 -05:00
2016-08-06 12:51:43 -04:00
hostname , port = host . split ( " : " )
2010-09-22 20:09:06 -04:00
2015-01-04 04:35:06 -05:00
request_env = {
2009-04-30 18:26:03 -04:00
:method = > method ,
2015-09-18 18:11:18 -04:00
:params = > request_encoder . encode_params ( params ) ,
2008-12-07 17:37:48 -05:00
2010-09-26 11:06:19 -04:00
" SERVER_NAME " = > hostname ,
2010-09-26 16:54:00 -04:00
" SERVER_PORT " = > port || ( https? ? " 443 " : " 80 " ) ,
2008-12-07 17:37:48 -05:00
" HTTPS " = > https? ? " on " : " off " ,
" rack.url_scheme " = > https? ? " https " : " http " ,
2006-02-28 13:15:46 -05:00
" REQUEST_URI " = > path ,
2010-09-26 11:06:19 -04:00
" HTTP_HOST " = > host ,
2006-03-17 22:27:37 -05:00
" REMOTE_ADDR " = > remote_addr ,
2015-09-18 18:11:18 -04:00
" CONTENT_TYPE " = > request_encoder . content_type ,
2010-04-02 14:54:10 -04:00
" HTTP_ACCEPT " = > accept
2009-04-24 21:24:03 -04:00
}
2015-02-01 08:07:42 -05:00
if xhr
2016-08-06 12:51:43 -04:00
headers [ " HTTP_X_REQUESTED_WITH " ] = " XMLHttpRequest "
headers [ " HTTP_ACCEPT " ] || = [ Mime [ :js ] , Mime [ :html ] , Mime [ :xml ] , " text/xml " , " */* " ] . join ( " , " )
2015-02-01 08:07:42 -05:00
end
2015-01-04 04:35:06 -05:00
# this modifies the passed request_env directly
if headers . present?
2015-08-20 18:57:15 -04:00
Http :: Headers . from_hash ( request_env ) . merge! ( headers )
2015-01-04 04:35:06 -05:00
end
if env . present?
2015-08-20 18:57:15 -04:00
Http :: Headers . from_hash ( request_env ) . merge! ( env )
2015-01-04 04:35:06 -05:00
end
2009-08-31 16:39:19 -04:00
2010-04-05 18:01:33 -04:00
session = Rack :: Test :: Session . new ( _mock_session )
2010-04-03 23:23:23 -04:00
2010-04-05 18:01:33 -04:00
# NOTE: rack-test v0.5 doesn't build a default uri correctly
# Make sure requested path is always a full uri
2015-01-04 04:35:06 -05:00
session . request ( build_full_uri ( path , request_env ) , request_env )
2009-04-26 12:37:11 -04:00
2007-11-01 03:59:24 -04:00
@request_count += 1
2009-09-01 00:08:20 -04:00
@request = ActionDispatch :: Request . new ( session . last_request . env )
2010-04-05 18:01:33 -04:00
response = _mock_session . last_response
2015-02-24 19:28:45 -05:00
@response = ActionDispatch :: TestResponse . from_response ( response )
2015-12-01 14:28:01 -05:00
@response . request = @request
2009-04-26 12:37:11 -04:00
@html_document = nil
2012-05-10 15:28:53 -04:00
@url_options = nil
2008-12-17 09:21:20 -05:00
2015-08-07 19:00:57 -04:00
@controller = @request . controller_instance
2010-01-20 09:59:26 -05:00
2015-02-01 08:07:42 -05:00
response . status
2006-02-28 13:15:46 -05:00
end
2014-05-13 22:30:57 -04:00
def build_full_uri ( path , env )
" #{ env [ 'rack.url_scheme' ] } :// #{ env [ 'SERVER_NAME' ] } : #{ env [ 'SERVER_PORT' ] } #{ path } "
end
2015-09-18 18:11:18 -04:00
2016-06-25 05:13:42 -04:00
def build_expanded_path ( path , request_encoder )
location = URI . parse ( path )
yield location if block_given?
path = request_encoder . append_format_to location . path
location . query ? " #{ path } ? #{ location . query } " : path
end
2006-02-28 13:15:46 -05:00
end
2007-11-01 03:59:24 -04:00
module Runner
2010-03-17 20:52:16 -04:00
include ActionDispatch :: Assertions
2015-02-10 13:48:08 -05:00
APP_SESSIONS = { }
2015-03-09 17:10:24 -04:00
attr_reader :app
2015-07-28 06:22:37 -04:00
def before_setup # :nodoc:
2015-03-09 17:10:24 -04:00
@app = nil
@integration_session = nil
2015-03-09 16:43:49 -04:00
super
2015-03-09 17:10:24 -04:00
end
def integration_session
2016-03-02 14:30:52 -05:00
@integration_session || = create_session ( app )
2015-02-12 15:04:23 -05:00
end
2007-11-01 03:59:24 -04:00
# Reset the current session. This is useful for testing multiple sessions
# in a single test case.
def reset!
2016-03-02 14:30:52 -05:00
@integration_session = create_session ( app )
2015-02-10 13:48:08 -05:00
end
def create_session ( app )
klass = APP_SESSIONS [ app ] || = Class . new ( Integration :: Session ) {
# If the app is a Rails app, make url_helpers available on the session
# This makes app.url_for and app.foo_path available in the console
if app . respond_to? ( :routes )
include app . routes . url_helpers
include app . routes . mounted_helpers
end
}
klass . new ( app )
2007-11-01 03:59:24 -04:00
end
2014-11-05 10:38:02 -05:00
def remove! # :nodoc:
@integration_session = nil
end
2013-05-16 13:39:18 -04:00
%w( get post patch put head delete cookies assigns
2008-08-19 19:53:46 -04:00
xml_http_request xhr get_via_redirect post_via_redirect ) . each do | method |
2007-11-01 03:59:24 -04:00
define_method ( method ) do | * args |
2014-11-12 07:06:18 -05:00
# reset the html_document variable, except for cookies/assigns calls
2016-08-06 12:51:43 -04:00
unless method == " cookies " || method == " assigns "
2014-11-12 07:06:18 -05:00
@html_document = nil
end
2010-09-24 14:41:42 -04:00
integration_session . __send__ ( method , * args ) . tap do
2007-11-01 03:59:24 -04:00
copy_session_variables!
end
end
end
# Open a new session instance. If a block is given, the new session is
# yielded to the block before being returned.
#
# session = open_session do |sess|
# sess.extend(CustomAssertions)
# end
#
# By default, a single session is automatically created for you, but you
# can use this method to open multiple sessions that ought to be tested
# simultaneously.
2014-06-14 19:29:34 -04:00
def open_session
2010-03-22 20:04:56 -04:00
dup . tap do | session |
yield session if block_given?
2007-11-01 03:59:24 -04:00
end
end
# Copy the instance variables from the current session instance into the
# test instance.
def copy_session_variables! #:nodoc:
2015-02-12 15:11:19 -05:00
@controller = @integration_session . controller
@response = @integration_session . response
@request = @integration_session . request
2007-11-01 03:59:24 -04:00
end
2012-05-10 15:28:53 -04:00
def default_url_options
integration_session . default_url_options
end
2010-02-25 20:51:56 -05:00
2012-05-10 15:28:53 -04:00
def default_url_options = ( options )
integration_session . default_url_options = options
2010-02-25 20:51:56 -05:00
end
2010-11-21 07:46:25 -05:00
def respond_to? ( method , include_private = false )
2010-11-23 04:09:24 -05:00
integration_session . respond_to? ( method , include_private ) || super
2010-11-21 07:46:25 -05:00
end
2007-11-01 03:59:24 -04:00
# Delegate unhandled messages to the current session instance.
def method_missing ( sym , * args , & block )
2010-09-24 14:41:42 -04:00
if integration_session . respond_to? ( sym )
integration_session . __send__ ( sym , * args , & block ) . tap do
2009-08-30 23:46:48 -04:00
copy_session_variables!
end
else
super
2007-11-01 03:59:24 -04:00
end
end
end
2006-02-28 13:15:46 -05:00
end
2011-03-29 01:17:20 -04:00
# An integration test spans multiple controllers and actions,
2006-02-28 13:15:46 -05:00
# tying them all together to ensure they work together as expected. It tests
# more completely than either unit or functional tests do, exercising the
# entire stack, from the dispatcher to the database.
#
2010-08-28 18:04:14 -04:00
# At its simplest, you simply extend <tt>IntegrationTest</tt> and write your tests
2006-02-28 13:15:46 -05:00
# using the get/post methods:
#
2009-12-22 20:25:34 -05:00
# require "test_helper"
2006-02-28 13:15:46 -05:00
#
2010-09-24 20:15:52 -04:00
# class ExampleTest < ActionDispatch::IntegrationTest
2006-02-28 13:15:46 -05:00
# fixtures :people
#
# def test_login
# # get the login page
# get "/login"
# assert_equal 200, status
#
# # post the login and follow through to the home page
2015-03-07 00:28:47 -05:00
# post "/login", params: { username: people(:jamis).username,
# password: people(:jamis).password }
2006-02-28 13:15:46 -05:00
# follow_redirect!
# assert_equal 200, status
# assert_equal "/home", path
# end
# end
#
# However, you can also have multiple session instances open per test, and
# even extend those instances with assertions and methods to create a very
# powerful testing DSL that is specific for your application. You can even
2010-08-28 18:04:14 -04:00
# reference any named routes you happen to have defined.
2006-02-28 13:15:46 -05:00
#
2009-12-22 20:25:34 -05:00
# require "test_helper"
2006-02-28 13:15:46 -05:00
#
2010-09-24 20:15:52 -04:00
# class AdvancedTest < ActionDispatch::IntegrationTest
2006-02-28 13:15:46 -05:00
# fixtures :people, :rooms
#
# def test_login_and_speak
# jamis, david = login(:jamis), login(:david)
# room = rooms(:office)
#
# jamis.enter(room)
# jamis.speak(room, "anybody home?")
#
# david.enter(room)
# david.speak(room, "hello!")
# end
#
# private
#
# module CustomAssertions
# def enter(room)
# # reference a named route, for maximum internal consistency!
2012-10-31 15:19:44 -04:00
# get(room_url(id: room.id))
2006-02-28 13:15:46 -05:00
# assert(...)
# ...
# end
#
# def speak(room, message)
2015-03-07 00:28:47 -05:00
# post "/say/#{room.id}", xhr: true, params: { message: message }
2006-02-28 13:15:46 -05:00
# assert(...)
# ...
# end
# end
#
# def login(who)
# open_session do |sess|
# sess.extend(CustomAssertions)
# who = people(who)
2015-03-07 00:28:47 -05:00
# sess.post "/login", params: { username: who.username,
# password: who.password }
2006-02-28 13:15:46 -05:00
# assert(...)
# end
# end
# end
2014-12-29 20:28:15 -05:00
#
# Another longer example would be:
#
# A simple integration test that exercises multiple controllers:
#
# require 'test_helper'
#
# class UserFlowsTest < ActionDispatch::IntegrationTest
# test "login and browse site" do
# # login via https
# https!
# get "/login"
# assert_response :success
#
2015-03-07 00:28:47 -05:00
# post "/login", params: { username: users(:david).username, password: users(:david).password }
# follow_redirect!
2014-12-29 20:28:15 -05:00
# assert_equal '/welcome', path
# assert_equal 'Welcome david!', flash[:notice]
#
# https!(false)
# get "/articles/all"
# assert_response :success
2015-05-17 21:20:02 -04:00
# assert_select 'h1', 'Articles'
2014-12-29 20:28:15 -05:00
# end
# end
#
# As you can see the integration test involves multiple controllers and
# exercises the entire stack from database to dispatcher. In addition you can
# have multiple session instances open simultaneously in a test and extend
# those instances with assertion methods to create a very powerful testing
# DSL (domain-specific language) just for your application.
#
# Here's an example of multiple sessions and custom DSL in an integration test
#
# require 'test_helper'
#
# class UserFlowsTest < ActionDispatch::IntegrationTest
# test "login and browse site" do
# # User david logs in
# david = login(:david)
# # User guest logs in
# guest = login(:guest)
#
# # Both are now available in different sessions
# assert_equal 'Welcome david!', david.flash[:notice]
# assert_equal 'Welcome guest!', guest.flash[:notice]
#
# # User david can browse site
# david.browses_site
# # User guest can browse site as well
# guest.browses_site
#
# # Continue with other assertions
# end
#
# private
#
# module CustomDsl
# def browses_site
# get "/products/all"
# assert_response :success
2015-05-17 21:20:02 -04:00
# assert_select 'h1', 'Products'
2014-12-29 20:28:15 -05:00
# end
# end
#
# def login(user)
# open_session do |sess|
# sess.extend(CustomDsl)
# u = users(user)
# sess.https!
2015-03-07 00:28:47 -05:00
# sess.post "/login", params: { username: u.username, password: u.password }
2014-12-29 20:28:15 -05:00
# assert_equal '/welcome', sess.path
# sess.https!(false)
# end
# end
# end
#
2015-09-18 18:11:18 -04:00
# You can also test your JSON API easily by setting what the request should
# be encoded as:
#
# require 'test_helper'
#
# class ApiTest < ActionDispatch::IntegrationTest
2016-02-10 15:46:51 -05:00
# test 'creates articles' do
2015-09-18 18:11:18 -04:00
# assert_difference -> { Article.count } do
# post articles_path, params: { article: { title: 'Ahoy!' } }, as: :json
# end
#
# assert_response :success
2016-02-10 15:46:51 -05:00
# assert_equal({ id: Arcticle.last.id, title: 'Ahoy!' }, response.parsed_body)
2015-09-18 18:11:18 -04:00
# end
# end
#
# The `as` option sets the format to JSON, sets the content type to
# 'application/json' and encodes the parameters as JSON.
#
2016-02-10 15:46:51 -05:00
# 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`.
#
2015-09-18 18:11:18 -04:00
# For any custom MIME Types you've registered, you can even add your own encoders with:
#
2016-02-10 15:46:51 -05:00
# 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
2016-02-12 14:07:01 -05:00
# `response_parser` defines how the response body should be parsed through
# `parsed_body`.
2015-09-18 18:11:18 -04:00
#
2014-12-29 20:28:15 -05:00
# Consult the Rails Testing Guide for more.
2008-06-13 03:21:03 -04:00
class IntegrationTest < ActiveSupport :: TestCase
2016-02-25 05:42:21 -05:00
module UrlOptions
extend ActiveSupport :: Concern
def url_options
integration_session . url_options
end
end
2009-09-26 22:38:48 -04:00
2016-02-25 05:42:21 -05:00
module Behavior
extend ActiveSupport :: Concern
2009-09-26 22:38:48 -04:00
2016-02-25 05:42:21 -05:00
include Integration :: Runner
include ActionController :: TemplateAssertions
2009-09-26 22:38:48 -04:00
2016-02-25 05:42:21 -05:00
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
2009-09-26 22:38:48 -04:00
2016-02-25 05:42:21 -05:00
module ClassMethods
def app
2016-07-26 21:02:38 -04:00
if defined? ( @@app ) && @@app
@@app
else
ActionDispatch . test_app
end
2016-02-25 05:42:21 -05:00
end
2012-05-10 15:28:53 -04:00
2016-02-25 05:42:21 -05:00
def app = ( app )
@@app = app
end
2014-05-28 03:51:41 -04:00
2016-02-25 05:42:21 -05:00
def register_encoder ( * args )
2016-07-10 16:02:12 -04:00
RequestEncoder . register_encoder ( * args )
2016-02-25 05:42:21 -05:00
end
end
def app
super || self . class . app
end
2015-09-18 18:11:18 -04:00
2016-02-25 05:42:21 -05:00
def document_root_element
html_document . root
end
2015-09-18 18:11:18 -04:00
end
2016-03-06 21:52:51 -05:00
2016-02-25 05:42:21 -05:00
include Behavior
2006-02-28 13:15:46 -05:00
end
2007-10-02 01:32:14 -04:00
end