How to get Selenoid session ID - selenoid

I would like to clarify how can I use Selenoid API to check downloaded files.
According the documentation to get downloaded file from container I need to call
http://selenoid-host.example.com:4444/download/f2bcd32b-d932-4cdc-a639-687ab8e4f840/myfile.txt
where f2bcd32b-d932-4cdc-a639-687ab8e4f840 is a Selenoid Session ID
So, the question is "How can I get this session ID?"
Value, returned by getSessionId from RemoteWebDriver doesn't look like correct one.
UPD. My bad. Session ID, that I can get from RemoteWebDriver instance, is correct.
The problem was I didn't wait enough to get a file exactly downloaded into container. That's why I got 404 error on attempt to get a file via API

Thats depends on your client bindings that you use for tests.
For example in java:
WebDriver driver = new FirefoxDriver();
SessionId session = ((FirefoxDriver)driver).getSessionId();
System.out.println("Session id: " + session.toString());
If you want to get list of active sessions with their IDs outside of tests: use selenoid /status endpoint
Pleas notice, if you use GGR - it modifies session id -
every new browser session in Selenium automatically obtains an ID
called session ID. According to Selenium JSONWire protocol this ID is
always passed to request. GridRouter appends information about
selected Selenium Hub to this session and returns enriched session ID
to user.
https://hackernoon.com/selenium-testing-a-new-hope-7fa87a501ee9

Related

Using Selenium with an existing session and sign in details [duplicate]

