diff options
author | Gonçalo Silva <goncalossilva@gmail.com> | 2011-04-17 17:08:49 +0100 |
---|---|---|
committer | Gonçalo Silva <goncalossilva@gmail.com> | 2011-04-17 17:08:49 +0100 |
commit | 1c2b2233c3a7ec76c0a0eddf5b8be45c489be133 (patch) | |
tree | 56f2b767c3a4f1f14c51606bf2cbb714a98c5f89 /actionpack/lib/action_dispatch/testing | |
parent | 8d558cb1b069410c8f693295c9c4e2ffc9661e06 (diff) | |
parent | b6843f22ac42b503f6b8ac00105ca0679049be7d (diff) | |
download | rails-1c2b2233c3a7ec76c0a0eddf5b8be45c489be133.tar.gz rails-1c2b2233c3a7ec76c0a0eddf5b8be45c489be133.tar.bz2 rails-1c2b2233c3a7ec76c0a0eddf5b8be45c489be133.zip |
Merge branch 'master' of https://github.com/rails/rails into performance_test
Diffstat (limited to 'actionpack/lib/action_dispatch/testing')
3 files changed, 24 insertions, 212 deletions
diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 77a15f3e97..8a04cfa886 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/object/inclusion' + module ActionDispatch module Assertions # A small suite of assertions that test responses from \Rails applications. @@ -33,7 +35,7 @@ module ActionDispatch def assert_response(type, message = nil) validate_request! - if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?") + if type.in?([:success, :missing, :redirect, :error]) && @response.send("#{type}?") assert_block("") { true } # to count the assertion elsif type.is_a?(Fixnum) && @response.response_code == type assert_block("") { true } # to count the assertion diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 2b862fb7d6..c67a0664dc 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -1,4 +1,5 @@ require 'action_controller/vendor/html-scanner' +require 'active_support/core_ext/object/inclusion' #-- # Copyright (c) 2006 Assaf Arkin (http://labnotes.org) @@ -18,7 +19,7 @@ module ActionDispatch # from the response HTML or elements selected by the enclosing assertion. # # In addition to HTML responses, you can make the following assertions: - # * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations. + # # * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions. # * +assert_select_email+ - Assertions on the HTML body of an e-mail. # @@ -79,7 +80,7 @@ module ActionDispatch return matches else - root = response_from_page_or_rjs + root = response_from_page end case arg @@ -203,7 +204,7 @@ module ActionDispatch root.children.concat @selected else # Otherwise just operate on the response document. - root = response_from_page_or_rjs + root = response_from_page end # First or second argument is the selector: string and we pass @@ -325,144 +326,6 @@ module ActionDispatch end end - # Selects content from the RJS response. - # - # === Narrowing down - # - # With no arguments, asserts that one or more elements are updated or - # inserted by RJS statements. - # - # Use the +id+ argument to narrow down the assertion to only statements - # that update or insert an element with that identifier. - # - # Use the first argument to narrow down assertions to only statements - # of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>, - # <tt>:show</tt>, <tt>:hide</tt>, <tt>:toggle</tt>, <tt>:remove</tta>, - # <tt>:insert_html</tt> and <tt>:redirect</tt>. - # - # Use the argument <tt>:insert</tt> followed by an insertion position to narrow - # down the assertion to only statements that insert elements in that - # position. Possible values are <tt>:top</tt>, <tt>:bottom</tt>, <tt>:before</tt> - # and <tt>:after</tt>. - # - # Use the argument <tt>:redirect</tt> followed by a path to check that an statement - # which redirects to the specified path is generated. - # - # Using the <tt>:remove</tt> statement, you will be able to pass a block, but it will - # be ignored as there is no HTML passed for this statement. - # - # === Using blocks - # - # Without a block, +assert_select_rjs+ merely asserts that the response - # contains one or more RJS statements that replace or update content. - # - # With a block, +assert_select_rjs+ also selects all elements used in - # these statements and passes them to the block. Nested assertions are - # supported. - # - # Calling +assert_select_rjs+ with no arguments and using nested asserts - # asserts that the HTML content is returned by one or more RJS statements. - # Using +assert_select+ directly makes the same assertion on the content, - # but without distinguishing whether the content is returned in an HTML - # or JavaScript. - # - # ==== Examples - # - # # Replacing the element foo. - # # page.replace 'foo', ... - # assert_select_rjs :replace, "foo" - # - # # Replacing with the chained RJS proxy. - # # page[:foo].replace ... - # assert_select_rjs :chained_replace, 'foo' - # - # # Inserting into the element bar, top position. - # assert_select_rjs :insert, :top, "bar" - # - # # Remove the element bar - # assert_select_rjs :remove, "bar" - # - # # Changing the element foo, with an image. - # assert_select_rjs "foo" do - # assert_select "img[src=/images/logo.gif"" - # end - # - # # RJS inserts or updates a list with four items. - # assert_select_rjs do - # assert_select "ol>li", 4 - # end - # - # # The same, but shorter. - # assert_select "ol>li", 4 - # - # # Checking for a redirect. - # assert_select_rjs :redirect, root_path - def assert_select_rjs(*args, &block) - rjs_type = args.first.is_a?(Symbol) ? args.shift : nil - id = args.first.is_a?(String) ? args.shift : nil - - # If the first argument is a symbol, it's the type of RJS statement we're looking - # for (update, replace, insertion, etc). Otherwise, we're looking for just about - # any RJS statement. - if rjs_type - if rjs_type == :insert - position = args.shift - id = args.shift - insertion = "insert_#{position}".to_sym - raise ArgumentError, "Unknown RJS insertion type #{position}" unless RJS_STATEMENTS[insertion] - statement = "(#{RJS_STATEMENTS[insertion]})" - else - raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type] - statement = "(#{RJS_STATEMENTS[rjs_type]})" - end - else - statement = "#{RJS_STATEMENTS[:any]}" - end - - # Next argument we're looking for is the element identifier. If missing, we pick - # any element, otherwise we replace it in the statement. - pattern = Regexp.new( - id ? statement.gsub(RJS_ANY_ID, "\"#{id}\"") : statement - ) - - # Duplicate the body since the next step involves destroying it. - matches = nil - case rjs_type - when :remove, :show, :hide, :toggle - matches = @response.body.match(pattern) - else - @response.body.gsub(pattern) do |match| - html = unescape_rjs(match) - matches ||= [] - matches.concat HTML::Document.new(html).root.children.select { |n| n.tag? } - "" - end - end - - if matches - 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 - @selected = in_scope - end - end - matches - else - # RJS statement not found. - case rjs_type - when :remove, :show, :hide, :toggle - flunk_message = "No RJS statement that #{rjs_type.to_s}s '#{id}' was rendered." - else - flunk_message = "No RJS statement that replaces or inserts HTML content." - end - flunk args.shift || flunk_message - end - end - # Extracts the content of an element, treats it as encoded HTML and runs # nested assertion on it. # @@ -562,62 +425,9 @@ module ActionDispatch end protected - RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\"" - RJS_ANY_ID = "\"([^\"])*\"" - RJS_STATEMENTS = { - :chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)", - :chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)", - :replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)", - :replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)", - :redirect => "window.location.href = #{RJS_ANY_ID}" - } - [:remove, :show, :hide, :toggle].each do |action| - RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)" - end - RJS_INSERTIONS = ["top", "bottom", "before", "after"] - RJS_INSERTIONS.each do |insertion| - RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)" - end - RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)" - RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})") - RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/ - - # +assert_select+ and +css_select+ call this to obtain the content in the HTML - # page, or from all the RJS statements, depending on the type of response. - def response_from_page_or_rjs() - content_type = @response.content_type - - if content_type && Mime::JS =~ content_type - body = @response.body.dup - root = HTML::Node.new(nil) - - while true - next if body.sub!(RJS_STATEMENTS[:any]) do |match| - html = unescape_rjs(match) - matches = HTML::Document.new(html).root.children.select { |n| n.tag? } - root.children.concat matches - "" - end - break - end - - root - else - html_document.root - end - end - - # Unescapes a RJS string. - def unescape_rjs(rjs_string) - # RJS encodes double quotes and line breaks. - unescaped= rjs_string.gsub('\"', '"') - unescaped.gsub!(/\\\//, '/') - unescaped.gsub!('\n', "\n") - unescaped.gsub!('\076', '>') - unescaped.gsub!('\074', '<') - # RJS encodes non-ascii characters. - unescaped.gsub!(RJS_PATTERN_UNICODE_ESCAPED_CHAR) {|u| [$1.hex].pack('U*')} - unescaped + # +assert_select+ and +css_select+ call this to obtain the content in the HTML page. + def response_from_page + html_document.root end end end diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 5c6416a19e..7d707d03a9 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -1,6 +1,7 @@ require 'stringio' require 'uri' require 'active_support/core_ext/kernel/singleton_class' +require 'active_support/core_ext/object/inclusion' require 'active_support/core_ext/object/try' require 'rack/test' require 'test/unit/assertions' @@ -26,31 +27,31 @@ module ActionDispatch # object's <tt>@response</tt> instance variable will point to the same # response object. # - # You can also perform POST, PUT, DELETE, and HEAD requests with +post+, - # +put+, +delete+, and +head+. + # You can also perform POST, PUT, DELETE, and HEAD requests with +#post+, + # +#put+, +#delete+, and +#head+. def get(path, parameters = nil, headers = nil) process :get, path, parameters, headers end - # Performs a POST request with the given parameters. See get() for more + # Performs a POST request with the given parameters. See +#get+ for more # details. def post(path, parameters = nil, headers = nil) process :post, path, parameters, headers end - # Performs a PUT request with the given parameters. See get() for more + # Performs a PUT request with the given parameters. See +#get+ for more # details. def put(path, parameters = nil, headers = nil) process :put, path, parameters, headers end - # Performs a DELETE request with the given parameters. See get() for + # Performs a DELETE request with the given parameters. See +#get+ for # more details. def delete(path, parameters = nil, headers = nil) process :delete, path, parameters, headers end - # Performs a HEAD request with the given parameters. See get() for more + # Performs a HEAD request with the given parameters. See +#get+ for more # details. def head(path, parameters = nil, headers = nil) process :head, path, parameters, headers @@ -59,7 +60,7 @@ module ActionDispatch # Performs an XMLHttpRequest request with the given parameters, mirroring # a request from the Prototype library. # - # The request_method is :get, :post, :put, :delete or :head; the + # The request_method is +:get+, +:post+, +:put+, +:delete+ or +:head+; the # parameters are +nil+, a hash, or a url-encoded or multipart string; # the headers are a hash. Keys are automatically upcased and prefixed # with 'HTTP_' if not already. @@ -243,7 +244,8 @@ module ActionDispatch end # Performs the actual request. - def process(method, path, parameters = nil, rack_environment = nil) + def process(method, path, parameters = nil, env = nil) + env ||= {} if path =~ %r{://} location = URI.parse(path) https! URI::HTTPS === location if location.scheme @@ -259,7 +261,7 @@ module ActionDispatch hostname, port = host.split(':') - env = { + default_env = { :method => method, :params => parameters, @@ -277,9 +279,7 @@ module ActionDispatch session = Rack::Test::Session.new(_mock_session) - (rack_environment || {}).each do |key, value| - env[key] = value - end + env.reverse_merge!(default_env) # NOTE: rack-test v0.5 doesn't build a default uri correctly # Make sure requested path is always a full uri @@ -321,7 +321,7 @@ module ActionDispatch define_method(method) do |*args| 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) + @html_document = nil unless method.in?(["cookies", "assigns"]) integration_session.__send__(method, *args).tap do copy_session_variables! end @@ -384,7 +384,7 @@ module ActionDispatch end end - # An test that spans multiple controllers and actions, + # An integration test 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. |