Capture Existing Selenium WebDriver Session

Notes on how to intervene an existing selenium web driver session with impelementation and tests.

Problem to Solve

As a software engineer in automation test, sometimes it is the most reasonable method to capture the existing selenium web driver session and intervene with customized action steps. Especially with the commercial toolkit or homemade testing utility but source is not open at the meantime.

In my case, the toolkit is not able to fill up one of the authentication page. However, it offers a keyword to pause until a manual action to input user crediential. Current solution is to monitor the stdout with bash shell, when the typical log of "http://localhost:XXXX" shows up, use the selenium commander URL to capture the existing selenium session. There is still a parameter of session ID missing. This can be solved by an JSON wired protocol end point, "/sessions". Usually toolkit implements singleton on seleenium driver language binding. Query the end point of "/sessions" will return the session ID between web driver executable and the browser.

Solution

Find Existing Session ID

As mentioned in above, the communication between Selenium Development Language bindings and WebDriver executables is the JSON wired protocol.

https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessions

Unfortunately this end point is not implemented with Selenium Java or Python binding. It could be soloved by a new created wrapper function to query existing sessions.

Generally automation test toolkit desktop version implements singleton on selenium binding instance and keep one session. So the query above will return one session in JSON. The solution is to add code parsing the return value and extract the session ID.

For example, if the selenium based toolkit generates stdout or logs as:

http://localhost:6064

The session can be queried by URL in browser with the end point:

http://localhost:6064/sessions

(Update Aug 08, 2017) The sample code to query session information. The codesnap only return the first session ID and capabilities in tuple. Production code shall take care of situation when there are multiple sessions as well.

# return tupple of session ID and capability dict.
@staticmethod
def get_session_id_and_cap(command_executor=None):
if not command_executor:
return None

# requests respects environment variables on proxy and does not bypass localhost.
# It seems the new post IETF draft catches eyes to solve such issues,
# https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-04
os.environ['NO_PROXY'] = 'localhost'

url = command_executor + '/sessions'
resp = requests.get(url=url)
data = json.loads(resp.text)
if data['value']:
return data['value'][0]['id'], data['value'][0]['capabilities']
else:
return None

(End of Aug 08, 2017 Update)

Capture Existing Selenium Session

With an effective session ID and executing commander URL, the captured web driver class overwrites start_session method. Property "w3c" is assigned for Web Element Find method groups.

class CapturedDriver(WebDriver):
"""
>>> CapturedDriver.doctest_visit_github()
PASS
"""
def __init__(self,
command_executor=None,
desired_capabilities={},
browser_profile=None,
proxy=None,
keep_alive=False,
session_id=None,
w3c=True):
super(CapturedDriver, self).__init__(command_executor, desired_capabilities, browser_profile, proxy, keep_alive)
self.session_id = session_id
self.w3c = w3c

def start_session(self, desired_capabilities, browser_profile):
self.capabilities = {}

@staticmethod
def doctest_visit_github():
d = wd.Firefox()
d.get('http://github.com')
# "The world's leading software development platform · GitHub"
title1 = d.title
d2 = CapturedDriver(command_executor=d.command_executor, session_id=d.session_id, w3c=d.w3c)
title2 = d2.title
if title1 == title2:
print "PASS"
else:
print "driver title is %s, captured driver title is %s" % (title1, title2)
d.quit()

if __name__ == "__main__":
import doctest
doctest.testmod()

The unit test is implemented with doctest as a fast way for experiment codes.

The source code is shared at Github Folder now. Java binding solution is still under construction. After that, a separate Github project will be created to maintain this solution together with monitoring bash shell.

Test The Solution

To tes the solution, open a selenium session and extract the session ID and commander URL. For a quick test, the existing github project cucumber-java-toy is used. The code is as below:

public void webDriver1(){
githubPage = new GithubPage(driver, "maxwu");
List<String> followings = githubPage.getFollowingList();
followings.stream().forEach(System.out::println);

URL driverUrl = ((HttpCommandExecutor)(((RemoteWebDriver) driver).getCommandExecutor())).getAddressOfRemoteServer();
String sessionId = ((RemoteWebDriver) driver).getSessionId().toString();
System.out.println("URL=" + driverUrl + " ID=" + sessionId);

System.out.println("Old Title=" + driver.getTitle());

pause();

}

When the commander URL and session ID are available, the quick test could be performed with below Python snap.

from captured_driver.captured_driver import CapturedDriver

if __name__ == "__main__":
# For temp test
# d = CapturedDriver(command_executor='http://127.0.0.1:4444/wd/hub', session_id='')
d = CapturedDriver(command_executor='http://localhost:6064 ', session_id='49075f494d1add687ab74f1cb95f0314')
print "Captured Session Title is %s" % d.title
explore = d.find_element_by_link_text("Explore")
explore.click()
print "Captured Session Title changes to %s" % d.title
d.back()

Successful output of test code shall be:

Captured Session Title is maxwu (Max WU) / Following · GitHub
Captured Session Title changes to Explore · GitHub

Since browser is not running in headless mode, the page transition and backward movement action can also be visual checked that the captured web driver works fine and either driver can quit the session, which leads to a termination on web driver executable process, too.

Future Works

  • Add query on "/sessions" end point for Selenium Java Binding. Prototype passed test. (TODO: update github and maintain in separate repo).

  • Implement Captured Web Driver with Selenium Java Binding.

  • It works fine with GeckoDriver for Firefox on both Mac and Windows. However, IEDriverServer throws 404 error while performing "find*" API calls.

    It finally reject the 2nd connection with Selenium Python binding. In the meantime, title/url property query through the JSON wired protocol works well.

Change Log

Aug 06, 2017: Initial post as a quick note on captured session with selenium web driver.