A simplified version of Page Objects for your Protractor tests
Tags: protractor, testing, pageobjects, e2etesting
Published: 2021-02-19 08:44:34

## Understand what is needed in end-to-end tests for a better separation of responsibilities

When writing GUI (graphical user interface) tests, it's a good practice to separate responsibilities.

Let's see a **Protractor** test script that does not separate responsibilities very well, and then I'll explain why that is. Afterward, I'll show you how to make it better using **Page Objects**.

```js
// specs/sample.spec.js

const helper = require('protractor-helper')

describe('Messages sample app', () => {
  beforeEach(() => browser.get('https://example.com/messages'))

  it('successfully sends a message', () => {
    const thankYouHeading = element(by.className('thanks'))

    sendMessage(
      'John',
      'johndoe@example.com',
      'Hi, this is a test message'
    )

    helper.waitForElementVisibility(thankYouHeading)
  })

  function sendMessage(name, email, message) {
    const nameField = element(by.id('name'))
    const emailField = element(by.id('email'))
    const messageField = element(by.id('message'))
    const submitButton = element(by.css('button[type="submit"]'))

    helper.fillFieldWithText(nameField, name)
    helper.fillFieldWithText(emailField, email)
    helper.fillFieldWithText(messageField, message)
    helper.click(submitButton)
  }
})
```

Test files (`*.spec.js`) should describe how the application behaves in different scenarios. By looking at them, you should understand:

* What the pre-conditions for the tests are (e.g., `beforeEach(...)`)
* What actions every test performs (e.g., `sendMessage(...)`)
* And last but not least, what are the expected results for each scenario (e.g., `helper.waitForElementVisibility(thankYouHeading)`.)

Anything else from the above-list is a distraction. Test cases are specifications of the application behaviors in different situations. This is why we suffix them with `.spec`.

Going back to our existing tests, I can see at least two major distractions. They are:

* The definitions of elements
* And the `sendMessage` function

But what if we could have them on a different module, called `page` maybe?

Well, we actually can.

Simplifying, **Page Objects** are an abstraction used in **testing automation**, where we define elements that could be present on a web page, and methods (which are actions that we could perform if we were using such a web page.)

A sample **Page Object** for our previous test example could be defined as follows.

```js
// page-objects/sample.js

const helper = require('protractor-helper')

const nameField = element(by.id('name'))
const emailField = element(by.id('email'))
const messageField = element(by.id('message'))
const submitButton = element(by.css('button[type="submit"]'))
const thankYouHeading = element(by.className('thanks'))

function sendMessage(name, email, message) {
  helper.fillFieldWithText(nameField, name)
  helper.fillFieldWithText(emailField, email)
  helper.fillFieldWithText(messageField, message)
  helper.click(submitButton)
}

module.exports = {
  nameField,
  emailField,
  messageField,
  submitButton,
  thankYouHeading,
  sendMessage
}
```

Our test could then require such a page and use all of its elements and methods, as needed (see below.)

```js
// specs/sample.spec.js

const helper = require('protractor-helper')

const page = require('../page-objects/sample.js')

describe('Messages sample app', () => {
  beforeEach(() => browser.get('https://example.com/messages'))

  it('successfully sends a message', () => {
    page.sendMessage(
      'John',
      'johndoe@example.com',
      'Hi, this is a test message'
    )

    helper.waitForElementVisibility(page.thankYouHeading)
  })
})
```

Now, the test is mostly concerned with exactly what it should be doing, which is **testing**! On the other hand, the **Page Object** deals with locating elements and defining ways of interacting with them (functions).

This way, we're now better at separating responsibilities, and our test suite is easier to maintain.

___

This post was translated to Portuguese, and you can find it on the [**Talking About Testing**](https://talkingabouttesting.com/2021/02/19/uma-versao-simplificada-de-page-objects-para-testes-escritos-com-protractor/) blog.