1

I am making a Regression suite Automation project using Selenium Webdriver, Java, Cucumber, Maven etc.

Now, the problem is that I have multiple Page Object classes that I initialise again and again using PageFactory Class in almost every scenario Step Definition methods i.e. @Given, @Then, @And etc. I am getting a lot of "StaleElement Exception" ,"TimeoutException" and "Null Pointer" exception errors consistently?

Can I just initialize a PageObject class JUST ONCE and use it in all test classes, step definition methods?

I have a BaseClass that initializes the ChromeWebDriver instance and all other StepDefinitions java classes implement that BaseClass.

Cucumber project structure is something like this:


    public class BaseClass{
    
    public void setupWendriver(...)
    }
    
    public class User implements BaseClass{ // this is a stepDefinition class
    Webdriver driver;
    
    
      @AddUserProfile
      Scenario: Add a new User Profile in Users Section
        Given Navigate to Users Tab
        Then Add a new User Profile
    
    
    @Given("^Navigate to Users Tab$")
        public void Login() throws Exception {
            UserProfile user = PageFactory.initElements(BaseClass.driver, UserProfile.class);
        user.enterUserName();
        user.enterPwd();
    etc...
        }
    
        @Then("^Add a new User Profile$")
        UserProfile user = PageFactory.initElements(BaseClass.driver, UserProfile.class);
            UserProfile user = PageFactory.initElements(BaseClass.driver, UserProfile.class);
        user.addNewUser();
        user.VerifyUser();
    

Now, you can see that I have to initialize the SAME PageObject Class, i.e UserProfile in all StepDefinition methods... If I don't it and just initialize once, still I get StaleElement, NullPointer, Timeout errors... If I initialize just once per StepDef class, still I get the Error.

NOTE: I don't want to initialize every PageObject in its constructor, but want to initialize it directly.

    public UserProfile(){
    driver = BaseClass.driver;
    PageFactory.initElements(this, UserProfile.class)

      // Dont want to do this to save one extra line of code, i am not creating object of pageObject class, im directly assigning it initElements() return type...

Please help, as I can't get my code to work correctly?

2
  • 1
    What error are you getting exactly? (Stacktrace would be useful). Additionally, why do you think the repeated initialization is connected to this error? Errors such as StaleElement are usually connected to keeping the same object after the elements are not interactable anymore - not the contrary, creating new objects repeatibly would actually mitigate these errors. Aug 3, 2020 at 7:15
  • @João Farias, can you please see my answer...
    – Nick2358
    Aug 3, 2020 at 12:11

4 Answers 4

1

This may help you

TestBase.java

public class TestBase {
    public Properties prop;
    public FileInputStream file;
    public WebDriver driver;

    // Pages objects
    public HomePage homepage;
    public Dashboard dashboard;

    

    public void intialization() {
        try {
            System.setProperty("webdriver.chrome.driver",
                        new File("driverpath").getAbsolutePath());
            driver = new ChromeDriver();
            System.out.println("Started chrome in GUI mode");           
            driver.manage().timeouts().pageLoadTimeout(50, TimeUnit.SECONDS);
            driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS);
            driver.manage().window().maximize();
      driver.get("https://templatemag.com/demo/templates/Dashio/login.html");               

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Alert Site seems very slow!!!! Please increase the page load time out in util class");
            driver.close();
            System.exit(0);
        }
    }

    @BeforeTest
    public void BrowserSetup() {
        System.out.println("BeforeTest");
        intialization();
        homepage = new HomePage();
        PageFactory.initElements(driver, homepage);
        dashboard=new Dashboard();
        PageFactory.initElements(driver, dashboard);
    }
    
    
    @AfterTest
    public void TearDown() {
        driver.quit();
    }
}

Login.java

public class Login extends TestBase{
    
    
    @Test(priority=1)
    public void createissue() {
        homepage.EnterEmail("[email protected]");
        homepage.EnterPassword("password");
        homepage.PerformLogin();    
    }
    
    @Test(priority=2)
    public void Check_username() {
        System.out.println(dashboard.getdashTitle());   
    }
}

HomePage.java

public class HomePage{
    
    public Helper waithelper;
    
    @FindBy(xpath="//input[@placeholder='User ID']")
    WebElement emailid;
    
    @FindBy(xpath="//input[@placeholder='Password']")
    WebElement password;
    
    @FindBy(xpath="//button[@type='submit']")
    WebElement signin;
    
    
    public void EnterEmail(String testdata) {
        emailid.sendKeys(testdata);
    }
    
    public void EnterPassword(String testdata) {
        password.sendKeys(testdata);
    }
    
    public void PerformLogin() {
        signin.click();
    }
}

Dashboard.java

public class Dashboard{
    
    @FindBy(xpath="//ul//h5")
    WebElement dash_title;
    
    public String getdashTitle() {
        return dash_title.getText();
    }

}

Explanation

TestBase.java is the parent class for all the test class i have called annotation @BeforeTest and @AfterTest for initialization of browser.

In @BeforeTest, i have called browser initialization method and you can see PageFactory.initElements(driver, object); void method called after the Page locator class initialization this will help you to initialize pagefactory for multiple page classes into a single TestBase classes so this will give your required output.

In PageFactory.initElements(driver, object);, driver is the WebDriver object and object is the pageclass object. I have used with the testng you can follow the same with cucumber

This is working code example which you can try it

Hope this will be helpful

1

Cucumber has the facility to address the issues like yours one. It is called Object Factory. Object factory is responsible for creating objects once per scenario through the chosen injection framework.

Recommended injection framework is PicoContainer:

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-picocontainer</artifactId>
    <version>6.1.1</version>
    <scope>test</scope>
</dependency>

Here is the post about how to use it for Cucumber syntax where you mark your step definitions with annotations.

Here is the post about how to use it for Cucumber syntax where you describe your step definitions with lambda expressions.

Using mentioned approaches you will be able to inject one object per each scenario independent on whether your step definitions are described in one class or spread across different classes.

0

In some applications I have worked on it makes more sense to have the Page Objects be Global Page Objects.

Instead of each area having the specific page objects it needs - which is good for isolation. consider one single file that holds them all.

One of the questions you can ask yourself to see if this option would help - are all your page object identifiers unique already? They often are.

I have used this approach for projects with under 200 objects and it has worked well. I have also used it on similar projects which then grew larger and I needed to switch to having 'page' specific objects (possibly keeping some global ones such as login button, logout button, etc.

I don't practice the language you are using so I can't write the code for you.

1
  • thanks for your reply! MBy Global Page Objects, do you mean that i create a new .java class and initialise all the PageObject Classes at once place. Something like this.... public class PageObjectInitialiser{
    – Nick2358
    Aug 3, 2020 at 12:07
0

thanks for your reply! By Global Page Objects, do you mean that i create a new .java class and initialise all the PageObject Classes at once place. Something like this....

public class PageObjectInitialiser{
User u = PageFactory.initElements(BaseClass.driver, User.class); // PageObject
Administrator admin = PageFactory.initElements(BaseClass.driver, Administrator .class);
Entitlement rights = PageFactory.initElements(BaseClass.driver, Entitlement .class);
Reports report = PageFactory.initElements(BaseClass.driver, Reports .class);
}...

or writing the "PageFactory.initElements()....statement at the top of StepDefinition files.

1
  • This answer should really be either converted to comment or added to the original question as an edit.
    – Mate Mrše
    Oct 14, 2020 at 6:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.