Shahboz
Shahboz

Reputation: 546

Selenium NoSuchElementException when accessing a class variable

So, I have a class A and it has a (public static WebElement element1, element2).

public class myClass {
public static WebElement element1, element2;


public myClass(){
    WebDriver driver = new FirefoxDriver();

    this.element1 = driver.findElement(By.id("button"));
    this.element2 = driver.findElement(By.id("text"));
}
}

And then I have a test class where it has a method called @Test public void testClassA.

@Test
public void testClassA(){

    myClass m = new myClass();

    m.element1.click();

    m.element2.sendKeys("input something");

}

Questions is I am getting org.openqa.selenium.NoSuchElementException: Unable to locate element:{} error. I think my error is happening because the element2 is located in the next page, it shows up after clicking the button. What should I do in my code so that when I assign both elements to findBy method the test is going through the first click and then sendKeys to element2?

Upvotes: 1

Views: 437

Answers (3)

Manu
Manu

Reputation: 2301

The way you have written the code will break in scenarios where elements are dynamic and also on page navigation.

This is not a good practice to find the webelement in different class altogether and use the object of that class in your test class.

As you can see in code: myClass m = new myClass();, when object of myClass is created, the constructor is triggered and driver finds both the element1 and element2 at once. And, since element2 is still not displayed, it throws an exception.

I don't know what prompted you to follow this practice, instead find the webelement only when you actually need it. There seems to be many alternative and it depends on how you want to design your code.

  1. Use same class to find the element and performing action on that.
  2. Use different methods to find the webelements, instead of using constructors to find them.
  3. Use keywords for webdriver actions if you want to make things generic.
  4. Use properties file to store the locators and dat if you want.

More Standard practice(I guess so):

  1. Use Page Objects to find the webelements.
  2. Use PageFactory in addition to Page Objects.

Good Reference: http://www.guru99.com/page-object-model-pom-page-factory-in-selenium-ultimate-guide.html

Upvotes: 1

Shantanu Nandan
Shantanu Nandan

Reputation: 1462

You can use webdriver implicitwait to wait for the elements on the page to load for a certain period of time.

driver.manage().timeouts().implicitlyWait(8, TimeUnit.SECONDS);

As you can see in the above code i used 8 seconds for the elemnets on the page to load. Read more about wait in Webdriver

Use a try catch block to handle the exception.

@Test
public void testClassA(){
driver.manage().timeouts().implicitlyWait(8, TimeUnit.SECONDS);
try{
myClass m = new myClass();

m.element1.click();

m.element2.sendKeys("input something");
}catch(NoSuchElementException e){
    e.printStackTrace();
}
}

Upvotes: 1

Purus
Purus

Reputation: 5819

As you mentioned that the element2 is present in the next page, you have to wait till the new page loads. Without this wait, if you try finding the element2, it will throw an exception as the element is not found on the current page before the page change.

Solutions:

1) Add a Explicit wait after the element1 click() method. You can wait till the element2 is present after the click().

m.element1.click();

WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(By.id("text")));

m.element2.sendKeys("input something");

2) Simple but I would not recommend this. Use Thread.sleep() to wait for the new page to load.

3) Use Page Object Design Pattern.

Upvotes: 1

Related Questions