diff options
Diffstat (limited to 'actionpack/lib/action_dispatch')
10 files changed, 103 insertions, 87 deletions
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 6e06c70dc2..dea6c4482e 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -2054,7 +2054,7 @@ module ActionDispatch # your url helper definition, e.g: # # direct :browse, page: 1, size: 10 do |options| - # [ :products, options.merge(params.permit(:page, :size)) ] + # [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ] # end # # In this instance the `params` object comes from the context in which the the diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb index 984ded1ff5..e89ea8b21d 100644 --- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb +++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb @@ -40,7 +40,7 @@ module ActionDispatch # # Example usage: # - # edit_polymorphic_path(@post) # => "/posts/1/edit" + # edit_polymorphic_path(@post) # => "/posts/1/edit" # polymorphic_path(@post, format: :pdf) # => "/posts/1.pdf" # # == Usage with mounted engines @@ -104,7 +104,7 @@ module ActionDispatch end if mapping = polymorphic_mapping(record_or_hash_or_array) - return mapping.call(self, [record_or_hash_or_array, options]) + return mapping.call(self, [record_or_hash_or_array, options], false) end opts = options.dup @@ -128,7 +128,7 @@ module ActionDispatch end if mapping = polymorphic_mapping(record_or_hash_or_array) - return mapping.call(self, [record_or_hash_or_array, options], only_path: true) + return mapping.call(self, [record_or_hash_or_array, options], true) end opts = options.dup @@ -273,7 +273,7 @@ module ActionDispatch def handle_model_call(target, record) if mapping = polymorphic_mapping(target, record) - mapping.call(target, [record], only_path: suffix == "path") + mapping.call(target, [record], suffix == "path") else method, args = handle_model(record) target.send(method, *args) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index c4719f8a71..8a9a48938b 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -164,13 +164,13 @@ module ActionDispatch @path_helpers_module.module_eval do define_method(:"#{name}_path") do |*args| - helper.call(self, args, only_path: true) + helper.call(self, args, true) end end @url_helpers_module.module_eval do define_method(:"#{name}_url") do |*args| - helper.call(self, args) + helper.call(self, args, false) end end end @@ -509,6 +509,10 @@ module ActionDispatch @_proxy.url_for(options) end + def route_for(name, *args) + @_proxy.route_for(name, *args) + end + def optimize_routes_generation? @_proxy.optimize_routes_generation? end @@ -613,26 +617,14 @@ module ActionDispatch @block = block end - def call(t, args, outer_options = {}) + def call(t, args, only_path = false) options = args.extract_options! - url_options = eval_block(t, args, options) - - case url_options - when String - t.url_for(url_options) - when Hash - t.url_for(url_options.merge(outer_options)) - when ActionController::Parameters - if url_options.permitted? - t.url_for(url_options.to_h.merge(outer_options)) - else - raise ArgumentError, "Generating a URL from non sanitized request parameters is insecure!" - end - when Array - opts = url_options.extract_options! - t.url_for(url_options.push(opts.merge(outer_options))) + url = t.url_for(eval_block(t, args, options)) + + if only_path + "/" + url.partition(%r{(?<!/)/(?!/)}).last else - t.url_for([url_options, outer_options]) + url end end @@ -860,8 +852,7 @@ module ActionDispatch params[key] = URI.parser.unescape(value) end end - old_params = req.path_parameters - req.path_parameters = old_params.merge params + req.path_parameters = params app = route.app if app.matches?(req) && app.dispatcher? begin diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 3e564f13d8..d199bece96 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -192,6 +192,10 @@ module ActionDispatch end end + def route_for(name, *args) # :nodoc: + public_send(:"#{name}_url", *args) + end + protected def optimize_routes_generation? diff --git a/actionpack/lib/action_dispatch/system_test_case.rb b/actionpack/lib/action_dispatch/system_test_case.rb index d6388d8fb7..f908607e50 100644 --- a/actionpack/lib/action_dispatch/system_test_case.rb +++ b/actionpack/lib/action_dispatch/system_test_case.rb @@ -1,8 +1,8 @@ require "capybara/dsl" +require "capybara/minitest" require "action_controller" require "action_dispatch/system_testing/driver" require "action_dispatch/system_testing/server" -require "action_dispatch/system_testing/browser" require "action_dispatch/system_testing/test_helpers/screenshot_helper" require "action_dispatch/system_testing/test_helpers/setup_and_teardown" @@ -81,15 +81,23 @@ module ActionDispatch # tests as long as you include the required gems and files. class SystemTestCase < IntegrationTest include Capybara::DSL + include Capybara::Minitest::Assertions include SystemTesting::TestHelpers::SetupAndTeardown include SystemTesting::TestHelpers::ScreenshotHelper + def initialize(*) # :nodoc: + super + self.class.superclass.driver.use + end + def self.start_application # :nodoc: Capybara.app = Rack::Builder.new do map "/" do run Rails.application end end + + SystemTesting::Server.new.run end # System Test configuration options @@ -104,21 +112,13 @@ module ActionDispatch # driven_by :selenium, using: :firefox # # driven_by :selenium, screen_size: [800, 800] - def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400]) - driver = if selenium?(driver) - SystemTesting::Browser.new(using, screen_size) - else - SystemTesting::Driver.new(driver) - end - - setup { driver.use } - teardown { driver.reset } - - SystemTesting::Server.new.run + def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {}) + @driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size, options: options) end - def self.selenium?(driver) # :nodoc: - driver == :selenium + # Returns the driver object for the initialized system test + def self.driver + @driver ||= SystemTestCase.driven_by(:selenium) end end diff --git a/actionpack/lib/action_dispatch/system_testing/browser.rb b/actionpack/lib/action_dispatch/system_testing/browser.rb deleted file mode 100644 index 14ea06459d..0000000000 --- a/actionpack/lib/action_dispatch/system_testing/browser.rb +++ /dev/null @@ -1,27 +0,0 @@ -require "action_dispatch/system_testing/driver" - -module ActionDispatch - module SystemTesting - class Browser < Driver # :nodoc: - def initialize(name, screen_size) - super(name) - @name = name - @screen_size = screen_size - end - - def use - register - super - end - - private - def register - Capybara.register_driver @name do |app| - Capybara::Selenium::Driver.new(app, browser: @name).tap do |driver| - driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size) - end - end - end - end - end -end diff --git a/actionpack/lib/action_dispatch/system_testing/driver.rb b/actionpack/lib/action_dispatch/system_testing/driver.rb index 8decb54419..5cf17883f7 100644 --- a/actionpack/lib/action_dispatch/system_testing/driver.rb +++ b/actionpack/lib/action_dispatch/system_testing/driver.rb @@ -1,18 +1,34 @@ module ActionDispatch module SystemTesting class Driver # :nodoc: - def initialize(name) + def initialize(name, **options) @name = name + @browser = options[:using] + @screen_size = options[:screen_size] + @options = options[:options] end def use - @current = Capybara.current_driver - Capybara.current_driver = @name + register if selenium? + setup end - def reset - Capybara.current_driver = @current - end + private + def selenium? + @name == :selenium + end + + def register + Capybara.register_driver @name do |app| + Capybara::Selenium::Driver.new(app, { browser: @browser }.merge(@options)).tap do |driver| + driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size) + end + end + end + + def setup + Capybara.current_driver = @name + end end end end diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb index ddc961cf84..3078e035a3 100644 --- a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb @@ -8,9 +8,20 @@ module ActionDispatch # +take_screenshot+ can be used at any point in your system tests to take # a screenshot of the current state. This can be useful for debugging or # automating visual testing. + # + # The screenshot will be displayed in your console, if supported. + # + # You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to + # control the output. Possible values are: + # * [+inline+ (default)] display the screenshot in the terminal using the + # iTerm image protocol (http://iterm2.com/documentation-images.html). + # * [+simple+] only display the screenshot path. + # This is the default value if the +CI+ environment variables + # is defined. + # * [+artifact+] display the screenshot in the terminal, using the terminal + # artifact format (http://buildkite.github.io/terminal/inline-images/). def take_screenshot save_image - puts "[Screenshot]: #{image_path}" puts display_image end @@ -22,7 +33,7 @@ module ActionDispatch # fails add +take_failed_screenshot+ to the teardown block before clearing # sessions. def take_failed_screenshot - take_screenshot if failed? + take_screenshot if failed? && supports_screenshot? end private @@ -38,14 +49,32 @@ module ActionDispatch page.save_screenshot(Rails.root.join(image_path)) end + def output_type + # Environment variables have priority + output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] || ENV["CAPYBARA_INLINE_SCREENSHOT"] + + # If running in a CI environment, default to simple + output_type ||= "simple" if ENV["CI"] + + # Default + output_type ||= "inline" + + output_type + end + def display_image - if ENV["CAPYBARA_INLINE_SCREENSHOT"] == "artifact" - "\e]1338;url=artifact://#{image_path}\a" - else + message = "[Screenshot]: #{image_path}\n" + + case output_type + when "artifact" + message << "\e]1338;url=artifact://#{image_path}\a\n" + when "inline" name = inline_base64(File.basename(image_path)) image = inline_base64(File.read(image_path)) - "\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a" + message << "\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a\n" end + + message end def inline_base64(path) @@ -55,6 +84,10 @@ module ActionDispatch def failed? !passed? && !skipped? end + + def supports_screenshot? + Capybara.current_driver != :rack_test + end end end end diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb index 491559eedf..187ba2cc5f 100644 --- a/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb @@ -10,9 +10,9 @@ module ActionDispatch end def after_teardown - super take_failed_screenshot Capybara.reset_sessions! + super end end end diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 5fa0b727ab..b46a97413a 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -192,11 +192,10 @@ module ActionDispatch # HTTP methods in integration tests. +#process+ is only required when using a # request method that doesn't have a method defined in the integration tests. # - # This method returns a Response object, which one can use to - # inspect the details of the response. Furthermore, if this method was - # called from an ActionDispatch::IntegrationTest object, then that - # object's <tt>@response</tt> instance variable will point to the same - # response object. + # This method returns the response status, after performing the request. + # Furthermore, if this method was called from an ActionDispatch::IntegrationTest object, + # then that object's <tt>@response</tt> instance variable will point to a Response object + # which one can use to inspect the details of the response. # # Example: # process :get, '/author', params: { since: 201501011400 } @@ -572,7 +571,7 @@ module ActionDispatch # end # # assert_response :success - # assert_equal({ id: Arcticle.last.id, title: "Ahoy!" }, response.parsed_body) + # assert_equal({ id: Article.last.id, title: "Ahoy!" }, response.parsed_body) # end # end # |