For some unknown reasons ,my browser open test pages of my remote server very slowly. So I am thinking if I can reconnect to the browser after quitting the script but don't execute webdriver.quit() this will leave the browser opened. It is probably kind of HOOK or webdriver handle.
I have looked up the selenium API doc but didn't find any function.
I'm using Chrome 62,x64,windows 7,selenium 3.8.0.
I'll be very appreciated whether the question can be solved or not.
No, you can't reconnect to the previous Web Browsing Session after you quit the script. Even if you are able to extract the Session ID, Cookies and other session attributes from the previous Browsing Context still you won't be able to pass those attributes as a HOOK to the WebDriver.
A cleaner way would be to call webdriver.quit() and then span a new Browsing Context.
Deep Dive
There had been a lot of discussions and attempts around to reconnect WebDriver to an existing running Browsing Context. In the discussion Allow webdriver to attach to a running browser Simon Stewart [Creator WebDriver] clearly mentioned:
Reconnecting to an existing Browsing Context is a browser specific feature, hence can't be implemented in a generic way.
With internet-explorer, it's possible to iterate over the open windows in the OS and find the right IE process to attach to.
firefox and google-chrome needs to be started in a specific mode and configuration, which effectively means that just
attaching to a running instance isn't technically possible.
tl; dr
webdriver.firefox.useExisting not implemented
Yes, that's actually quite easy to do.
A selenium <-> webdriver session is represented by a connection url and session_id, you just reconnect to an existing one.
Disclaimer - the approach is using selenium internal properties ("private", in a way), which may change in new releases; you'd better not use it for production code; it's better not to be used against remote SE (yours hub, or provider like BrowserStack/Sauce Labs), because of a caveat/resource drainage explained at the end.
When a webdriver instance is initiated, you need to get the before-mentioned properties; sample:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.google.com/')
# now Google is opened, the browser is fully functional; print the two properties
# command_executor._url (it's "private", not for a direct usage), and session_id
print(f'driver.command_executor._url: {driver.command_executor._url}')
print(f'driver.session_id: {driver.session_id}')
With those two properties now known, another instance can connect; the "trick" is to initiate a Remote driver, and provide the _url above - thus it will connect to that running selenium process:
driver2 = webdriver.Remote(command_executor=the_known_url)
# when the started selenium is a local one, the url is in the form 'http://127.0.0.1:62526'
When that is ran, you'll see a new browser window being opened.
That's because upon initiating the driver, the selenium library automatically starts a new session for it - and now you have 1 webdriver process with 2 sessions (browsers instances).
If you navigate to an url, you'll see it is executed on that new browser instance, not the one that's left from the previous start - which is not the desired behavior.
At this point, two things need to be done - a) close the current SE session ("the new one"), and b) switch this instance to the previous session:
if driver2.session_id != the_known_session_id: # this is pretty much guaranteed to be the case
driver2.close() # this closes the session's window - it is currently the only one, thus the session itself will be auto-killed, yet:
driver2.quit() # for remote connections (like ours), this deletes the session, but does not stop the SE server
# take the session that's already running
driver2.session_id = the_known_session_id
# do something with the now hijacked session:
driver.get('https://www.bing.com/')
And, that is it - you're now connected to the previous/already existing session, with all its properties (cookies, LocalStorage, etc).
By the way, you do not have to provide desired_capabilities when initiating the new remote driver - those are stored and inherited from the existing session you took over.
Caveat - having a SE process running can lead to some resource drainage in the system.
Whenever one is started and then not closed - like in the first piece of the code - it will stay there until you manually kill it. By this I mean - in Windows for example - you'll see a "chromedriver.exe" process, that you have to terminate manually once you are done with it. It cannot be closed by a driver that has connected to it as to a remote selenium process.
The reason - whenever you initiate a local browser instance, and then call its quit() method, it has 2 parts in it - the first one is to delete the session from the Selenium instance (what's done in the second code piece up there), and the other is to stop the local service (the chrome/geckodriver) - which generally works ok.
The thing is, for Remote sessions the second piece is missing - your local machine cannot control a remote process, that's the work of that remote's hub. So that 2nd part is literally a pass python statement - a no-op.
If you start too many selenium services on a remote hub, and don't have a control over it - that'll lead to resource drainage from that server. Cloud providers like BrowserStack take measures against this - they are closing services with no activity for the last 60s, etc, yet - this is something you don't want to do.
And as for local SE services - just don't forget to occasionally clean up the OS from orphaned selenium drivers you forgot about :)
OK after mixing various solutions shared on here and tweaking I have this working now as below. Script will use previously left open chrome window if present - the remote connection is perfectly able to kill the browser if needed and code functions just fine.
I would love a way to automate the getting of session_id and url for previous active session without having to write them out to a file during hte previous session for pick up...
This is my first post on here so apologies for breaking any norms
#Set manually - read/write from a file for automation
session_id = "e0137cd71ab49b111f0151c756625d31"
executor_url = "http://localhost:50491"
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
driver = webdriver.Remote(command_executor=executor_url, desired_capabilities={})
driver.session_id = session_id
# Replace the patched function with original function
WebDriver.execute = original_execute
return driver
remote_session = 0
#Try to connect to the last opened session - if failing open new window
try:
driver = attach_to_session(executor_url,session_id)
driver.current_url
print(" Driver has an active window we have connected to it and running here now : ")
print(" Chrome session ID ",session_id)
print(" executor_url",executor_url)
except:
print("No Driver window open - make a new one")
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()),options=myoptions)
session_id = driver.session_id
executor_url = driver.command_executor._url
Without getting into why do you think that leaving an open browser windows will solve the problem of being slow, you don't really need a handle to do that. Just keep running the tests without closing the session or, in other words, without calling driver.quit() as you have mentioned yourself. The question here though framework that comes with its own runner? Like Cucumber?
In any case, you must have some "setup" and "cleanup" code. So what you need to do is to ensure during the "cleanup" phase that the browser is back to its initial state. That means:
Blank page is displayed
Cookies are erased for the session

Swtich browsers in Karate

