Why doesn't python-selenium-webdriver "quit" go away?

I have a very complicated test setup of python-selenium py.test , where I create a Firefox web editor inside the py.test tool. Here are some ideas on what I'm 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 . The whole process stops at this stage and does not seem to continue. All selenium test stuck on webdriver.quit) .

The tests, however, were successfully completed ...

What reasons can there be for this behavior?

Addendum:

The reason for the execution to freeze is a popup that asks the user if he wants to leave the page due to unsaved data. This means that the documentation for the quit method is incorrect. It states:

 Quits the driver and close every associated window. 
+8
source share
6 answers

This is a non-trivial problem with which selenium is really controversial. The quit method should, as documented, just close the browser windows, but it is not. Instead, you get a pop-up window asking the user if he wants to leave the page:

enter image description here

The worst part is that this popup only appears after the user

 driver.quit() 

One way to fix this is to set the following profile for the driver.

 from selenium import webdriver profile = webdriver.FirefoxProfile() # other settings here profile.set_preference("dom.disable_beforeunload", True) driver = webdriver.Firefox(firefox_profile = profile) 
+6
source

The default close warning is true by default in firefox, as you can see in about:config , and you can disable them for your profile:

Firefox config

And since

The reason the execution freezes seems to be a popup that asks if it wants to leave the page due to unsaved data.

You can install browser.tabs.warnOnClose in your Firefox configuration profile as follows:

 from selenium import webdriver profile = webdriver.FirefoxProfile() profile.set_preference("browser.tabs.warnOnClose", False) driver = webdriver.Firefox(firefox_profile = profile) 

You can look at the profile.DEFAULT_PREFERENCES , which is json in python/site-packages/selenium/webdriver/firefox/webdriver_prefs.json

Default settings

+3
source

So, I was able to reproduce your problem using the sample HTML file below

 <html> <body> Please enter a value for me: <input name="name" > <script> window.onbeforeunload = function(e) { return 'Dialog text here.'; }; </script> <h2>ask questions on exit</h2> </body> </html> 

Then I ran a sample script that reproduces the hang

 from selenium import webdriver driver = webdriver.Firefox() driver.get("http://localhost:8090/index.html") driver.find_element_by_name("name").send_keys("Tarun") driver.quit() 

This will hang selenium python indefinitely. Which is not so good. The problem is that window.onload and window.onbeforeunload for Selenium are tough to handle due to the life cycle when this happens. onload occurs even before selenium has entered its own code to suppress alert and confirm for processing. I am sure that onbeforeunload also does not reach selenium.

So, there are several ways to get around.

Change application

Ask developers not to use onload or onbeforeunload . Will they listen? Not sure

Disable preload in profile

This is what you already posted in your answer

 from selenium import webdriver profile = webdriver.FirefoxProfile() # other settings here profile.set_preference("dom.disable_beforeunload", True) driver = webdriver.Firefox(firefox_profile = profile) 

Disable events through code

 try: driver.execute_script("window.onunload = null; window.onbeforeunload=null") finally: pass driver.quit() 

This will only work if you do not have several tabs that can be opened or the tab assumes that the popup is in focus. But this is a good general way to deal with this situation.

Do not allow selenium

Well, the reason selenium is because it sends a geckodriver request, which then sends it to firefox, and one of them just doesn't respond, as they wait for the user to close the dialog. But the problem is that the Selenium python driver does not set the timeout for this part of the connection.

To solve the problem, it is as simple as adding two lines of code below

 import socket socket.setdefaulttimeout(10) try: driver.quit() finally: # Set to something higher you want socket.setdefaulttimeout(60) 

But the problem with this approach is that the driver / browser will not be closed anyway. Here you need an even more robust approach to kill the browser, as described below.

In Python, how to check if Selenium WebDriver has left or not?

Code at the top of the link to complete the response

 from selenium import webdriver import psutil driver = webdriver.Firefox() driver.get("http://tarunlalwani.com") driver_process = psutil.Process(driver.service.process.pid) if driver_process.is_running(): print ("driver is running") firefox_process = driver_process.children() if firefox_process: firefox_process = firefox_process[0] if firefox_process.is_running(): print("Firefox is still running, we can quit") driver.quit() else: print("Firefox is dead, can't quit. Let kill the driver") firefox_process.kill() else: print("driver has died") 
+1
source

As I understand it, basically there are two questions that I will try to answer:

  • Why driver.webdriver.quit() failure of calling the driver.webdriver.quit() method leave the script in a frozen / unresponsive state, and not when any exceptions fail?
  • Why did the test file still pass if the script never completed the execution loop?

To answer the first question, I will try to explain Selenium Architecture , which will eliminate most of our doubts.

So how does the Selenium Webdriver function work?

Each operator or command that you write using the Selenium Client Library will be converted to JSON Wire Protocol via http, in turn, will be transmitted to our browser drivers (chromedriver, geckodriver). So basically these generated http ( REST- based) URLs reach the browser drivers. Inside the browser drivers there are HTTP servers that will internally transfer the received URLs to the Real browser (like HTTP via the HTTP server), for which the corresponding response will be created by the web browser and sent back to the Browser Drivers (like HTTP via the HTTP server ), which in turn will use the JSON Wire Protocol to send a response to the Selenium Client Library , which will finally decide how to proceed depending on the response. See attached image for details.

enter image description here

Now, returning to the question of where the script is on hold, we can simply conclude that our browser is still working on demand, so why the answer is not sent back to the Browser Driver , which, in turn, is the Selenium quit() Library quit() in standby mode, i.e. awaits completion of request processing.

Thus, there are many workarounds that we can use, among which Alex is already explained. But I believe that there is a much better way to deal with such conditions, since the Selenium browser can leave us in a hold / freeze state for other cases, too, in my experience, so I personally prefer the approach to destroying a thread with a timeout , since the Selenium object always works in main() thread . We can allocate a specific time for the main thread and we can kill main() thread if the timeout session time is reached.

Now we turn to the second question, which is:

Why did the test file still pass if the script never completed the execution loop?

Well, I don't have a big idea on how pytest works, but I have a basic idea on how the test engine works, based on which I will try to answer this question.

First, for any test case, this is not possible until the script is fully run. Again, if your test cases pass, there may be very few possible scenarios, such as:

  • Your testing methods have never used a method that leaves all execution in a freeze / freeze state.
  • You must have called the method inside the stall test environment (wrt [TestNG][4] in Java: @AfterClass, @AfterTest, @AfterGroups, @AfterMethod, @AfterSuite), which means that the test has completed. Therefore, this may be the reason that the tests show success.

I'm still not sure what the reason is for the second reason. I will continue to search and update the message if something comes up.

@Alex : Can you update the question with a better understanding, i.e. Your current test design, which I can research to find the best explanation.

0
source

The best way to ensure that you run your teardown code in pytest is to define a finalizer function and add it as a finalizer to this tool. This ensures that even if something fails before the yield command, you still get a break.

To avoid a pop-up that hangs when it breaks, invest in some WebdriverWait.until commands to wait time whenever you want. A popup window appears, the test cannot continue, timeout, a call is called.

0
source

For ChromeDriver users:

 options = Options() options.add_argument('no-sandbox') driver.close() driver.quit() 

loans for ... https://bugs.chromium.org/p/chromedriver/issues/detail?id=1135

0
source

Source: https://habr.com/ru/post/1275256/


All Articles