0

I am facing inconsistencies in Selenium execution. Last line in the code snippet I pasted below doesn't execute consistently. Sometimes it works, sometimes it throws an error saying that element is not found. Doesn't Selenium "block" for the element to appear before attempting to execute the click? I generated it using Selenium IDE. What I am missing here?

self.driver.find_element(By.CSS_SELECTOR, ".dx-ellipsis:nth-child(2)").click()
self.driver.switch_to.default_content()
self.driver.find_element(By.CSS_SELECTOR, "#PageContentPlaceHolder_TimeControlSplitter_TimeControlContent_TimesheetEntrySplitter_TimesheetDetailsMenu_DXI0_T > .dxm-contentText").click()
Jean
  • 21,665
  • 24
  • 69
  • 119
  • selenium may not find the elements if they are loaded dynamically by JS and if you search for them before they are loaded. – theoctober19th Dec 05 '20 at 16:39
  • The "blocking" you're thinking of is called an implicit wait. See the answer below talking about explicit waits. It's better convention. – DMart Dec 05 '20 at 19:33

3 Answers3

2

Selenium may not find elements if they happen to be loaded dynamically by JS and if you search for them before they are loaded.

You can try either an implicit wait or an explicit wait.

In case of implicit waiting, the docs say:

An implicit wait tells WebDriver to poll the DOM for a certain amount of time when trying to find any element (or elements) not immediately available.

You could do with something like:

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10) #wait and poll for 10 seconds

Whereas the explicit waiting means to explicitly specify the element which is to be waited for it to be available. As per the docs:

An explicit wait is a code you define to wait for a certain condition to occur before proceeding further in the code.

You can do this with something like:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")

element1 = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".dx-ellipsis:nth-child(2)")))
element1.click()

self.driver.switch_to.default_content()

element2 = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "#PageContentPlaceHolder_TimeControlSplitter_TimeControlContent_TimesheetEntrySplitter_TimesheetDetailsMenu_DXI0_T > .dxm-contentText")))
element2.click()
theoctober19th
  • 364
  • 3
  • 13
1

As you are using the line of code:

self.driver.switch_to.default_content()

Presumably you are switching Selenium's focus from a frame or iframe to the Top Level Content. Hence you need to induce WebDriverWait for the desired element to be clickable and you can use the following Locator Strategy:

self.driver.switch_to.default_content()
WebDriverWait(self.driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#PageContentPlaceHolder_TimeControlSplitter_TimeControlContent_TimesheetEntrySplitter_TimesheetDetailsMenu_DXI0_T > .dxm-contentText"))).click()

Note:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

References

You can find a couple of relevant detailed discussions in:

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
0

Wait for the element to be loaded

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".dx-ellipsis:nth-child(2)"))).click()
self.driver.switch_to.default_content()
WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#PageContentPlaceHolder_TimeControlSplitter_TimeControlContent_TimesheetEntrySplitter_TimesheetDetailsMenu_DXI0_T > .dxm-contentText"))).click()

The number is how long the driver should spend looking for the element before moving on.

coderoftheday
  • 1,987
  • 4
  • 7
  • 21