2

I have a test suite that currently runs across different development environments. Recently a complete rewrite of the application was done & deployed to a new environment.

The application looks & acts almost identically. Page logic is more or less the same. The big difference is the HTML rewrite has rendered my locators useless. I am unsure how to deal with the locators for this new environment while at the same time adhering to the page object model.

The page object model states that all page logic should be kept in the respective page object class. I am assuming that this includes locators as well.

Following this strategy would leave me with a bloated page object class full of duplicate locators. Is there any recommended best practices or clean solutions to combat this problem ?

The possible solutions i can think of are:

  • Create separate locator files for each environment and remove them from the page object class.
  • Create duplicate or similarly named locators in the current page object class
  • Create separate page objects for the new environment

Can anybody comment on whether or not these solutions sound ok ? Or offer any alternative suggestions ?

1 Answer 1

2

The create separate page objects for the new environment can work well if you use polymorphism appropriately.

I would suggest understanding Dave Farley's DSL + Protocol Driver architecture (short video here and long webinar here).

Basically your tests shouldn't know about the details of your page objects, just their behaviors. So...

(Pseudo-code)

loginTest() {

   loginPage = LoginPageFactory.makePage();
   loginPage.login(new Credentials(username, password));
   assertIsOnHomePage();
}

Let's leave the factory definition for later. Now you can define the different behaviors of a generic login page:

abstract class LoginPage {
  fun login(credentials) {
     getUsernameField().sendKeys(credentials.username));
     getPasswordField().sendKeys(credentials.password));
     getLoginButton().click();
  }
  abstract getUsernameField();
  abstract getPasswordField();
  abstract getLoginButton();
}

Now you define the behaviors of the new login page:

class NewLoginPage extends LoginPage {
    fun getUsernameField() {
        return find(LOCATOR_FOR_USER_NAME_FIELD_IN_THE_NEW_LOGIN_PAGE);
    }
    // So on for the other functions

}

Whereas you can have the behavior of the old page as well...

class OldLoginPage extends LoginPage {
    fun getUsernameField() {
        return find(LOCATOR_FOR_USER_NAME_FIELD_IN_THE_OLD_LOGIN_PAGE);
    }
    // So on for the other functions

}

And now, in the factory, you decide which page object to inject in your tests:

class LoginPageFactory {
   fun makePage() {
      if(enviorment.getEnv() == "Old") return new OldLoginPage();
      if(enviorment.getEnv() == "New") return new NewLoginPage();
      // so on and so forth
   }
}

This way you have only one point to change if you need to change:

  • The behavior of your tests;

  • The behavior of a generic login page;

  • The behavior specifically of the new or the old login pages

  • The types of login pages you can have

2

Your Answer

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

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