Skip to content

Instantly share code, notes, and snippets.

@gkop
Created November 17, 2011 00:13
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save gkop/1371962 to your computer and use it in GitHub Desktop.
Save gkop/1371962 to your computer and use it in GitHub Desktop.
Capture javascript errors in Cucumber+Capybara+Webdriver tests
# in features/support/env.rb
require 'selenium/webdriver'
# we need a firefox extension to start intercepting javascript errors before the page
# scripts load
Capybara.register_driver :selenium do |app|
profile = Selenium::WebDriver::Firefox::Profile.new
# see https://github.com/mguillem/JSErrorCollector
profile.add_extension File.join(Rails.root, "features/support/extensions/JSErrorCollector.xpi")
Capybara::Selenium::Driver.new app, :profile => profile
end
After do |scenario|
if page.driver.to_s.match("Selenium")
errors = page.execute_script("return window.JSErrorCollector_errors.pump()")
if errors.any?
puts '-------------------------------------------------------------'
puts "Found #{errors.length} javascript #{pluralize(errors.length, 'error')}"
puts '-------------------------------------------------------------'
errors.each do |error|
puts " #{error["errorMessage"]} (#{error["sourceName"]}:#{error["lineNumber"]})"
end
raise "Javascript #{pluralize(errors.length, 'error')} detected, see above"
end
end
end
@gkop
Copy link
Author

gkop commented Nov 17, 2011

Note: you may need to define pluralize.

@jaredbeck
Copy link

Four years later, is this still the best way to get a JS stack trace out of selenium-webdriver?

@alexspeller
Copy link

I use this in env.rb:

class DriverJSError < StandardError; end

AfterStep do |scenario, step|

  errors = page.driver.browser.manage.logs.get(:browser)

  if errors.present?
    message = errors.map(&:message).join("\n\n")
    raise DriverJSError, message
  end
end

@jacob-s-son
Copy link

May I suggest a small improvement over @alexspeller suggestion.

class DriverJSError < StandardError; end

AfterStep do |scenario, step|
  errors = page.driver.browser.manage.logs.get(:browser)
    .select {|e| e.level == "SEVERE" && message.present? }
    .map(&:message)
    .to_a

  if errors.present?
    raise DriverJSError, errors.join("\n\n")
  end
end

Main difference here is that it only collects errors (in practice my instance of browser throws quite a lot of warnings, but errors are marked as "SEVERE" in Selenium) and also filters out entries with empty messages (I encountered entries with empty message, though not sure if there are any for "SEVERE" entries).

@anandchavan
Copy link

Not a geek, but would love to understand above lines.

.select {|e| e.level == "SEVERE" && message.present? }
.map(&:message)

To learn above lines, which instance of message variable are we referring to? should it be written as e.message.present?

@jacob-s-son ?

@tyler-boyd
Copy link

@anandchavan you're correct, it should be e.message.present?.

@calebkeene
Copy link

@jacob-s-son the to_a is not necessary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment