In our previous articles we discussed about re-using Browser session in Selenium for local browsers. We spoke about saving the Session ID and the Executor URL for re-creating the sessions. Now let’s us have re-look at the approach when we use Selenium Grid
Launching the Grid
I am using brew
to install selenium-server-standalone
on my Mac. But if you are using something else, then download the latest version from here
$ selenium-server
For those downloading the jar
$ java -jar selenium-server-standalone-3.4.0.jar
By default the grid launches on port 4444
.
Launching the drivers
So let us now launch the driver for Firefox and chrome in Python
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
grid_url = "http://127.0.0.1:4444/wd/hub"
driver_firefox = webdriver.Remote(grid_url, DesiredCapabilities.FIREFOX)
driver_chrome = webdriver.Remote(grid_url, DesiredCapabilities.CHROME)
Now let us print the executor url for one of the drivers
print (driver_firefox.command_executor._url)
This outputs http://127.0.0.1:4444/wd/hub
which is nothing but the grid_url
that we specified.
In our previous approach we had to save the command executor url to some place and re-use it later to re-create the driver object. But in case of the Selenium Grid the command executor URL is same as the Grid url itself. So no saving needed.
Getting the Session ID
The two key information needed to re-use a Selenium browser session is session_id
and command_executor_url
, we have the later one already for the grid. Now we need to figure out how to get the session ids.
Luckily the Selenium grid implements a /sessions
API endpoint. So if we hit the URL we get below response
$ curl http://127.0.0.1:4444/wd/hub/sessions | jq
{
"state": "success",
"sessionId": null,
"hCode": 973499128,
"value": [
{
"capabilities": {
"moz:profile": "/var/folders/4k/n292r2rj5_z3cb9ky0vh_szmk_m94b/T/rust_mozprofile.2ntb14zZkPUC",
"rotatable": false,
"timeouts": {
"implicit": 0,
"pageLoad": 300000,
"script": 30000
},
"pageLoadStrategy": "normal",
"platform": "ANY",
"specificationLevel": 0,
"moz:accessibilityChecks": false,
"acceptInsecureCerts": true,
"browserVersion": "53.0.3",
"platformVersion": "16.6.0",
"moz:processID": 10299,
"browserName": "firefox",
"takesScreenshot": true,
"javascriptEnabled": true,
"platformName": "darwin",
"cssSelectorsEnabled": true
},
"id": "26294a77-7ab2-47f1-81fd-e11f593bd960",
"hCode": 1451216119,
"class": "org.openqa.selenium.remote.server.handler.GetAllSessions$SessionInfo"
},
{
"capabilities": {
"applicationCacheEnabled": false,
"rotatable": false,
"mobileEmulationEnabled": false,
"networkConnectionEnabled": true,
"chrome": {
"chromedriverVersion": "2.27.440174 (e97a722caafc2d3a8b807ee115bfb307f7d2cfd9)",
"userDataDir": "/var/folders/4k/n292r2rj5_z3cb9ky0vh_szmk_m94b/T/.org.chromium.Chromium.ZtW0SD"
},
"takesHeapSnapshot": true,
"pageLoadStrategy": "normal",
"unhandledPromptBehavior": "",
"databaseEnabled": false,
"handlesAlerts": true,
"hasTouchScreen": true,
"version": "58.0.3029.110",
"platform": "MAC",
"browserConnectionEnabled": false,
"nativeEvents": true,
"acceptSslCerts": true,
"locationContextEnabled": true,
"webStorageEnabled": true,
"browserName": "chrome",
"takesScreenshot": true,
"javascriptEnabled": true,
"cssSelectorsEnabled": true,
"unexpectedAlertBehaviour": ""
},
"id": "29aa25cb-a60a-4454-a35c-315f76ff1251",
"hCode": 966845962,
"class": "org.openqa.selenium.remote.server.handler.GetAllSessions$SessionInfo"
}
],
"class": "org.openqa.selenium.remote.Response",
"status": 0
}
We can read these details in python using below code
import urllib.request
import json
grid_url = "http://127.0.0.1:4444/wd/hub"
sessions_req = urllib.request.urlopen(grid_url + "/sessions")
sessions_data = sessions_req.read()
sessions_encoding = sessions_req.info().get_content_charset('utf-8')
sessions = json.loads(sessions_data.decode(sessions_encoding))
for session in sessions["value"]:
print (session["id"])
print (session["capabilities"]["browserName"])
The above code prints
26294a77-7ab2-47f1-81fd-e11f593bd960
firefox
29aa25cb-a60a-4454-a35c-315f76ff1251
chrome
So now we have the session id also of our browsers. Using the function the we create in our previous article
def create_driver_session(session_id, executor_url):
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
# Save the original function, so we can revert our patch
org_command_execute = RemoteWebDriver.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 org_command_execute(self, command, params)
# Patch the function before creating the driver object
RemoteWebDriver.execute = new_command_execute
new_driver = webdriver.Remote(command_executor=executor_url, desired_capabilities={})
new_driver.session_id = session_id
# Replace the patched function with original function
RemoteWebDriver.execute = org_command_execute
return new_driver
Let us recreate these two drivers
driver_firefox_reuse = create_driver_session("26294a77-7ab2-47f1-81fd-e11f593bd960", grid_url)
driver_chrome_reuse = create_driver_session("29aa25cb-a60a-4454-a35c-315f76ff1251", grid_url)
driver_firefox_reuse.get("http://tarunlalwani.in")
driver_chrome_reuse.get("http://tarunlalwani.in")
And both the browsers navigate to the desired location. This approach creates depenceny on using Grid but in return makes re-using browser sessions a piece of cake.