Xpath is valid and can be found in Elements and Console, but can't be found while running an application

Viewed 200

I'm using Selenium Webdriver with ChromeDriver. Mastering my skills with XPath.

Here is the piece of code I tried to execute:

WebDriver driver;
String baseURL = "http://youtube.com";
System.setProperty("webdriver.chrome.driver", "/Users/svetlana_yatsushko/Documents/workspace/selenium/chromedriver");

driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get(baseURL);
driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
driver.findElement(By.xpath("//*[@id='dismiss-button']//descendant::yt-formatted-string[1]")).click();

I've got an error:

Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id='dismiss-button']//descendant::yt-formatted-string[1]"}

Also I tried to write other XPaths options like

  • //*[@aria-label='No, thanks']
  • //*[@id='button']//*[text()='No, thanks']

But no one works stable, though these XPaths have been found in Elements and Console and have 1 matching node.

I noticed a situation, it can be found 2 times out of 5, for example. Or sometimes it is not found 5 times in a row... Probably this is on an XPath issue, but I'm not able to get the reason.

Hopefully you had something similar and could help me.

1 Answers

When you set driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); it means that Selenium will be waiting for 30 seconds to document's property document.readyState becomes complete.

However there often could be the cases when UI is built dynamically so that it might change (some elements can be added, some can be modified or removed) after the page has been loaded.

So in the latter case there is a pattern that is supposed to use in Selenium to wait for the element - waiters (implementations of Wait interface). They can flexibly wait for element to take certain condition polling for that condition several times a period.

So this

driver.findElement(By.xpath("//*[@id='dismiss-button']//descendant::yt-formatted-string[1]")).click();

could be change to this:

Wait<WebDriver> wait = new FluentWait<>(driver)
        .pollingEvery(Duration.ofMillis(100))
        .withTimeout(Duration.ofSeconds(30));
        
wait
        .until(
                ExpectedConditions
                        .visibilityOfElementLocated(
                                By.xpath("//*[@id='dismiss-button']//descendant::yt-formatted-string[1]")
                        )
        ).click();

Here you can find some details on how FluentWait works.

Related