diff options
author | Gonçalo Silva <goncalossilva@gmail.com> | 2011-03-24 17:21:17 +0000 |
---|---|---|
committer | Gonçalo Silva <goncalossilva@gmail.com> | 2011-03-24 17:21:17 +0000 |
commit | 9887f238871bb2dd73de6ce8855615bcc5d8d079 (patch) | |
tree | 74fa9ff9524a51701cfa23f708b3f777c65b7fe5 /actionpack/lib/action_dispatch/testing | |
parent | aff821508a16245ebc03510ba29c70379718dfb7 (diff) | |
parent | 5214e73850916de3c9127d35a4ecee0424d364a3 (diff) | |
download | rails-9887f238871bb2dd73de6ce8855615bcc5d8d079.tar.gz rails-9887f238871bb2dd73de6ce8855615bcc5d8d079.tar.bz2 rails-9887f238871bb2dd73de6ce8855615bcc5d8d079.zip |
Merge branch 'master' of https://github.com/rails/rails
Diffstat (limited to 'actionpack/lib/action_dispatch/testing')
9 files changed, 114 insertions, 206 deletions
diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb index 9c215de743..47c84742aa 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb @@ -3,7 +3,7 @@ require 'action_controller/vendor/html-scanner' module ActionDispatch module Assertions module DomAssertions - # Test two HTML strings for equivalency (e.g., identical up to reordering of attributes) + # \Test two HTML strings for equivalency (e.g., identical up to reordering of attributes) # # ==== Examples # diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index ec5e9efe44..77a15f3e97 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -1,6 +1,6 @@ module ActionDispatch module Assertions - # A small suite of assertions that test responses from Rails applications. + # A small suite of assertions that test responses from \Rails applications. module ResponseAssertions extend ActiveSupport::Concern @@ -18,9 +18,9 @@ module ActionDispatch # * <tt>:missing</tt> - Status code was 404 # * <tt>:error</tt> - Status code was in the 500-599 range # - # You can also pass an explicit status number like assert_response(501) - # or its symbolic equivalent assert_response(:not_implemented). - # See ActionDispatch::StatusCodes for a full list. + # You can also pass an explicit status number like <tt>assert_response(501)</tt> + # or its symbolic equivalent <tt>assert_response(:not_implemented)</tt>. + # See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list. # # ==== Examples # @@ -45,8 +45,8 @@ module ActionDispatch end # Assert that the redirection options passed in match those of the redirect called in the latest action. - # This match can be partial, such that assert_redirected_to(:controller => "weblog") will also - # match the redirection of redirect_to(:controller => "weblog", :action => "show") and so on. + # This match can be partial, such that <tt>assert_redirected_to(:controller => "weblog")</tt> will also + # match the redirection of <tt>redirect_to(:controller => "weblog", :action => "show")</tt> and so on. # # ==== Examples # @@ -81,14 +81,10 @@ module ActionDispatch def normalize_argument_to_redirection(fragment) case fragment - when %r{^\w[\w\d+.-]*:.*} + when %r{^\w[A-Za-z\d+.-]*:.*} fragment when String - if fragment =~ %r{^\w[\w\d+.-]*:.*} - fragment - else - @request.protocol + @request.host_with_port + fragment - end + @request.protocol + @request.host_with_port + fragment when :back raise RedirectBackError unless refer = @request.headers["Referer"] refer diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 9338fa9e70..11e8c63fa0 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -1,12 +1,13 @@ +require 'uri' require 'active_support/core_ext/hash/diff' require 'active_support/core_ext/hash/indifferent_access' module ActionDispatch module Assertions - # Suite of assertions to test routes generated by Rails and the handling of requests made to them. + # Suite of assertions to test routes generated by \Rails and the handling of requests made to them. module RoutingAssertions # Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash) - # match +path+. Basically, it asserts that Rails recognizes the route given by +expected_options+. + # match +path+. Basically, it asserts that \Rails recognizes the route given by +expected_options+. # # Pass a hash in the second argument (+path+) to specify the request method. This is useful for routes # requiring a specific HTTP method. The hash should contain a :path with the incoming request path @@ -36,18 +37,8 @@ module ActionDispatch # # # Test a custom route # assert_recognizes({:controller => 'items', :action => 'show', :id => '1'}, 'view/item1') - # - # # Check a Simply RESTful generated route - # assert_recognizes list_items_url, 'items/list' def assert_recognizes(expected_options, path, extras={}, message=nil) - if path.is_a? Hash - request_method = path[:method] - path = path[:path] - else - request_method = nil - end - - request = recognized_request_for(path, request_method) + request = recognized_request_for(path) expected_options = expected_options.clone extras.each_key { |key| expected_options.delete key } unless extras.nil? @@ -77,7 +68,16 @@ module ActionDispatch # # Asserts that the generated route gives us our custom route # assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" } def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil) - expected_path = "/#{expected_path}" unless expected_path[0] == ?/ + if expected_path =~ %r{://} + begin + uri = URI.parse(expected_path) + expected_path = uri.path.to_s.empty? ? "/" : uri.path + rescue URI::InvalidURIError => e + raise ActionController::RoutingError, e.message + end + else + expected_path = "/#{expected_path}" unless expected_path.first == '/' + end # Load routes.rb if it hasn't been loaded. generated_path, extra_keys = @routes.generate_extras(options, defaults) @@ -121,7 +121,8 @@ module ActionDispatch options[:controller] = "/#{controller}" end - assert_generates(path.is_a?(Hash) ? path[:path] : path, options, defaults, extras, message) + generate_options = options.dup.delete_if{ |k,v| defaults.key?(k) } + assert_generates(path.is_a?(Hash) ? path[:path] : path, generate_options, defaults, extras, message) end # A helper to make it easier to test different route configurations. @@ -143,16 +144,16 @@ module ActionDispatch # def with_routing old_routes, @routes = @routes, ActionDispatch::Routing::RouteSet.new - old_controller, @controller = @controller, @controller.clone if @controller - _routes = @routes - - # Unfortunately, there is currently an abstraction leak between AC::Base - # and AV::Base which requires having the URL helpers in both AC and AV. - # To do this safely at runtime for tests, we need to bump up the helper serial - # to that the old AV subclass isn't cached. - # - # TODO: Make this unnecessary - if @controller + if defined?(@controller) && @controller + old_controller, @controller = @controller, @controller.clone + _routes = @routes + + # Unfortunately, there is currently an abstraction leak between AC::Base + # and AV::Base which requires having the URL helpers in both AC and AV. + # To do this safely at runtime for tests, we need to bump up the helper serial + # to that the old AV subclass isn't cached. + # + # TODO: Make this unnecessary @controller.singleton_class.send(:include, _routes.url_helpers) @controller.view_context_class = Class.new(@controller.view_context_class) do include _routes.url_helpers @@ -161,14 +162,14 @@ module ActionDispatch yield @routes ensure @routes = old_routes - if @controller + if defined?(@controller) && @controller @controller = old_controller end end # ROUTES TODO: These assertions should really work in an integration context def method_missing(selector, *args, &block) - if @controller && @routes && @routes.named_routes.helpers.include?(selector) + if defined?(@controller) && @controller && @routes && @routes.named_routes.helpers.include?(selector) @controller.send(selector, *args, &block) else super @@ -177,15 +178,35 @@ module ActionDispatch private # Recognizes the route for a given path. - def recognized_request_for(path, request_method = nil) - path = "/#{path}" unless path.first == '/' + def recognized_request_for(path) + if path.is_a?(Hash) + method = path[:method] + path = path[:path] + else + method = :get + end # Assume given controller request = ActionController::TestRequest.new - request.env["REQUEST_METHOD"] = request_method.to_s.upcase if request_method - request.path = path - params = @routes.recognize_path(path, { :method => request.method }) + if path =~ %r{://} + begin + uri = URI.parse(path) + request.env["rack.url_scheme"] = uri.scheme || "http" + request.host = uri.host if uri.host + request.port = uri.port if uri.port + request.path = uri.path.to_s.empty? ? "/" : uri.path + rescue URI::InvalidURIError => e + raise ActionController::RoutingError, e.message + end + else + path = "/#{path}" unless path.first == "/" + request.path = path + end + + request.request_method = method if method + + params = @routes.recognize_path(path, { :method => method }) request.path_parameters = params.with_indifferent_access request diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 2fc9e2b7d6..2b862fb7d6 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -24,10 +24,6 @@ module ActionDispatch # # Also see HTML::Selector to learn how to use selectors. module SelectorAssertions - # :call-seq: - # css_select(selector) => array - # css_select(element, selector) => array - # # Select and return all matching elements. # # If called with a single argument, uses that argument as a selector @@ -71,7 +67,7 @@ module ActionDispatch arg = args.shift elsif arg == nil raise ArgumentError, "First argument is either selector or element to select, but nil found. Perhaps you called assert_select with an element that does not exist?" - elsif @selected + elsif defined?(@selected) && @selected matches = [] @selected.each do |selected| @@ -99,10 +95,6 @@ module ActionDispatch selector.select(root) end - # :call-seq: - # assert_select(selector, equality?, message?) - # assert_select(element, selector, equality?, message?) - # # An assertion that selects elements and makes one or more equality tests. # # If the first argument is an element, selects all matching elements @@ -195,6 +187,7 @@ module ActionDispatch def assert_select(*args, &block) # Start with optional element followed by mandatory selector. arg = args.shift + @selected ||= nil if arg.is_a?(HTML::Node) # First argument is a node (tag or text, but also HTML root), @@ -332,11 +325,6 @@ module ActionDispatch end end - # :call-seq: - # assert_select_rjs(id?) { |elements| ... } - # assert_select_rjs(statement, id?) { |elements| ... } - # assert_select_rjs(:insert, position, id?) { |elements| ... } - # # Selects content from the RJS response. # # === Narrowing down @@ -455,6 +443,7 @@ module ActionDispatch assert_block("") { true } # to count the assertion if block_given? && !([:remove, :show, :hide, :toggle].include? rjs_type) begin + @selected ||= nil in_scope, @selected = @selected, matches yield matches ensure @@ -474,9 +463,6 @@ module ActionDispatch end end - # :call-seq: - # assert_select_encoded(element?) { |elements| ... } - # # Extracts the content of an element, treats it as encoded HTML and runs # nested assertion on it. # @@ -529,8 +515,8 @@ module ActionDispatch node.content.gsub(/<!\[CDATA\[(.*)(\]\]>)?/m) { Rack::Utils.escapeHTML($1) } end - selected = elements.map do |element| - text = element.children.select{ |c| not c.tag? }.map{ |c| fix_content[c] }.join + selected = elements.map do |_element| + text = _element.children.select{ |c| not c.tag? }.map{ |c| fix_content[c] }.join root = HTML::Document.new(CGI.unescapeHTML("<encoded>#{text}</encoded>")).root css_select(root, "encoded:root", &block)[0] end @@ -543,9 +529,6 @@ module ActionDispatch end end - # :call-seq: - # assert_select_email { } - # # Extracts the body of an email and runs nested assertions on it. # # You must enable deliveries for this assertion to work, use: diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index b52795c575..5c6416a19e 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -115,8 +115,8 @@ module ActionDispatch end end - # An integration Session instance represents a set of requests and responses - # performed sequentially by some virtual user. Because you can instantiate + # An instance of this class represents a set of requests and responses + # performed sequentially by a test process. Because you can instantiate # multiple sessions and run them side-by-side, you can also mimic (to some # limited extent) multiple simultaneous users interacting with your system. # @@ -171,6 +171,7 @@ module ActionDispatch # Create and initialize a new Session instance. def initialize(app) + super() @app = app # If the app is a Rails app, make url_helpers available on the session @@ -182,6 +183,7 @@ module ActionDispatch reset! end + remove_method :default_url_options def default_url_options { :host => host, :protocol => https? ? "https" : "http" } end @@ -233,9 +235,7 @@ module ActionDispatch # Set the host name to use in the next request. # # session.host! "www.example.com" - def host!(name) - @host = name - end + alias :host! :host= private def _mock_session @@ -257,12 +257,14 @@ module ActionDispatch end end + hostname, port = host.split(':') + env = { :method => method, :params => parameters, - "SERVER_NAME" => host.split(':')[0], - "SERVER_PORT" => (https? ? "443" : "80"), + "SERVER_NAME" => hostname, + "SERVER_PORT" => port || (https? ? "443" : "80"), "HTTPS" => https? ? "on" : "off", "rack.url_scheme" => https? ? "https" : "http", @@ -305,7 +307,7 @@ module ActionDispatch include ActionDispatch::Assertions def app - @app + @app ||= nil end # Reset the current session. This is useful for testing multiple sessions @@ -317,10 +319,10 @@ module ActionDispatch %w(get post put head delete cookies assigns xml_http_request xhr get_via_redirect post_via_redirect).each do |method| define_method(method) do |*args| - reset! unless @integration_session + reset! unless integration_session # reset the html_document variable, but only for new get/post calls @html_document = nil unless %w(cookies assigns).include?(method) - @integration_session.__send__(method, *args).tap do + integration_session.__send__(method, *args).tap do copy_session_variables! end end @@ -345,7 +347,7 @@ module ActionDispatch # Copy the instance variables from the current session instance into the # test instance. def copy_session_variables! #:nodoc: - return unless @integration_session + return unless integration_session %w(controller response request).each do |var| instance_variable_set("@#{var}", @integration_session.__send__(var)) end @@ -355,35 +357,44 @@ module ActionDispatch include ActionDispatch::Routing::UrlFor def url_options - reset! unless @integration_session - @integration_session.url_options + reset! unless integration_session + integration_session.url_options + end + + def respond_to?(method, include_private = false) + integration_session.respond_to?(method, include_private) || super end # Delegate unhandled messages to the current session instance. def method_missing(sym, *args, &block) - reset! unless @integration_session - if @integration_session.respond_to?(sym) - @integration_session.__send__(sym, *args, &block).tap do + reset! unless integration_session + if integration_session.respond_to?(sym) + integration_session.__send__(sym, *args, &block).tap do copy_session_variables! end else super end end + + private + def integration_session + @integration_session ||= nil + end end end - # An IntegrationTest is one that spans multiple controllers and actions, + # An test that spans multiple controllers and actions, # 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. # - # At its simplest, you simply extend IntegrationTest and write your tests + # At its simplest, you simply extend <tt>IntegrationTest</tt> and write your tests # using the get/post methods: # # require "test_helper" # - # class ExampleTest < ActionController::IntegrationTest + # class ExampleTest < ActionDispatch::IntegrationTest # fixtures :people # # def test_login @@ -403,11 +414,11 @@ module ActionDispatch # 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 - # reference any named routes you happen to have defined! + # reference any named routes you happen to have defined. # # require "test_helper" # - # class AdvancedTest < ActionController::IntegrationTest + # class AdvancedTest < ActionDispatch::IntegrationTest # fixtures :people, :rooms # # def test_login_and_speak diff --git a/actionpack/lib/action_dispatch/testing/performance_test.rb b/actionpack/lib/action_dispatch/testing/performance_test.rb index 33a5c68b9d..e7aeb45fb3 100644 --- a/actionpack/lib/action_dispatch/testing/performance_test.rb +++ b/actionpack/lib/action_dispatch/testing/performance_test.rb @@ -1,5 +1,4 @@ require 'active_support/testing/performance' -require 'active_support/testing/default' begin module ActionDispatch @@ -11,9 +10,8 @@ begin # formats are written, so you'll have two output files per test method. class PerformanceTest < ActionDispatch::IntegrationTest include ActiveSupport::Testing::Performance - include ActiveSupport::Testing::Default end end rescue NameError $stderr.puts "Specify ruby-prof as application's dependency in Gemfile to run benchmarks." -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb index c56ebc6438..d430691429 100644 --- a/actionpack/lib/action_dispatch/testing/test_process.rb +++ b/actionpack/lib/action_dispatch/testing/test_process.rb @@ -22,7 +22,7 @@ module ActionDispatch end def cookies - @request.cookies.merge(@response.cookies) + @request.cookies.merge(@response.cookies).with_indifferent_access end def redirect_to_url diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index b3e67f6e36..822adb6a47 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/object/blank' require 'active_support/core_ext/hash/reverse_merge' +require 'rack/utils' module ActionDispatch class TestRequest < Request @@ -10,9 +11,10 @@ module ActionDispatch end def initialize(env = {}) - env = Rails.application.env_defaults.merge(env) if defined?(Rails.application) + env = Rails.application.env_config.merge(env) if defined?(Rails.application) super(DEFAULT_ENV.merge(env)) + @cookies = nil self.host = 'test.host' self.remote_addr = '0.0.0.0' self.user_agent = 'Rails Testing' @@ -66,7 +68,7 @@ module ActionDispatch def accept=(mime_types) @env.delete('action_dispatch.request.accepts') - @env['HTTP_ACCEPT'] = Array(mime_types).collect { |mime_types| mime_types.to_s }.join(",") + @env['HTTP_ACCEPT'] = Array(mime_types).collect { |mime_type| mime_type.to_s }.join(",") end def cookies @@ -76,10 +78,14 @@ module ActionDispatch private def write_cookies! unless @cookies.blank? - @env['HTTP_COOKIE'] = @cookies.map { |name, value| "#{name}=#{value};" }.join(' ') + @env['HTTP_COOKIE'] = @cookies.map { |name, value| escape_cookie(name, value) }.join('; ') end end + def escape_cookie(name, value) + "#{Rack::Utils.escape(name)}=#{Rack::Utils.escape(value)}" + end + def delete_nil_values! @env.delete_if { |k, v| v.nil? } end diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb index 44fb1bde99..82039e72e7 100644 --- a/actionpack/lib/action_dispatch/testing/test_response.rb +++ b/actionpack/lib/action_dispatch/testing/test_response.rb @@ -14,123 +14,16 @@ module ActionDispatch end end - module DeprecatedHelpers - def template - ActiveSupport::Deprecation.warn("response.template has been deprecated. Use controller.template instead", caller) - @template - end - attr_writer :template - - def session - ActiveSupport::Deprecation.warn("response.session has been deprecated. Use request.session instead", caller) - @request.session - end - - def assigns - ActiveSupport::Deprecation.warn("response.assigns has been deprecated. Use controller.assigns instead", caller) - @template.controller.assigns - end - - def layout - ActiveSupport::Deprecation.warn("response.layout has been deprecated. Use template.layout instead", caller) - @template.layout - end - - def redirected_to - ::ActiveSupport::Deprecation.warn("response.redirected_to is deprecated. Use response.redirect_url instead", caller) - redirect_url - end - - def redirect_url_match?(pattern) - ::ActiveSupport::Deprecation.warn("response.redirect_url_match? is deprecated. Use assert_match(/foo/, response.redirect_url) instead", caller) - return false if redirect_url.nil? - p = Regexp.new(pattern) if pattern.class == String - p = pattern if pattern.class == Regexp - return false if p.nil? - p.match(redirect_url) != nil - end - - # Returns the template of the file which was used to - # render this response (or nil) - def rendered - ActiveSupport::Deprecation.warn("response.rendered has been deprecated. Use template.rendered instead", caller) - @template.instance_variable_get(:@_rendered) - end - - # A shortcut to the flash. Returns an empty hash if no session flash exists. - def flash - ActiveSupport::Deprecation.warn("response.flash has been deprecated. Use request.flash instead", caller) - request.session['flash'] || {} - end - - # Do we have a flash? - def has_flash? - ActiveSupport::Deprecation.warn("response.has_flash? has been deprecated. Use flash.any? instead", caller) - !flash.empty? - end - - # Do we have a flash that has contents? - def has_flash_with_contents? - ActiveSupport::Deprecation.warn("response.has_flash_with_contents? has been deprecated. Use flash.any? instead", caller) - !flash.empty? - end - - # Does the specified flash object exist? - def has_flash_object?(name=nil) - ActiveSupport::Deprecation.warn("response.has_flash_object? has been deprecated. Use flash[name] instead", caller) - !flash[name].nil? - end - - # Does the specified object exist in the session? - def has_session_object?(name=nil) - ActiveSupport::Deprecation.warn("response.has_session_object? has been deprecated. Use session[name] instead", caller) - !session[name].nil? - end - - # A shortcut to the template.assigns - def template_objects - ActiveSupport::Deprecation.warn("response.template_objects has been deprecated. Use template.assigns instead", caller) - @template.assigns || {} - end - - # Does the specified template object exist? - def has_template_object?(name=nil) - ActiveSupport::Deprecation.warn("response.has_template_object? has been deprecated. Use tempate.assigns[name].nil? instead", caller) - !template_objects[name].nil? - end - - # Returns binary content (downloadable file), converted to a String - def binary_content - ActiveSupport::Deprecation.warn("response.binary_content has been deprecated. Use response.body instead", caller) - body - end - end - include DeprecatedHelpers - # Was the response successful? - def success? - (200..299).include?(response_code) - end + alias_method :success?, :successful? # Was the URL not found? - def missing? - response_code == 404 - end + alias_method :missing?, :not_found? # Were we redirected? - def redirect? - (300..399).include?(response_code) - end + alias_method :redirect?, :redirection? # Was there a server-side error? - def error? - (500..599).include?(response_code) - end - alias_method :server_error?, :error? - - # Was there a client client? - def client_error? - (400..499).include?(response_code) - end + alias_method :error?, :server_error? end end |