capybara-screenshot icon indicating copy to clipboard operation
capybara-screenshot copied to clipboard

Screenshot not getting entire page

Open mfaughn opened this issue 3 years ago • 6 comments

I am using capybara-selenium w/ Chrome headless. The screenshots that are saved on failure are not getting the entire page. The error I'm having is farther down on the page than what is shown in the saved PNG file. Is there some way to configure things to capture the entire page or to take an image that is positioned relative to the last successful focus from capybara?

mfaughn avatar Apr 28 '21 13:04 mfaughn

A solution would be to get the document height/width on the fly with some JS :

height = Math.max($(document).height(), $(window).height())
width = Math.max($(document).width(), $(window).width())

see: https://stackoverflow.com/a/14744331

and do the screenshot with these values instead of using the configured :window_size

I've done the test on my side :

Here my Capybara config :

def register_driver(driver_name)
  opts = {
    js_errors: true,
    timeout: 15,
    window_size: [1920, 1200],
    browser_options: {
      'no-sandbox': nil,
      'disable-gpu': nil,
      'disable-dev-shm-usage': nil,
      'disable-infobars': nil,
      'disable-extensions': nil,``
      'disable-popup-blocking': nil,
    }
  }

  Capybara.register_driver(driver_name) do |app|
    Capybara::Cuprite::Driver.new(app, opts)
  end

  Capybara::Screenshot.register_driver(driver_name) do |driver, path|
    driver.save_screenshot(path)
  end
end

# Register our own custom drivers
register_driver(:headless_chrome)

# Configure Capybara JS driver
Capybara.current_driver    = :headless_chrome
Capybara.javascript_driver = :headless_chrome

capybara-screenshot generates 1920x1200 images.

I've made a full page screenshot with the Firefox tool (right click / make a screenshot) and it generates a 2548x2465 image.

Running the JS above in a console returns (of course) the right values :

Math.max($(document).width(), $(window).width())
2548
Math.max($(document).height(), $(window).height())
2465

n-rodriguez avatar Sep 18 '21 12:09 n-rodriguez

After studying the various API this does the trick for Cuprite (tested in CI) :

Capybara::Screenshot.register_driver(driver_name) do |driver, path|
  driver.save_screenshot(path, full: true)
end

See:

https://github.com/rubycdp/ferrum/blob/master/lib/ferrum/page/screenshot.rb#L31 https://github.com/rubycdp/ferrum/blob/master/lib/ferrum/page/screenshot.rb#L175

n-rodriguez avatar Sep 18 '21 23:09 n-rodriguez

Ferrum doc : https://github.com/rubycdp/ferrum#screenshots

n-rodriguez avatar Sep 24 '21 16:09 n-rodriguez

It looks like it already passes full: true to save_screenshot for the driver named :cuprite as of e19db98b1f6a142a63084e694677f1250bd8e4d4.

So it looks like you only ran into this because you weren't using the default name for the driver (you're calling yours :headless_chrome, which is a great name, by the way—I think I may copy that).

(I've run into similar problems when I've tried to use names that make more sense to me, like calling my Firefox driver :firefox instead of using the default name of :selenium.)

It would be nice if Capybara::Screenshot looked up the adapter code for the current driver based on page.driver.class (Capybara::Cuprite::Driver) rather than Capybara.current_driver (:headless_chrome). Then it wouldn't matter which custom name you had used to register the driver with Capybara (Capybara.register_driver)—it would find it regardless of the name used!

Does that sound reasonable to you guys? If so, here's a MR; please merge. :smile:

TylerRick avatar Oct 25 '22 02:10 TylerRick