Selenium can't find element by XPATH or by CLASS_NAME even when it exists

Question:

I am trying to click a button on this page (The blue button) but Selenium and even the dev console return "cannot find element" or null. What am I missing?

driver.find_element(By.XPATH, "/html/body/ts-app//div/div[3]/ts-button//paper-button")

Error:

raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"/html/body/ts-app//div/div[3]/ts-button//paper-button"}

Why does this happen??

Asked By: robotmr

||

Answers:

The problem is that there are two shadow-root nodes above the button you are trying to click. You need to switch context to them, almost like an IFRAME, to be able to see inside them. The code below clicks the button.

url = "https://www.gstatic.com/cloud-site-ux/text_to_speech/text_to_speech.min.html"
driver = webdriver.Chrome()
driver.maximize_window()
driver.get(url)

shadow_host1 = driver.find_element(By.CSS_SELECTOR, "ts-app")
shadow_root1 = shadow_host1.shadow_root
shadow_host2 = shadow_root1.find_element(By.ID, "button")
shadow_root2 = shadow_host2.shadow_root
shadow_root2.find_element(By.CSS_SELECTOR, "paper-button").click()

NOTE: While I’m sure it’s easier to copy/paste the XPath using Chrome dev tools, the locators it generates are pretty terrible from a maintenance perspective. Any XPath that starts at the root /html tag, has several levels, and/or has indices are prone to break. I created new locators that are easier to read and a lot less likely to break on a minor update to the page.

Answered By: JeffC