17

I need to capture the console logs (category: info) of a browser using Ruby & Capybara. Until now I have tried using driver.manage.logs.get(:browser) or (:client) but, using this, the result is not what I want. It gives out the interaction results between selenium and browser where I can see my javascript statements sent for execution, but the resulting output fails to get captured.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Vivek Khurana
  • 251
  • 1
  • 3
  • 8

6 Answers6

31

Whether or not logs are available when using selenium depends on what browser you are using with Selenium. If you were using Firefox you'd be out of luck since it doesn't support the log retrieval API, however since you're using Chrome they are accessible. The issue you're having is that, by default, only WARN or ERROR level logs are captured. You can change this in the driver registration through the loggingPrefs capability

Selenium 3

    Capybara.register_driver :logging_selenium_chrome do |app|
      caps = Selenium::WebDriver::Remote::Capabilities.chrome(loggingPrefs:{browser: 'ALL'})
      browser_options = ::Selenium::WebDriver::Chrome::Options.new()
      # browser_options.args << '--some_option' # add whatever browser args and other options you need (--headless, etc)
      Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options, desired_capabilities: caps)
    end

Selenium 4

   Capybara.register_driver :logging_selenium_chrome do |app|
     options = Selenium::WebDriver::Chrome::Options.new
     options.add_option("goog:loggingPrefs", {browser: 'ALL'})

     browser_options = ::Selenium::WebDriver::Chrome::Options.new()

     Capybara.register_driver :chrome do |app|
     Capybara::Selenium::Driver.new(app,
                                 capabilities: options,
                                 browser: :chrome)
     end
   end

and then specify to use :logging_selenium_chrome as your driver

 Capybara.javascript_driver = :logging_selenium_chrome # or however else you're specifying which driver to use

which should then allow you to get the logs in your tests with

page.driver.browser.manage.logs.get(:browser)
Jason FB
  • 4,752
  • 3
  • 38
  • 69
Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
  • Thanks for the reply @Thomas Walpole. I tried to implement your solution but I am getting **uninitialized constant Selenium::WebDriver::Chrome::Options (NameError)** constantly. Do you have any solution so I can implement it more fastly. – Vivek Khurana Sep 19 '17 at 12:18
  • @VivekKhurana what version of selenium are you using? – Thomas Walpole Sep 19 '17 at 14:34
  • 1
    @VivekKhurana Update your `selenium-webdriver` gem - The `Chrome::Options` class was added in 3.4.1. The current release is 3.5.2, upgrade to that. – Thomas Walpole Sep 19 '17 at 16:31
  • You saved my day. – Pedro Adame Vergara Mar 27 '18 at 11:19
  • 2
    Does not work for me at `Google Chrome 85.0.4183.83` & `ChromeDriver 85.0.4183.83` `NoMethodError: private method 'log' called for #` – milushov Sep 04 '20 at 06:28
  • See https://stackoverflow.com/q/56522499/120136 for info about `NoMethodError: private method 'log' called for # – L.R. Apr 08 '21 at 19:02
9

Thomas Walpole answer is correct but it seems that nowadays if you are using chrome as your driver you should use

Selenium::WebDriver::Remote::Capabilities.chrome( "goog:loggingPrefs": { browser: 'ALL' } )

Notice goog:loggingPrefs instead of loggingPrefs only with this solution i was able to get console.log printed in the log.

Took me a while and got it from here https://intellipaat.com/community/5478/getting-console-log-output-from-chrome-with-selenium-python-api-bindings after several frustrating attempts.

0Ds0
  • 598
  • 5
  • 19
  • I believe this is the case for Chrome 75+, the original config works for up to Chrome 74. – boylec1986 Mar 24 '20 at 17:20
  • 1
    Does not work for me at `Google Chrome 85.0.4183.83` & `ChromeDriver 85.0.4183.83` `NoMethodError: private method 'log' called for #` – milushov Sep 04 '20 at 06:31
  • for modern Chrome, you need to specify `goog:loggingPrefs` as `{browser: 'ALL'}` (see selenium configuration answers above) – Jason FB Dec 29 '22 at 23:08
2

November 2022 update, use:

page.driver.browser.logs.get(:browser)

jmccure
  • 1,180
  • 7
  • 16
  • for modern Chrome, you need to specify `goog:loggingPrefs` as `{browser: 'ALL'}` (see selenium configuration answers above) – Jason FB Dec 29 '22 at 23:09
1

Not sure that this is what you want, but take a look at https://github.com/dbalatero/capybara-chromedriver-logger.

It helps me identify the problem with dynamic modules import(''). Works both locally and in Github Actions / Circle CI by displaying failed loads of assets (which i believe outputs as console.error).

woto
  • 2,893
  • 1
  • 29
  • 24
0

Building on the answers from @thomas-walpole and @0ds0, rummaging through various other posts, and following-up on deprecation warnings led me to this code (working as of July 2023 w/ Chrome v114). It also reproduces the code that Capybara uses to build the original selenium_chrome driver.

Capybara.register_driver :selenium_chrome do |app|
  browser_options = Selenium::WebDriver::Chrome::Options.new.tap do |opts|
    # Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
    opts.add_argument('--disable-site-isolation-trials')

    opts.add_option('goog:loggingPrefs', browser: 'ALL')
  end

  Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
end

Capybara.javascript_driver = :selenium_chrome

I store the logs like so:

config.prepend_after(js: true) do |example|
  Selenium::WebDriver.logger.info "Finishing Capybara test: #{example.location}\n"

  browser_logs = page.driver.browser.logs.get(:browser)
  log_str = SystemConfigurationHelpers.make_browser_log_string(browser_logs)

  Selenium::WebDriver.logger.info "** Browser logs for #{example.location}:\n\n#{log_str}\n"

  driver_logs = page.driver.browser.logs.get(:driver)
  log_str = SystemConfigurationHelpers.make_browser_log_string(driver_logs)

  Selenium::WebDriver.logger.info "** Driver logs for #{example.location}:\n\n#{log_str}\n"
end

the code that makes the log entries look nice is:

module SystemConfigurationHelpers
  # Convenience method used for displaying browser log statements extracted from Selenium
  # @param [Array<String>] collection of browser log statements
  # @return [String] newline-delimited list of formatted log messages
  def self.make_browser_log_string(logs)
    logs.inject(+'') do |result, log|
      result << "* #{log.time} #{log.level}: #{log.message}\n"
    end
  end
end
subelsky
  • 405
  • 6
  • 12
0

I was running into the deprecated warning about Selenium::WebDriver::Remote::Capabilities.

This is working for me, and seems inline with what the documentation suggests:

    ...
    # this gives us access to the javascript logs using `page.driver.browser.logs.get(:browser)` in our test
    # see https://www.selenium.dev/documentation/webdriver/browsers/chrome/
    service = Selenium::WebDriver::Service.chrome
    service.args << '--log-level=ALL'

    Capybara::Selenium::Driver.new(
      app,
      browser: :chrome,
      options: options,
      service: service
    )