0

I'm using Capybara::Selenium from my script (not tests) for getting some image from external site. Page loads fine, all images are loaded also and I see them, but any attempt to execute function page.session.driver.evaluate_script always throws Net::ReadTimeout: Net::ReadTimeout with #<TCPSocket:(closed)>.

Full code:

require 'capybara-webkit' require 'selenium-webdriver' JS_GET_IMAGE = <<~EJSGETIMAGE var img = document.getElementById('requestImage'); const cvs = document.createElement('canvas'); cvs.width = img.width; cvs.height = img.height; cvs.getContext('2d').drawImage( img, 0, 0 ); return cvs.toDataURL("image/png"); EJSGETIMAGE session = Capybara::Session.new :selenium page = session.visit Cfg.site.url driver = session.driver.browser driver.manage.timeouts.script_timeout = 5000 @img = driver.execute_async_script JS_GET_IMAGE 

Okay, I started to test very simple script, but that also gone to the same error.

page.session.driver.browser.execute_async_script("setTimeout(arguments[0], 2000)") 

Also I used session = Capybara::Session.new :selenium_headless and got the same error.

  • ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
  • selenium-webdriver (3.142.3)
  • capybara (3.28.0)
  • capybara-webkit (1.15.1)
  • community/geckodriver 0.24.0-1
  • firefox 68.0.1 (64-битный)

Any help is very appreciated.

    1 Answer 1

    2

    Small thing first - there is no need to load capybara-webkit if you're using the Selenium driver.

    Now onto the main issue. There is no need to call methods directly on driver when executing JS, rather you should just be calling the Capybara methods execute_script, evaluate_script, or evaluate_async_script. The evaluate_xxx methods are for when you expect a return value, the execute_script method is for when you don't care about any return value. evaluate_async_script receives a callback function as the last argument which needs to be called to return a value, but your JS_GET_IMAGE doesn't appear to ever do that (nor really need to since it's not async) so it would be better to just use evaluate_script. The other requirement for evaluate_script is that the code evaluated needs to be a single statement. To meet that requirement we can use an IIFE.

    require "capybara/dsl" JS_GET_IMAGE = <<~EJSGETIMAGE (function(){ var img = document.getElementById('requestImage'); const cvs = document.createElement('canvas'); cvs.width = img.width; cvs.height = img.height; cvs.getContext('2d').drawImage( img, 0, 0 ); return cvs.toDataURL("image/png"); })() EJSGETIMAGE session = Capybara::Session.new :selenium session.visit Cfg.site.url @img = session.evaluate_script JS_GET_IMAGE 

    although IMHO it would be better to have Capybara find the element and pass it to the JS function making it more flexible and taking advantage of Capybaras waiting for elements to appear

    require "capybara/dsl" JS_GET_IMAGE = <<~EJSGETIMAGE (function(img){ const cvs = document.createElement('canvas'); cvs.width = img.width; cvs.height = img.height; cvs.getContext('2d').drawImage( img, 0, 0 ); return cvs.toDataURL("image/png"); })(arguments[0]) EJSGETIMAGE session = Capybara::Session.new :selenium session.visit Cfg.site.url img_element = session.find('#requestImage') @img = session.evaluate_script JS_GET_IMAGE, img_element 
    2
    • Your first js example gives me Selenium::WebDriver::Error::JavascriptError: TypeError: img is null but the last one is ok. Thank you!
      – Dimitri
      CommentedAug 16, 2019 at 17:11
    • 1
      @Dimitri Yes - if you executed the script before the id=requestImage element was on the page - then var img = document.getElementById('requestImage'); would set img to null - which means when trying to do img.width you'd get that error. That's one of the reasons why it's better to use Capybara to find the element and pass it in to the JS, because Capybara will wait a bit for the element to be on the page if it isn't yet there initially.CommentedAug 16, 2019 at 17:26

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.