I'm having a lot of troubles to find a clean and reliable way to wait in my Python Selenium tests. I've been using Implicit wait for a long time and for some reason it started being unstable so I switched to explicit wait. For some reason, I can't figure out a way for my tests to work 100% of the time. Right now, even though the code being tested and the test itself does not change, problems are happening again and again. (I'd say it works 50% of the time). When problems are happening, it's usually and the same lines. Here are some of them :
for th in td_list:
if(th.text == "18"):
th.click()
break
time.sleep(3)
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.ID, "closeModalDisplayBill"))
)
Here the "closeModalDisplayBill" is a button that has to be pushed. The problem it raises is the following :
Traceback (most recent call last):
File "./scripts/test-sl/SeleniumTest.py", line 54, in test_selenium_launcher
frontAdminErr = SlFrontAdminErr(driver, self.add)
File "/Users/JNEB/WebstormProjects/backend/backend/scripts/test-sl/SlFrontAdminErr.py", line 45, in __init__
driver.find_element_by_id("closeModalAddComp").click()
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 78, in click
self._execute(Command.CLICK_ELEMENT)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 499, in _execute
return self._parent.execute(command, params)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 297, in execute
self.error_handler.check_response(response)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 194, in check_response
raise exception_class(message, screen, stacktrace)
ElementNotInteractableException: Message:
Another place where problems are recurrent is when Selenium try to open a modal to edit some stuff (clicking or clearing inputs is pretty unstable). Here is the code :
time.sleep(5)
driver.implicitly_wait(15)
driver.find_element_by_id("btnLogin").click()
time.sleep(1)
driver.find_element_by_id("login-email").clear()
And here is the log when the bug happen (trying to clear the login-email input field) :
Traceback (most recent call last):
File "./scripts/test-sl/SeleniumTest.py", line 39, in test_selenium_launcher
frontUserTest = SlFrontUser(self, driver, self.add)
File "/Users/JNEB/WebstormProjects/backend/backend/scripts/test-sl/SlFrontUser.py", line 21, in __init__
driver.find_element_by_id("login-email").clear()
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 93, in clear
self._execute(Command.CLEAR_ELEMENT)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 499, in _execute
return self._parent.execute(command, params)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 297, in execute
self.error_handler.check_response(response)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 194, in check_response
raise exception_class(message, screen, stacktrace)
InvalidElementStateException: Message: Element is not currently interactable and may not be manipulated
The same test can be successful four or five times in a row and then bug the same amount of time. (Everything here is tested from my own computer). When those tests are done through Jenkins it gets worse. Some of the time the full suite of test can be done in 10 or 8 minutes, but some of the time thoses tests will be done/failing after 30 minutes. I figure that the slow factor on Jenkins can be one of the reason my tests are unstable, but that doesn't explain why those bug appear regularly on my own computer.
All those tests are launched from another Python Script that initiate the firefox driver instance and then launch all the tests like such :
class SeleniumTestLauncher(unittest.TestCase):
environmnent = "envName"
add = ""
quickbooks_url = "https://developer.intuit.com/"
port = ""
driver = webdriver.Firefox()
base_url = ""
def setUpAdd(self):
self.driver.implicitly_wait(30)
self.verificationErrors = []
self.accept_next_alert = True
def test_selenium_launcher(self):
driver = self.driver
### -- Here just call every selenium test -- ###
## -- Test Front User -- ##
frontUserTest = SlFrontUser(self, driver, self.add)
SECOND EDIT : As suggested I removed all the implicitly_wait() for explicit_wait. Seems a bit more stable but I still encounters bugs. For instance :
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.ID, "closeModalDisplayBill"))
)
driver.find_element_by_id("closeModalDisplayBill").click()
Even though the driver should wait for 'closeModalDisplayBill' to be clickable to actually attempt to click, I get this error :
Traceback (most recent call last):
File "./scripts/test-sl/SeleniumTest.py", line 53, in test_selenium_launcher
frontUserTest = SlFrontUser(self, driver, self.add)
File "/Users/JNEB/WebstormProjects/backend/backend/scripts/test-sl/SlFrontUser.py", line 37, in __init__
driver.find_element_by_id("closeModalDisplayBill").click()
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 78, in click
self._execute(Command.CLICK_ELEMENT)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 499, in _execute
return self._parent.execute(command, params)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 297, in execute
self.error_handler.check_response(response)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 194, in check_response
raise exception_class(message, screen, stacktrace)
ElementNotInteractableException: Message:
EDIT 3 : Using only explicit wait is as unstable as before. Most of the errors I run into are those : "InvalidElementStateException: Message: Element is not currently interactable and may not be manipulated". I don't understand why Selenium tries to click on the "input field" even though I use an explicit_wait. For instance :
time.sleep(3)
element = WebDriverWait(driver, 20).until(
EC.presence_of_element_located((By.ID, "login-email"))
)
driver.find_element_by_id("login-email").clear()
Here I ask selenium to wait for 'login-email' to be present, and if it is, to click on it. The wait returns before the 20 seconds timeout but the .clear() function throw a "InvalidElementStateException: Message: Element is not currently interactable and may not be manipulated".