Skip to content

new functionality to re-use existing browser session #690

Closed

Description

@yahman72

What do you guys think about this kind of enhancement:
Add a new KW (or extend the Create Webdriver) for attaching to an existing browser/selenium session.

This doesn't make that much sense in "production" environment but would be very useful when implementing test cases. The idea would be to speed-up following scenarios

  • When testing web apps there's quite often a scenario where you do lots of stuff and then something breaks: e.g. you have typo in your xpath, a timing issue with (e.g. jQuery not finished) or something else. When this happens you have to start from the beginning but it would be great if you could continue from the point where the TC broke ...
  • In environments where the set-up is time consuming, it would great to reuse the browser session(s). For example a set-up where you open a browser and login to the web-app, open another browser and login to the CRM, open yet another browser and login to a web-email app. It would be great to keep those 3 browsers open and skip the browser opening and login steps...

I need this functionality and will implement it for sure, the question is just: should I implement it in my libraries (that use selenium2lib) or should I create a PR for this?

Here a short example how to connect to an existing session:

  • Open new browser, print out the session details and leave the browser open
> python sel.py 
c1c31e1e-9b19-4363-9ab7-369e84313601  http://127.0.0.1:55486/hub
  • Go manually to google.com with the browser
  • re-attach (with session details) and click the I'm feeling lucky button:
> python sel.py c1c31e1e-9b19-4363-9ab7-369e84313601  http://127.0.0.1:55486/hub

sel.py file:

from selenium.webdriver import Firefox, Remote
import sys

def open():
    driver = Firefox()
    print("%s  %s" % (driver.session_id, driver.command_executor._url))
    
def attach(sid, url):
    driver = Remote(command_executor=url, desired_capabilities={})
    driver.session_id = sid
    driver.find_element_by_xpath("//input[contains(@value, 'Lucky')]").click()

sid = sys.argv[1] if len(sys.argv) > 1 else None
url = sys.argv[2] if len(sys.argv) > 2 else None

if sid is None:
    open()
else:
    attach(sid, url)