I am new to Karate UI automation, stuck with an issue and need advice on how to proceed.
I have a test scenario which is a 3 step process
User A logs in and fills up a form
User B logs in with a different browser and approves the application
User A(already logged in) in step 1 can view that his application is accepted
The e2e test snippet is as follows:
Scenario: E2E - User agreement acceptance
#1 USER A logs in and fills agreement form
When def userA_create_agreement = call read('./../Features/CreateAgreement.feature') { shared_agrname: '#(SharedAgreementName)' }
#2 USER B retrieve above agmt and approves it
When def userB_read_agreement = call read('./../Features/ReadAndApprove.feature') { shared_agrname: '#(SharedAgreementName)' }
#3 USER A confirms acceptance
When def userA_confirm_acceptance = call read('./../Features/ConfirmAcceptance.feature') { shared_agrname: '#(SharedAgreementName)' }
Each of the 'called' feature files - CreateAgreement.feature, ReadAndApprove.feature, ConfirmAcceptance.feature have the following background section
Background:
* configure driver = { type: '#(drivertype)', executable: '#(driverpath)'}
Scenario:
Given driver agreementmanager_url
.....
.....
For step 1 and 3 the drivertype and driverpath is chrome
and for step 2 its firefox. User A and B cannot be logged in at the same time with the same browser. This is by design.
With the above way currently, each of the steps invokes a new browser instance and runs the tests rightly so because I am invoking the driver every time in each of the called feature files. What I am looking for is to be able to switch between the browsers and continue running without needing to invoke a new instance in each feature file if its not needed.
So
Step 1 - User A logs in and registers using Chrome
Step 2 - User B logs in and approves using Firefox
Step 3 - Switches back to browser instance of step 1 with User A(who is already logged), views the update of acceptance.
I was wondering if this was possible using Karate? I read the documentation and we have switchPage() that switches between tabs of the same browser but is there a way we can switch browers without having the need to relaunch a new instance and login again?
Any advice or help in how to achieve this will be really helpful.
I would simplify your scenario to not have 2 browsers open at the same time. You can try this sequence that should switch from Chrome to Firefox:
* configure driver = { type: 'chrome' }
* driver 'https://github.com/login'
* driver.quit()
* configure driver = { type: 'geckodriver' }
* driver 'https://google.com'
So the rule is if you quit() you can start a new browser in a flow (0.9.6 onwards).
If you really insist on having Chrome open, maybe you can experiment with the Java API, which gives you more control: https://github.com/intuit/karate/tree/master/karate-core#chrome-java-api
But have you really reached a level of maturity where all the other things you want to test are running trouble free :)
Anyway, to simulate the "logged in" context from the first browser - all you need to do is pick up the cookie values and recreate the cookies later in the test. That is what I would recommend as your test strategy instead of juggling browsers. I would also get that flow to work first before even thinking of switching from Chrome to FireFox, for example I'm not sure if you can even get that to work in Docker or CI. Or are you using a Selenium grid ?

Pass a process ID to start selenium in

How can I pass a chrome process ID to selenium to force it to start an existing browser? I tried passing arguments to capabilities but they did not help.
Thanks
Any help is appreciated.
capabilities.setCapability( "pid", pid ); //$NON-NLS-1$
ChromeDriver driver = new ChromeDriver(capabilities);
Answering straight, No, you can't pass a Chrome Process ID [PID] to Selenium to force it to start an existing browser.
Similarly, even if you are able to extract the Session ID and other session attributes from the previous Browsing Session still you won't be able to pass those attributes as a HOOK to the WebDriver.

Selenium Grid Proxy: how to get the response after a command get executed

I created a Selenium Grid proxy, I want to log every command done, the problem is I can't find a way to get the response of the command for example after "GetTitle" command I want to get the "Title" returned.
Where do you want this logging to be done ? If you attempt at logging this at the Custom Proxy, then these logs would be available only on the machine that runs the hub. Is that what you want ? If yes, then here's how you should be doing it :
Within an overloaded variant of org.openqa.grid.internal.listeners.CommandListener#afterCommand (this method should be available in your DefaultRemoteProxy extension object that you are building), extract this information from within the javax.servlet.http.HttpServletRequest by reading its entity value and then translating that into a proper payload.
Here's how the afterCommand() (or) beforeCommand() method from your customized version of org.openqa.grid.selenium.proxy.DefaultRemoteProxy can look like:
org.openqa.grid.web.servlet.handler.SeleniumBasedResponse ar = new org.openqa.grid.web.servlet.handler.SeleniumBasedResponse(response);
if (ar.getForwardedContent() != null) {
System.err.println("Content" + ar.getForwardedContent());
}
If that's not what you want, then you should be looking at leveraging the EventFiringWebDriver. Take a look at the below blogs to learn how to work with the EventFiringWebDriver. The EventFiringWebDriver does not require customization at the Grid side, it just needs you to make use of the EventFiringWebDriver which would wrap within it an existing RemoteWebDriver object and the listeners you inject to it will help you get this.
http://darrellgrainger.blogspot.in/2011/02/generating-screen-capture-on-exception.html
https://rationaleemotions.wordpress.com/2015/04/18/eavesdropping-into-webdriver/ (This is my blog) Here I talk about not even using EventFiringWebDriver but instead work with a decorated CommandExecutor which would log all these information for you.

RESTAssured and WebDriver: get and use a session id from browser

I'm trying to use WebDriver to get the session ID from the browser being tested so that I can pass that ID in through the given().session(string) functionality in RESTAssured. The browser will go through a normal login to create the session ID. Any ideas how to capture it?
You can get your session id by casting the driver object to RemoteWebDriver like this
String session = ((RemoteWebDriver) driver).getSessionId().toString();
Maybe you could just read it from cookie. Or I don't understand the problem.
Here is similar problem Get cookies in Webdriver how?