<-- return to main

Optimising Automated Testing with Page Object Model (POM)

There are many ways to develop a structure for your automated test scripts. One of them would be Page Object Model (POM)

POM offers a clear separation of concern on the test script, in the sense that, page-specific code such as element locators, URL navigation are contained in a file, and testing specific code such as pseudo-steps to carry out the testing scenarios are in another file.

In other words, When the developer wants to learn how to interact with the element, he can refer to the page-specific file. When the developer wants to know what is the scenario being tested, he can refer to the test file.

Basics

Consider the following example

cy.navigate("http://www.wowmydomain.com/mypages/page1/page2/login")

The test script maintainer would need to know what the pages URl means, potentially need to add the comments for it. Of course we can declare a const for it, but the multiple declaration of const variable on other variable will surely bloat the test cases.

Now consider below snippet of code, with POM concept included:

// MyPage.ts
class MyPage {
  loginUrl = "http://www.wowmydomain.com/mypages/page1/page2/login"
  otherUrl = ...
  ...
}

// test.cy.ts
let myPage = new MyPage()
cy.navigate(mypage.loginUrl)

From the test file, it is clear that the navigate is for the loginUrl, and that URL can be found easily in MyPage.ts. Developers will have an easier time to maintain the test script, as the list of navigation-able URL is listed down, and changes in the URL for the application can be easily made.

Additionally, developer can also create a new page-specific function in the file itself, to give a more descriptive function to be used in the test script.

// MyPage.ts
class MyPage {
  protected _url = {
    loginUrl: 'http://www.wowmydomain.com/mypages/page1/page2/login',
    /*otherUrl:  ... */
  }

  protected _locators = {
    websiteTitle: cy.get(/* xpath here */)
  }

  /**
   * Navigate to the login page.
   * @returns {MyPage} The instance for chaining.
   */
  navigateToLoginPage() {
    cy.navigate(this.loginUrl)
    return this
  }

  /**
   * Verify that the user is at the login page.
   */
  verifyAtLoginPage() {
    this.websiteTitle.should('equal','MySite')
  }
}

// test.cy.ts
cy.test('Login scenario', () => {
  let myPage = new MyPage()

  myPage
    .navigateToLoginPage()
    .verifyAtLoginPage()
});

With this, when looking at the test file, even you don’t have any coding experience, you will still understand what is the scenario trying to do. All the framework functions are factorised in the page-specific file.

Data Fixture, the third component

Now, lets level up and introduce the third component of the POM, Data Fixture. It is the file the contains solely the test data needed for the scenario to run. The data can be test input data, dummy GET response to be passed to the browser, expected scenario data verification and so on.

To recap, we are maintaining:

  • Test steps in one file
  • Page Interaction code in one file
  • Test data in another, own separated file.

With proper file structure, it will be easy to navigate and find what it is needed at the moment, to debug for issues such as changing test data, or checking the element selection. It will make the overall test script experience a better ones for all of us.

Adding the third file into the mix…

// myPage.json
{
  loginURL: "http://www.wowmydomain.com/mypages/page1/page2/login",
  
  siteName: "MySite"
}

// MyPage.ts
class MyPage {
  protected _url = {
    loginUrl: 'http://www.wowmydomain.com/mypages/page1/page2/login',
    /*otherUrl:  ... */
  }

  protected _locators = {
    websiteTitle: cy.get(/* xpath here */)
  }

  /**
   * Navigate to the login page.
   * @returns {MyPage} The instance for chaining.
   */
  navigateToLoginPage() {
    cy.navigate(this.loginUrl)
    return this;
  }

  /**
   * Verify that the user is at the login page.
   */
  verifyAtLoginPage() {
    this.websiteTitle.should('equal','MySite')
  }
}

// test.cy.ts
cy.test('Login scenario', () => {
  let myPage = new MyPage();

  myPage
    .navigateToLoginPage()
    .verifyAtLoginPage()
});

Conclusion

Automation test development can be easy and not be a nightmare, but only when the proper foundations are laid. Hence, with the help of POM model, it is a right step for any automation test script developer to lay the foundation.

Additionally, the model can be further modified to suit the needs and dynamics of the current team.