Reputation: 673
I need to wait for the presence of an element with specific text in it. I want to fetch the info from that element in the moment the element is present and has text in it. I appears sometime after submitting a form and normaly fills with info a little later. My current solution looks like this:
wait = WebDriverWait(self.driver, MAXIMUM_LOAD_TIME)
try:
wait.until(ec.presence_of_element_located((By.ID,"IdOfElement")))
wait.until(ec.text_to_be_present_in_element((By.ID, "IdOfElement"), "theText"))
data = self._extract_data()
except TimeoutException:
raise WebsiteTimeoutError(MAXIMUM_LOAD_TIME)
This runs perfectly in >99% of the cases but now it happened that i got an error on ec.text_to_be_present_in_element
.
The error was:
File "my/Path", line 436, in _scrape_quote
wait.until(ec.text_to_be_present_in_element((By.ID, "IdOfElement"), "theText"))
File "C:\Program Files (x86)\Python38-32\lib\site-packages\selenium\webdriver\support\wait.py", line 71, in until
value = method(self._driver)
File "C:\Program Files (x86)\Python38-32\lib\site-packages\selenium\webdriver\support\expected_conditions.py", line 210, in __call__
return self.text in element_text
TypeError: argument of type 'NoneType' is not iterable
Apparently the element dissapeared again. Is my assumption right? What is the best way to fix this?
Upvotes: 0
Views: 813
Reputation: 1876
If you take a look at the text_to_be_present_in_element
implementation it assume the value is never None.
def __call__(self, driver):
try:
element_text = _find_element(driver, self.locator).text
return self.text in element_text
except StaleElementReferenceException:
return False
If the value of element_text
is None (which can be sometime), it will throw you an exception
TypeError: argument of type 'NoneType' is not iterable
Now your code is a little cumbersome as you need to ensure the element is present first, then retrieve the same element to find the proper value. There is no class in the EC module that offer both at the same time. So how about implementing your class.
You can implement a class that will ensure it is present and at the same time fix the issue to handle the case of None in the text return.
class FindPresenceOfTextInElement(object):
def __init__(self, locator, text):
self.locator = locator
self.text = text
def __call__(self, driver):
try:
text = driver.find_element(*self.locator).text
return self.text in text
except (NoSuchElementException, StaleElementReferenceException, TypeError):
return False
Then your code becomes:
wait = WebDriverWait(self.driver, MAXIMUM_LOAD_TIME)
try:
wait.until(FindPresenceOfTextInElement((By.ID,"IdOfElement")))
data = self._extract_data()
except TimeoutException:
raise WebsiteTimeoutError(MAXIMUM_LOAD_TIME)
You will need the following imports:
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException
UPDATE
AS the above is the best approach, I believe, you could have work around it by adding the exception handler in the wait obj as follow:
wait = WebDriverWait(driver, 30, ignored_exceptions=(TypeError, ))
If you add the NoSuchElementException
as well, you basically added to ensure element is present too.
Upvotes: 1