0

I am new to selenium web driver and currently working with the Ruby programming language. I currently have a scenario where I need to execute multiple ruby scripts with the selenium web driver but they have to use the same browser session. I am following the documentation provided in the following link: https://github.com/SeleniumHQ/selenium/wiki/Ruby-Bindings

Currently, my code looks like the following.

require 'selenium-webdriver'

# ---------------------------------------------------------
url = "http://localhost:4444/wd/hub"
driver1 = Selenium::WebDriver.for :remote, url: url, desired_capabilities: :firefox
driver1.get "http://www.msn.com"
puts driver1.title

# store the session id
sessionid = driver1.session_id

# ---------------------------------------------------------
#  Try using the existing session id from driver1
driver2 = Selenium::WebDriver.for :remote, url: url, desired_capabilities: :firefox

# The below statement gives error on assignment
driver2.session_id = sessionid
driver2.get "http://www.yahoo.com"

I read this post Can Selenium interact with an existing browser session? and tried to follow the steps provided here unable to use an existing web-driver / browser session.

Has anyone successfully reused the existing session with selenium-webdriver along with Ruby? Kindly let me know what is being missed in this code snippet.

I was able to get this done in python.

from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities



executor_url = "http://localhost:4444/wd/hub"
# Create a desired capabilities object as a starting point.
capabilities = DesiredCapabilities.FIREFOX.copy()
capabilities['platform'] = "WINDOWS"
capabilities['version'] = "10"

# ------------------------ STEP 1 --------------------------------------------------


# driver1 = webdriver.Firefox()
driver1 = webdriver.Remote(command_executor=executor_url, desired_capabilities=capabilities)
driver1.get('http://google.com/')
url = driver1.command_executor._url       
print(driver1.command_executor._url)
print(driver1.session_id)
print(driver1.title)

# Serialize the session id in a file
session_id = driver1.session_id

# ------------------ END OF STEP 1 --------------------------------------------------

# Pass the session id from step 1 to step 2

# ------------------------ STEP 2 --------------------------------------------------
def attach_to_session(executor_url, session_id):
    original_execute = WebDriver.execute
    def new_command_execute(self, command, params=None):
        if command == "newSession":
            # Mock the response
            return {'success': 0, 'value': None, 'sessionId': session_id}
        else:
            return original_execute(self, command, params)
    
    # Patch the function before creating the driver object
    WebDriver.execute = new_command_execute

    temp_driver = webdriver.Remote(command_executor=executor_url)
    # Replace the patched function with original function
    WebDriver.execute = original_execute
    return temp_driver

# read the session id from the file
driver2 = attach_to_session(executor_url, session_id)
driver2.get('http://msn.com/')

print(driver2.command_executor._url)
print(driver2.session_id)

print(driver2.title)
driver2.close()
  • Basically, I am looking for the following answer with Ruby programming language. https://tarunlalwani.com/post/reusing-existing-browser-session-selenium/ and https://stackoverflow.com/questions/8344776/can-selenium-interact-with-an-existing-browser-session – Vishwanath Heddoori Aug 25 '21 at 06:18
  • You would like to attach a browser? Its actually possible in chrome but not possible in Firefox. – Rajagopalan Aug 25 '21 at 12:44
  • Mostly you can't. The reason we don't make it easy is because it is rarely the best solution. If you could do what you tried to do in your example, the driver might think it had capabilities set that the session with that ID does not have. Things would get ugly quickly. What is your use case for needing to access the same browsing sessions from different Ruby processes? – titusfortner Aug 25 '21 at 13:03
  • @titusfortner: The use case is basically to use the same browser session while running different test steps. For e.g. Step 1 -Launch a web browser and navigate to URL and step 2 would be to click at a specific link present in a page. I got this working in python present in the following stack overflow link https://stackoverflow.com/questions/8344776/can-selenium-interact-with-an-existing-browser-session. – Vishwanath Heddoori Aug 25 '21 at 13:23
  • Different test steps shouldn't need different driver sessions. One process one test one driver session. You should be able to pass the driver as an instance variable between steps. What tool are you using? – titusfortner Aug 25 '21 at 14:16
  • 1
    @titusfortner: I've test scripts in ruby and test scripts in python and both should use the same web-driver session. I observe that there is a way to reuse existing session in python by using session id (code added in the description) but is not provided in ruby gem (selenium-webdriver). Few questions ---------------- 1. Is there any technical limitation for not providing this functionality? 2. I was thinking to subclass 'Driver' class from gem and add this functionality. Has this been tried before or are there any technical challenges that you foresee with this approach? – Vishwanath Heddoori Aug 26 '21 at 09:54
  • I meant what test runner are you using like minitest, RSpec or Cucumber? These tools are designed to allow you to work with the driver during the ruby process. I already explained the reason not to allow it, there's no way to ensure that the capabilities match between sessions, which can cause problems that would increase the maintenance costs for the developers. – titusfortner Aug 27 '21 at 02:23
  • @titusfortner: I'm not using any test runner, rather executing the scripts manually one-by-one. So I'm looking for a way where these scripts (ruby/python) can pick up an existing session launched by the previous step execution. Is there a way? Found the following related links [Python impl](https://web.archive.org/web/20171129014322/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium/) [Java Impl](https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/) – Vishwanath Heddoori Aug 27 '21 at 12:26
  • Use the tools everyone else uses to manage driver sessions with instance variables, this is literally what they are there for. Trying to run separate files is much harder in almost every way. – titusfortner Aug 27 '21 at 19:10
  • @titusfortner: Unfortunately, I would be able to use these tools as I have got a customized test runner. I've found a temporary fix that is not clean. Let me know if you have any comments on that. – Vishwanath Heddoori Aug 30 '21 at 12:30
  • This is why Rubyists shouldn't try to write their own custom implementations of standard functionality; libraries are written based on expectations for how other standard tools will interact with them. Each custom thing you do will dramatically increase your overall maintenance cost in unexpected ways. For your sake, I hope this is a tiny project that won't require many changes going forward. – titusfortner Sep 01 '21 at 21:30

1 Answers1

0

I was able to solve this issue by using the following code patch.

class RemoteWebDriver < Selenium::WebDriver::Driver
  def initialize(bridge)
    @bridge = bridge
  end
end

class RemoteBridge < Selenium::WebDriver::Remote::Bridge
  def self.handshake(**opts)
    capabilities = opts.delete(:desired_capabilities) { Capabilities.new }
    @session_id = opts.delete(:session_id)
    Selenium::WebDriver::Remote::W3C::Bridge.new(capabilities, @session_id, **opts)
  end
end

caps = Selenium::WebDriver::Remote::Capabilities.firefox()
remote_bridge = RemoteBridge.handshake(url: <YOUR_REMOTE_WEB_DRIVER_URL>, desired_capabilities: caps, session_id: <YOUR_SESSION_ID>)
remote_web_driver = RemoteWebDriver.new(remote_bridge)
  • Monkey patching like this is a very bad practice and should be avoided. For one, using this code will only work for this specific version of Selenium. – titusfortner Sep 01 '21 at 21:30