diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/system_testing')
6 files changed, 171 insertions, 41 deletions
diff --git a/actionpack/lib/action_dispatch/system_testing/browser.rb b/actionpack/lib/action_dispatch/system_testing/browser.rb index 14ea06459d..10e6888ab3 100644 --- a/actionpack/lib/action_dispatch/system_testing/browser.rb +++ b/actionpack/lib/action_dispatch/system_testing/browser.rb @@ -1,26 +1,48 @@ -require "action_dispatch/system_testing/driver" +# frozen_string_literal: true module ActionDispatch module SystemTesting - class Browser < Driver # :nodoc: - def initialize(name, screen_size) - super(name) + class Browser # :nodoc: + attr_reader :name + + def initialize(name) @name = name - @screen_size = screen_size end - def use - register - super + def type + case name + when :headless_chrome + :chrome + when :headless_firefox + :firefox + else + name + end + end + + def options + case name + when :headless_chrome + headless_chrome_browser_options + when :headless_firefox + headless_firefox_browser_options + end 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 + def headless_chrome_browser_options + options = Selenium::WebDriver::Chrome::Options.new + options.args << "--headless" + options.args << "--disable-gpu" + + options + end + + def headless_firefox_browser_options + options = Selenium::WebDriver::Firefox::Options.new + options.args << "-headless" + + options 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..5252ff6746 100644 --- a/actionpack/lib/action_dispatch/system_testing/driver.rb +++ b/actionpack/lib/action_dispatch/system_testing/driver.rb @@ -1,18 +1,59 @@ +# frozen_string_literal: true + module ActionDispatch module SystemTesting class Driver # :nodoc: - def initialize(name) + def initialize(name, **options) @name = name + @browser = Browser.new(options[:using]) + @screen_size = options[:screen_size] + @options = options[:options] end def use - @current = Capybara.current_driver - Capybara.current_driver = @name - end + register if registerable? - def reset - Capybara.current_driver = @current + setup end + + private + def registerable? + [:selenium, :poltergeist, :webkit].include?(@name) + end + + def register + Capybara.register_driver @name do |app| + case @name + when :selenium then register_selenium(app) + when :poltergeist then register_poltergeist(app) + when :webkit then register_webkit(app) + end + end + end + + def browser_options + @options.merge(options: @browser.options).compact + end + + def register_selenium(app) + Capybara::Selenium::Driver.new(app, { browser: @browser.type }.merge(browser_options)).tap do |driver| + driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size) + end + end + + def register_poltergeist(app) + Capybara::Poltergeist::Driver.new(app, @options.merge(window_size: @screen_size)) + end + + def register_webkit(app) + Capybara::Webkit::Driver.new(app, Capybara::Webkit::Configuration.to_hash.merge(@options)).tap do |driver| + driver.resize_window_to(driver.current_window_handle, *@screen_size) + end + end + + def setup + Capybara.current_driver = @name + end end end end diff --git a/actionpack/lib/action_dispatch/system_testing/server.rb b/actionpack/lib/action_dispatch/system_testing/server.rb index 4a214ef713..4fc1f33767 100644 --- a/actionpack/lib/action_dispatch/system_testing/server.rb +++ b/actionpack/lib/action_dispatch/system_testing/server.rb @@ -1,27 +1,26 @@ -require "rack/handler/puma" +# frozen_string_literal: true module ActionDispatch module SystemTesting class Server # :nodoc: + class << self + attr_accessor :silence_puma + end + + self.silence_puma = false + def run - register setup end private - def register - Capybara.register_server :rails_puma do |app, port, host| - Rack::Handler::Puma.run(app, Port: port, Threads: "0:1") - end - end - def setup set_server set_port end def set_server - Capybara.server = :rails_puma + Capybara.server = :puma, { Silent: self.class.silence_puma } if Capybara.server == Capybara.servers[:default] end def set_port 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..df0c5d3f0e 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 @@ -1,16 +1,28 @@ +# frozen_string_literal: true + module ActionDispatch module SystemTesting module TestHelpers - # Screenshot helper for system testing + # Screenshot helper for system testing. module ScreenshotHelper # Takes a screenshot of the current page in the browser. # # +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: + # * [+simple+ (default)] Only displays the screenshot path. + # This is the default value. + # * [+inline+] Display the screenshot in the terminal using the + # iTerm image protocol (https://iterm2.com/documentation-images.html). + # * [+artifact+] Display the screenshot in the terminal, using the terminal + # artifact format (https://buildkite.github.io/terminal/inline-images/). def take_screenshot save_image - puts "[Screenshot]: #{image_path}" puts display_image end @@ -22,7 +34,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 @@ -31,21 +43,40 @@ module ActionDispatch end def image_path - "tmp/screenshots/#{image_name}.png" + @image_path ||= absolute_image_path.relative_path_from(Pathname.pwd).to_s + end + + def absolute_image_path + Rails.root.join("tmp/screenshots/#{image_name}.png") end def save_image - page.save_screenshot(Rails.root.join(image_path)) + page.save_screenshot(absolute_image_path) + end + + def output_type + # Environment variables have priority + output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] || ENV["CAPYBARA_INLINE_SCREENSHOT"] + + # Default to outputting a path to the screenshot + output_type ||= "simple" + + output_type end def display_image - if ENV["CAPYBARA_INLINE_SCREENSHOT"] == "artifact" - "\e]1338;url=artifact://#{image_path}\a" - else - 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 = "[Screenshot]: #{image_path}\n".dup + + case output_type + when "artifact" + message << "\e]1338;url=artifact://#{absolute_image_path}\a\n" + when "inline" + name = inline_base64(File.basename(absolute_image_path)) + image = inline_base64(File.read(absolute_image_path)) + message << "\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a\n" end + + message end def inline_base64(path) @@ -55,6 +86,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 187ba2cc5f..ffa85f4e14 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 @@ -1,8 +1,15 @@ +# frozen_string_literal: true + module ActionDispatch module SystemTesting module TestHelpers module SetupAndTeardown # :nodoc: - DEFAULT_HOST = "127.0.0.1" + DEFAULT_HOST = "http://127.0.0.1" + + def host!(host) + super + Capybara.app_host = host + end def before_setup host! DEFAULT_HOST diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb new file mode 100644 index 0000000000..d64be3b3d9 --- /dev/null +++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module ActionDispatch + module SystemTesting + module TestHelpers + module UndefMethods # :nodoc: + extend ActiveSupport::Concern + included do + METHODS = %i(get post put patch delete).freeze + + METHODS.each do |verb| + undef_method verb + end + + def method_missing(method, *args, &block) + if METHODS.include?(method) + raise NoMethodError, "System tests cannot make direct requests via ##{method}; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information." + else + super + end + end + end + end + end + end +end |