I have a very complex py.test
python-selenium test setup where I create a Firefox webdriver inside a py.test
fixture. Here is some idea of what I am doing:
'driver.py':
class Driver(object):
"""
Driver class with basic wrappers around the selenium webdriver
and other convenience methods.
"""
def __init__(self, config, options):
"""Sets the driver and the config.
"""
self.remote = options.getoption("--remote")
self.headless = not options.getoption("--with-head")
if self.headless:
self.display = Display(visible=0, size=(13660, 7680))
self.display.start()
# Start the selenium webdriver
self.webdriver = fixefox_module.get_driver()
'conftest.py':
@pytest.fixture
def basedriver(config, options):
driver = driver.Driver(config, options)
yield driver
print("Debug 1")
driver.webdriver.quit()
print("Debug 2")
And when running the test I can only see Debug 1
printed out. The whole process stops at this point and does not seem to proceed. The whole selenium test is stuck at the webdriver.quit)
.
The tests, however, completed successfully...
What reasons could be for that behavior?
Addendum:
The reason why the execution hangs seems to be a popup that asks the user if he wants to leave the page because of unsaved data. That means that the documentation for the quit
method is incorrect. It states:
Quits the driver and close every associated window.
quit() : The quit() method quits the driver, closing every associated window. driver. close() : The close() method closes the currently focused window, quitting the driver if the current window is the only open window. If there are no windows open, it will error out.
The close() method is a Webdriver command that closes the browser window currently in focus. It is best to use the close() command when multiple browser tabs or windows are open. If only one window is open in the entire browser, then the close() command will quit the entire browser session.
We can stop a page loading with Selenium webdriver in Chrome browser by using the JavaScript Executor. Selenium can execute JavaScript commands with the help of the executeScript command. To stop a page loading, the command window. stop() is passed as a parameter to the executeScript method.
As far as I understood, there are basically two questions asked which I will try to answer :
- Why failure of
driver.webdriver.quit()
method call leaves the script in hang/unresponsive state instead of raising any exception ?- Why the testcase was still a pass if the script never completed it's execution cycle ?
For answering the first question I will try to explain the Selenium Architecture which will clear most of our doubts.
So how Selenium Webdriver Functions ?
Every statement or command you write using Selenium Client Library will be converted to JSON Wire Protocol over http which in turn will be passed to our browser drivers(chromedriver, geckodriver) . So basically these generated http URLs (based on REST architecture) reaches to browser drivers. Inside the browser drivers there are http servers which will internally pass the received URLs to Real Browser (as HTTP over HTTP Server) for which the appropriate response will be generated by Web Browser and sent back to Browser Drivers (as HTTP over HTTP Server) which in turn will use JSON Wire Protocol to send the response back to Selenium Client Library which will finally decide on how to proceed further based on response achieved. Please refer to attached image for more clarification :
Now coming back to the question where script is in hold we can simply conclude that our browser is still working on request received that's why no response is sent back to Browser Driver which in turn left Selenium Library quit()
function in hold i.e. waiting for the request processing completion.
So there are variety of workarounds available which we can use, among which one is already explained by Alex. But I believe there is a much better way to handle such conditions, as browser Selenium could leave us in hold/freeze state for other cases too as per my experience so I personally prefer Thread Kill Approach with Timeout as Selenium Object always runs in main() thread
. We can allocate a specific time to the main thread and can kill main() thread
if timeout session time is reached.
Now moving to the second question which is :
Why the testcase was still a pass if the script never completed it's execution cycle ?
Well I don't have much idea on how pytest
works but I do have basic idea on how test engine operates based on which I will try to answer this one.
For starters it's not at all possible for any test case to pass until the full script run is completed. Again, if your test cases are passing there could be very few possible scenarios such as :
[TestNG][4]
test engine in Java : @AfterClass, @AfterTest, @AfterGroups, @AfterMethod, @AfterSuite) meaning your test execution is completed already. So this might be the reason for tests showing up as successful completion.I am still not sure what proper cause is there for second reason. I will keep looking and update the post if came up with something.
@Alex : Can you update the question with better understanding i.e. your current test design which I can explore to find better explanation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With