Webdriver can't find element by locator set as variable in another class

Viewed 877

I wrote automated tests with help of JUnit, Selenium Webdriver (v. 3.141.59) and Chromedriver (v. 2.45).

Firstly, I wrote a login test:

[...]
void loginTest() {
    driver().findElement(By.id("login-button")).click();
    driver().findElement(By.id("name")).sendKeys("mail@xx.com");
    driver().findElement(By.id("password")).sendKeys("password");
    driver().findElement(By.id("send")).click();
    assertTrue(driver().findElement(By.id("logged-in-msg")).isDisplayed());
}

Everything worked fine, all good, test green.

Then I got some more and more complicated and long ids and xpaths I had to use, so I decided to keep tests short and nice and put all my locators in separate class, like this:

public class LocatorsList {
public static final String
        SIGN_IN_BUTTON = "login-button",
        LOG_IN_USERNAME = "name",
        LOG_IN_PASSWORD = "password",
        LOG_IN_BUTTON = "send",
        SUCCESS_MSG = "logged-in-msg";
}

And my test:

[...]
void loginTest() {
    driver().findElement(By.id(SIGN_IN_BUTTON)).click();
    driver().findElement(By.id(LOG_IN_USERNAME)).sendKeys("mail@xx.com");
    driver().findElement(By.id(LOG_IN_PASSWORD)).sendKeys("password");
    driver().findElement(By.id(LOG_IN_BUTTON)).click();
    assertTrue(driver().findElement(By.id(SUCCESS_MSG)).isDisplayed());
}

Then it stopped working. Webdriver sends errors:

org.openqa.selenium.NoSuchElementException: no such element: 
Unable to locate element: {"method":"id","selector":"name"}

As I watched my test going, this element was right there on the page, webdriver even clicked at it as if it wanted to fill the field... but it didn't. Says 'unable to locate element'. I tried to change chromedriver and selenium versions but it didn't help.

2 Answers

This is most probably due to element not present, you need to wait for the element to be loaded. Use

WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.presenceOfElementLocated((By.id(LOG_IN_USERNAME))));

After that you can perform the action on that particular element say sendKeys event.

public class Testing {

    public static final String 
    SIGN_IN_BUTTON = "jsid-login-button",
    LOG_IN_USERNAME = "login-email-name",
    LOG_IN_PASSWORD = "login-email-password",
    LOG_IN_BUTTON = "input[type='submit']";

    WebDriver driver;

    @BeforeMethod
    public void setUp() {
        System.setProperty("webdriver.chrome.driver", <driverLocation>);
        driver = new ChromeDriver();
        driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
        driver.get("https://9gag.com/");
    }

    @Test
    public void demoTest() {
        driver.findElement(By.id(SIGN_IN_BUTTON)).click();
        WebDriverWait wait = new WebDriverWait(driver, 20);
        wait.until(ExpectedConditions.presenceOfElementLocated((By.id(LOG_IN_USERNAME))));
        driver.findElement(By.id(LOG_IN_USERNAME)).sendKeys(<YOUR_EMAIL>);
        driver.findElement(By.id(LOG_IN_PASSWORD)).sendKeys(<YOUR_PASSWORD>);
        driver.findElement(By.cssSelector(LOG_IN_BUTTON)).click();
    }

    @AfterMethod
    public void tearDown() {
        driver.quit();
    }

}

If that's honestly the only real change to the code, then could it be as simple as you missing the class name before the string? I.e:

driver().findElement(By.id(LocatorsList.SIGN_IN_BUTTON)).click()

Related