Java Automation Selenium findElement by xpath can't find object sometimes

I'm pretty new to Selenium and automation. I'm trying to do automation for simple health declaration form page: https://forms.office.com/Pages/ResponsePage.aspx?id=bGOiBG0y_0iT-HCYdb06qZZ8CdlEQAhOkRllU1E9dVZUMVk1VTZFWThQV1FQUTFUV0FKNkNOVldMSi4u

To get to the textfield I used xpath:

driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://forms.office.com/Pages/ResponsePage.aspx?id=bGOiBG0y_0iT-HCYdb06qZZ8CdlEQAhOkRllU1E9dVZUMVk1VTZFWThQV1FQUTFUV0FKNkNOVldMSi4u");
WebElement element = driver.findElement(By.xpath("//*[@id=\"form-container\"]/div/div/div[1]/div/div[1]/div[2]/div[2]/div[1]/div[2]/div[3]/div/div/div/input"));
element.click();
element.sendKeys("Testing");

Problem is sometime it doesn't find the element and the program crashes.

*** Element info: {Using=xpath, value=//*[@id="form-container"]/div/div/div[1]/div/div[1]/div[2]/div[2]/div[1]/div[2]/div[3]/div/div/div/input}
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
    at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:323)
    at org.openqa.selenium.remote.RemoteWebDriver.findElementByXPath(RemoteWebDriver.java:428)
    at org.openqa.selenium.By$ByXPath.findElement(By.java:353)
    at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:315)
    at automactionproj.MainActivity.hazaratBriyot(MainActivity.java:31)
    at automactionproj.MainActivity.main(MainActivity.java:23)

Process finished with exit code 1

Any suggestions?

4 answers

  • answered 2020-09-14 05:43 NarendraR

    Using absolute xpath is not a good approach. I can't see the xpath matching in your application with the xpath string you have used in your code. Try using below relative xpath:

    WebElement element = driver.findElement(By.xpath("//input[@aria-labelledby='question1-title question1-required question1-questiontype']"));
    element.sendKeys("Testing");
    

    Even you can make xpath shorter and uniquely identifiable using unique attribute e.g. //input[contains(@aria-labelledby,'question1-title')]

    No need to perform click before enter text in textbox.

  • answered 2020-09-14 05:51 Justin Lambert

    Dont try to automate google forms For multiple reasons, logging into sites like Gmail and Facebook using WebDriver is not recommended. Aside from being against the usage terms for these sites (where you risk having the account shut down), it is slow and unreliable.

    The ideal practice is to use the APIs that email providers offer, or in the case of Facebook the developer tools service which exposes an API for creating test accounts, friends, and so forth. Although using an API might seem like a bit of extra hard work, you will be paid back in speed, reliability, and stability. The API is also unlikely to change, whereas webpages and HTML locators change often and require you to update your test framework.

    Logging in to third-party sites using WebDriver at any point of your test increases the risk of your test failing because it makes your test longer. A general rule of thumb is that longer tests are more fragile and unreliable.

    WebDriver implementations that are W3C conformant also annotate the navigator object with a WebDriver property so that Denial of Service attacks can be mitigated.

  • answered 2020-09-14 12:06 Razvan

    Since that page has 5 unique input fields, to avoid html code changes and locator's stability, you can go straight with the following locator:

    (//input)[1]
    

    Where 1 is the index for the fist input field. So you can go with any value from 1-5.

  • answered 2020-09-14 20:09 DebanjanB

    To send a character sequence within the first element with placeholder as Enter your answer you can use the following based Locator Strategy:

    driver.findElement(By.xpath("//span[text()='Required']//following::div[1]/div//input[@placeholder='Enter your answer']")).sendKeys("LiorShor");
    

    Ideally, you need to induce WebDriverWait for the elementToBeClickable() and you can use the following solution:

    new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//span[text()='Required']//following::div[1]/div//input[@placeholder='Enter your answer']"))).sendKeys("LiorShor");