Activity

  1. pekkaklarck commented on Nov 18, 2016

    @pekkaklarck
    Member

    AFAIK this isn't supported by Selenium itself.

  2. aaltat commented on Nov 18, 2016

    @aaltat
    Contributor

    Pekka is right and your request is not possible: SeleniumHQ/selenium-google-code-issue-archive#18 If you want support for this, then could you open issue to the selenium side.

    Because this is not an issue Selenium2Library or we can not do anything to fix it, I am closing the issue.

    As a side note, if your test setup time is too big, which is also my problem, it's usually best idea to start changing the product to the direction that it can be tested in smaller chunks.

  3. yahman72 commented on Nov 18, 2016

    @yahman72
    Author

    First of all, my example code does exactly this, it reuses the Firefox session = not possible is definitely not correct.

    About that selenium issue:

    • it's very old - so I'm not so sure whether it's still valid.
    • it's about generic support (i.e. all browsers) and might valid for some browsers (I tried it only with Firefox).

    Assuming the worst-case, i.e. works only with Firefox, this functionality would be usable because you could do (most of) the test case implementation with Firefox to get rid of those coding errors...

  4. hirsivaja commented on Nov 18, 2016

    @hirsivaja

    I think they are talking about a different issue in the Selenium Github page. They are saying that it is impossible to attach the webdriver to an existing browser instance that is started without Selenium. Yahman on the other hand is suggesting that Selenium2Library should be able to connect to a running webdriver instance instead of creating a new one and possibly switching between instances during the test case.

  5. pekkaklarck commented on Nov 18, 2016

    @pekkaklarck
    Member

    Sorry, didn't read the issue fully when I see this on mobile. What Selenium cannot do is attaching to an already externally opened session, but you apparently want to attach to a session that Selenium itself has already opened.

  6. pekkaklarck commented on Nov 18, 2016

    @pekkaklarck
    Member

    Could you clarify how would you use this functionality in practice? You one test run leave a browser open and you'd run a separate that attaches to that?

    Would you be interested to implement this support yourself?

  7. yahman72 commented on Nov 18, 2016

    @yahman72
    Author

    @pekkaklarck: Correct, open browser with Selenium and reconnect (see/try the example code). Just read the original issue description - without using your mobile :-)

    As I already mentioned: I'll definitely implement this for myself. For me it's enough when it works with Firefox only, but if the same implementation works also for the other browsers even better.

    I propose the following:

    • I'll figure out how it could work and update this issue with my findings.
    • Based on the findings we can make the final decision whether to include this functionality or not.
  8. pekkaklarck commented on Nov 18, 2016

    @pekkaklarck
    Member

    At least I don't see any problems adding this kind of functionality, but it definitely need to support also other browsers than Firefox. If it isn't a generic Selenium feature, there's a big chance future changes to Firefox break it. If it's part of the Selenium spec, then the feature ought to be stable.

    Part of the implementation would be figuring out how to get the session id so that it can be used later. Perhaps there could be a separate Save Session Id keyword that saves the id into a temporary file that Attach To Browser could then automatically read.

  9. ombre42 commented on Nov 18, 2016

    @ombre42
    Contributor

    I have been in your situation, dealing with tests that fail after minutes of execution, so I understand why you might want this. My question to you is - have you tried using a debugger to handle these scenarios?
    I have done the very crude step of inserting a line like this in a test:

    Evaluate    pdb.Pdb(stdout=sys.__stdout__).set_trace()    pdb,sys
    

    But you have to do everything on the command line in pure python.
    There is also robotframework-debuglibrary. I have not tried it but it looks pretty awesome.

    The problem with attaching to a existing session include:

    • Robot Framework variables initiated up to the point of failure based on the things that vary at runtime will not have useful values in the second run
    • You have disable the teardown to prevent the session from being destroyed.
    • For Grid, you would have to execute the second run and attach to the session before it times out (2 minutes or so?)
  10. aaltat commented on Nov 19, 2016

    @aaltat
    Contributor

    I also know this pain, specially when developing the test. To the problems that @ombre42 did say and which I also know, I have one more thing to consider. The internal state of the SUT.

    Usually when user logs in to the web app, there is a state. Example when testing that user account is locked after X number of failure login attempts, there is internal counter in the SUT which I need to take in to the consideration. Because if that internal state is not cleared, the SUT will behave differently than expected in the second test run (when those setup functionality is not executed to clear/reset the SUT) and test will fail again but from a different reason.

    To tackle the problem, I try to develop the test in smaller pieces. Do the setup once (like a swing deployment, user creation and so on) and then develop the first thing and then jump directly to the next. Like in this case open browser to the login page and enter wrong password. Iterate over until that part works fine. Then check the error message is displayed correctly. Then repeat the keywords few times that the account is locked. Then stay I stay in this state (I don't run the keywords which will lock the account, I trust that application keeps the account locked) and develop keywords to verify that account is locked.

    But each web app is different and what others are doing may not be suitable for you. And the solution which you are proposing may be the best for you.

    Other idea which comes in to my mind, is to create a keyword in S2L which allows users to register driver to the S2L. It would give users more freedom to create the driver as users wanted and still benefit from the S2L functionality. There is internal interface, but it's not exposed as a keyword.

  11. yahman72 commented on Nov 21, 2016

    @yahman72
    Author

    Thanks for the tips. That debuglibrary looks interesting, it looks like that it could be useful for some scenarios. However my main issue is not how to figure out what went wrong (RF debug logs have been good enough for this purpose) but the complexity of the test environment.

    I'm doing end-to-end testing for a set of systems, i.e. interactions between the systems e.g. "do something in WebApp-A, check WebApp-B and do something, check WebApp-A and WebApp-C, etc.". In another words, I have 3-4 Browser Windows that open at each pybot-execution, only opening those windows takes forever (at least feels like it :-). This is one the steps that I'm trying to speed up with this.

  12. aaltat commented on Nov 21, 2016

    @aaltat
    Contributor

    As a side note one can get the session ID from the server side: https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessions

    You may need to build some logic, if there are multiple session ID lying around in the server side.

  13. yahman72 commented on Nov 21, 2016

    @yahman72
    Author

    As promised, here my findings:

    WebDriver differences (when re-attaching to a session using that webdriver.Remote(desired_capabilites={}) from the example code:

    • Firefox Driver: creates a new session, but does not create/open a new window. Reusing old session possible.
    • Chrome Driver: creates a new session, but creates/opens a new browser window. Reusing old session possible.
    • IE Driver: creates a new session, but creates/opens a new browser window. Reusing old session possible.

    The new window is opened, because the webdriver.Remote()'s __init__ calls start_session() that sends a POST to http://localhost/hub/session with that desired_capabilities={}. Firefox seems to be the only browser that does not open a new window when this happens.

    This is of course not good, i.e. we should avoid calling that start_session() because we don't want create a new session. Instead we'd need something like ReusableWebDriver that inherits from the webdriver.Remote but doesn't create a new session - and this is where it gets a bit ugly:

    • to override webdriver.Remote()'s __init__ you'd need to copy-paste it to your ReusableWebDriver __init__ and comment out the start_session() step
    • webdriver.Remote()'s __init__ hasn't changed in the past years but if it does you'd need to do that copy-paste exercise again.
    • In another words: more logical place to implement the re-use logic would be the selenium client.

    However, I made a quick-and-dirty implementation of this:

    • There's now a ReusableWebDriver that skips the session creation steps
    • Create Webdriver KW now stores the session info (session ID, command executor URL and capabilities) into a file
    • When calling Create Webdriver KW with Remote argument the ReusableWebDriver is created using the session info from the file.

    The code is in my fork i.e. https://github.com/yahman72/Selenium2Library/tree/reusable_session

    This seems to work with the browsers I have installed (FF, Chrome and IE), and I don't see any reason why it shouldn't work with all other browsers and the grid. There are, of course, some limitations e.g. with the runtime variables (as @ombre42 mentioned) that might not be "correct" on the re-execution. Thee kind of things aren't, IMHO, selenium2library's problem, but more a test-implementation planning topic that could be solved by organizing the Test development differently (like @aaltat wrote above)

    And now the big question:
    Is it worth implementing this for the selenium2library? That copy-paste exercise is pretty ugly...

    If I would implement this properly I'd probably do it like @pekkaklarck already proposed i.e.:

    • a new KW for storing the session data
    • a new KW for re-connecting to a web-driver

    This way there would not be any changes in the existing code.

  14. 7 remaining items

  15. aaltat commented on Dec 10, 2016

    @aaltat
    Contributor

    @yahman72 sorry that it takes so long to review this pull request but the release 2.0 takes lot of attention.

  16. aaltat commented on Feb 8, 2017

    @aaltat
    Contributor

    @yahman72 did you actually create a PR?

  17. axelPalmerin commented on Mar 28, 2017

    @axelPalmerin

    This is my solution:

    1. Download the modified version of wb:

    https://github.com/axelPalmerin/personal/blob/master/webdriver.py
    2. Replace on remote dir:

    /usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/
    3.Run hub and node:

    $ java -jar selenium-server-standalone-3.3.1.jar -role hub
    $ java -jar selenium-server-standalone-3.3.1.jar -role node

    1. Run the script with Remote Wb:
    
    def setBrowser(sessionId=None):
        webdriver = w.Remote(command_executor='http://localhost:5555/wd/hub',
                             desired_capabilities=DC.CHROME,
                             session_id=sessionId)
        f.writeFile(webdriver.session_id) # should use an env var.
        return webdriver
    
    if __name__ == "__main__":
        sessionId = f.readFile()
        print "sessionID ->",sessionId
        wd = setBrowser(sessionId)
        if sessionId is None:
            # your code here
        else:
          # your code here will use the same browser
    
    
    1. Run the script whit the sessionId
  18. yahman72 commented on Mar 29, 2017

    @yahman72
    Author

    @aaltat sorry, missed your comment about the PR.
    No I did not, because my expectation was that we'll have some discussions about the implementation before I finalize and submit the PR. This was not so good as this topic was now idle for some and we almost forgot it :-)
    I submitted the PR #783 - we can continue the discussion based on that. It probably needs some updates since it was forked some time ago...

  19. aaltat commented on Mar 29, 2017

    @aaltat
    Contributor

    I was trying to read your code, but because it was in multiple commits is was difficult. In PR, it's easier to have a good understanding what is changed​ in overall.

  20. yahman72 commented on Mar 30, 2017

    @yahman72
    Author

    True - just check the PR and let me know if there's something unclear.

  21. vishalekhe commented on Aug 4, 2017

    @vishalekhe

    I have used modified webdriver.py and it worked for me.

    We use robot.run() function to start the automation tests. With mentioned solution, I need to get manually the session id & url i.e. command_executor with some program and then feed it to webdriver.py. If browser closes I need to it often.

    Is there a way to pass session id and command_executor to robot.run() which will take care passing session id and command_executor to webdriver.py.

  22. sheikhsamina commented on Sep 25, 2018

    @sheikhsamina

    String userProfile= "C:\Users\user\AppData\Local\Google\Chrome\User Data\Default\";
    System.setProperty("webdriver.chrome.driver","C:\Users\user\Desktop\chromedriver.exe");
    ChromeOptions options = new ChromeOptions();
    options.addArguments("user-data-dir="+userProfile);
    options.addArguments("--start-maximized");
    WebDriver driver = new ChromeDriver(options);
    driver.get("http://www.google.com");
    The above code is working for me to save cookies and history using selenium web driver

  23. aaltat commented on May 21, 2019

    @aaltat
    Contributor

    Closing due inactivity.

  24. zeeshanyshaikh commented on Aug 31, 2020

    @zeeshanyshaikh
  25. ortizjeison commented on Oct 21, 2023

    @ortizjeison

    Hi everyone , any news about this initiative?

  26. emanlove commented on Oct 21, 2023

    @emanlove
    Member

    @ortizjeison Jeison, it is not on our radar. I'll note much of the discussion around this was before Tatu released the SeleniumLibrary plug-in API and the extending capabilities. One may be able to connect through those extension options but I really have not explore that idea. I'm hesitant to give much indication that this will became a priority or a keyword would be added. So one could explore this more but I caution about devoting too much resources if it requires some changes within the core library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions