neumachen
11/11/2015 - 9:04 PM

Continuous Integration, parallel_tests, cucumber, headless, capybara-webkit, chrome. For mac and linux.Conditionally @show chrome browser (:

Continuous Integration, parallel_tests, cucumber, headless, capybara-webkit, chrome. For mac and linux.Conditionally @show chrome browser (:selenium) in development if @show tag is used, otherwise run headless and always run headless in a CI environment regardless of the tag's presence. Check javascript errors automatically when using webkit.

# verified against log_in.feature for blake
# https://github.com/jnicklas/capybara/issues/1443
# turn on webkit driver debug
$use_webkit = true
$use_chrome_instead_of_firefox = false
$webkit_debug = false
$wait_time = 5

def webkit_driver
  if $webkit_debug
    return :webkit_debug
  else
    return :webkit
  end
end

def webkit?
  [:webkit, :webkit_debug].include? Capybara.current_driver
end

def selenium?
  Capybara.javascript_driver == :selenium
end

if $use_chrome_instead_of_firefox
  # Register chrome browser for the :selenium driver, can be triggered below with the combination of @javascript @show
  Capybara.register_driver :selenium do |app|
    Capybara::Selenium::Driver.new(app, :browser => :chrome)
  end
end


# try to get a unique port, important for parallels tests
# if ENV['TEST_ENV_NUMBER']
test_env_number = ENV['TEST_ENV_NUMBER']
test_env_number ||= 1
test_port = 9887 + test_env_number.to_i
#test_port += 1 while is_port_open?(@port) and not is_running_on_port?(@port)

puts "Capybara::Server.port: #{test_port} for test process: #{test_env_number}"
Capybara.server_port = test_port
# end


if $headless_server.nil?

  # Unnecessary on mac, see https://github.com/leonid-shevtsov/headless/issues/31#issuecomment-8933108
  if !OS.mac?
    require 'headless'
    # allow display autopick (by default)
    # allow each headless to destroy_at_exit (by default)
    # allow each process to have their own headless by setting reuse: false
    # $headless_server = Headless.new(reuse: false)
    $headless_server = Headless.new(reuse: true, destroy_at_exit: false)
    $headless_server.start

    puts "Process[#{Process.pid}] started headless server display: #{$headless_server.display}"
  end
end

at_exit do
  unless $headless_server.nil?
    puts "Process[#{Process.pid}] destroying headless server on display: #{$headless_server.display}"
    $headless_server.destroy
  end
end


# first time around, we need this set.
if $use_webkit
  Capybara.default_driver = webkit_driver
  # Capybara.current_driver = webkit_driver
  # Capybara.javascript_driver = webkit_driver
end


#
# If the @show tag is present on a non-mac environment, ignore it,
#   otherwise allow the combination of @javascript @show to trigger the
#   :selenium driver (which is :chrome browser as configured above)
#
Before do |scenario|

  if $use_webkit
    Capybara.current_driver = webkit_driver
    Capybara.javascript_driver = webkit_driver
  end

  # problem on @show with backgrounds: https://github.com/cucumber/cucumber/issues/52
  if should_show(scenario)

    # for some reason, just using the `using_driver` doesn't get us all the way there, so set/reset the `javascript_driver` as necessary.
    Capybara.current_driver = :selenium
    Capybara.javascript_driver = :selenium # needed for @show with chrome, as it doesn't seem to explicitly set the javascript driver
  end
  # puts "Using #{Capybara.current_driver}/#{Capybara.javascript_driver}/#{Capybara.default_driver}"
end


After do |scenario|

  # problem on @show with backgrounds: https://github.com/cucumber/cucumber/issues/52
  # puts "Done #{Capybara.current_driver}/#{Capybara.javascript_driver}/#{Capybara.default_driver}"
  Capybara.use_default_driver
end

def should_show(scenario)
  OS.mac? && (has_tag(scenario, '@show') || has_tag(scenario, '@leave_browser_open') || has_tag(scenario, '@single_step'))
end

def has_tag(scenario, tag)
  (scenario.source_tags.map do |tag|
    tag.name
  end).include? tag
end

# Increase wait time for ajax retries
Capybara.default_wait_time = $wait_time

Before do |scenario|
  @scenario = scenario
  # reset to wait time in case something in the scenario upped it as it was long running
  Capybara.default_wait_time = $wait_time
end


# webkit javascript check only
AfterStep do
  if webkit?
    begin

      #puts "All Javascript errors: #{page.driver.error_messages}"
      # puts "All console messages: #{page.driver.console_messages}"
      real_error_messages = page.driver.error_messages
      #real_error_messages = []
      #page.driver.error_messages.each_with_index do |e, i|
      #  # first two messages appear to be bogus, always.
      #  if (e[:line_number] == 0) && (e[:source].eql? 'undefined') && (e[:message].eql? 'TypeError: \'null\' is not an object') && i <= 1
      #    # discard message
      #  else
      #    real_error_messages << e
      #  end
      #end
      if real_error_messages.length > 0
        unless real_error_messages.first[:source].include?('https://a.stripecdn.com/manage/assets/application.manage')
          raise "Javascript errors: #{real_error_messages}"
        end
      end
    rescue
      puts "Failed to check javascript error messages."
    end
  end
end

After do |scenario|
  if (scenario.failed?)
    print_console_messages scenario
  end
end

def print_console_messages(scenario)
  return unless webkit?
  begin
    messages =  page.driver.console_messages

    if messages.presence && messages.size > 0
      print "\n--------------------------------------------------------------------------------------------------------------------------------------------"
      print "\nConsole: #{scenario_unique_name(scenario)}: "
      print "\n---------------------------------------------------------------------------\n"
      messages.each do |console_message|
        print "\n"
        print console_message[:message]
      end
      print "\n--------------------------------------------------------------------------------------------------------------------------------------------"
    else
      print "\n--------------------------------------------------------------------------------------------------------------------------------------------"
      print "\nNo Console messages for: #{scenario_unique_name(scenario)}: "
      print "\n--------------------------------------------------------------------------------------------------------------------------------------------"
    end
    $stdout.flush
  rescue
    puts "Failed to write console messages."
  end
end