Skip to content

Commit

Permalink
Merge pull request #1262 from grafana/add-pom-example
Browse files Browse the repository at this point in the history
add page object model example
  • Loading branch information
mdcruz authored Jul 21, 2023
2 parents 79b7fee + bedd91d commit 1a3e006
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ In k6, you can import three different kinds of modules:
k6 provides many built-in modules for core functionalities.
For example, the `http` client make requests against the
system under test.
For the full list of built-in modules, refer to the [the API documentation](/javascript-api).
For the full list of built-in modules, refer to the [API documentation](/javascript-api).

```javascript
import http from 'k6/http';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export default function () {
tagWithCurrentStageIndex();

// all the requests will have a `stage` tag
// with its value equal to the the index of the stage
// with its value equal to the index of the stage
http.get('https://test.k6.io'); // e.g. {stage: "1"}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function () {
<Blockquote mod="note" title="">

With [`gracefulRampDown`](/using-k6/scenarios/concepts/graceful-stop/#the-gracefulrampdown) set to 0 seconds, some iterations might be
interrupted during the rampdown stage.
interrupted during the ramp down stage.

</Blockquote>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: 'Examples'
excerpt: 'A list of different examples and recommended practices when working with the k6 browser module'
---

This section presents some examples and recommended practices when working with the `k6 browser` module to leverage browser automation as part of your k6 tests.

- [Page object model pattern](/using-k6-browser/examples/page-object-model)


Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
title: 'Page object model'
heading: 'Page object model with k6 browser'
head_title: 'Page object model with k6 browser'
excerpt: 'An example on how to implement page object model design pattern with k6 browser'
---

When working with large test suites, a popular design pattern to improve your code’s maintainability and readability is the [page object model](https://martinfowler.com/bliki/PageObject.html).

A page object commonly represents an HTML page or significant elements/components within a page, such as a header or a footer. It is a form of encapsulation that hides the details of the UI structure from other places, such as your test files. Through page object models, any changes you need to make on a specific page or element within a page are constrained into a single place, resulting in ease of maintenance and avoiding code duplication.

Since k6 browser aims to provide rough compatibility with the Playwright API, you can leverage any existing page objects you have and easily re-use them with your k6 browser tests.

## Implementation

Let's take an example of a website with a booking form added to the homepage. Imagine you want to write a test that checks that a user can fill out the booking form successfully.

To model a page object for the homepage, we've created a page object class called `homepage.js`. Different locators are created inside the constructor so that when the homepage class is instantiated, the page locator elements are ready to be used.

The `homepage.js` class also contains different methods for:
- Navigating to the homepage
- Submitting the form
- Getting the verification message

When locators need to be updated or other specific changes related to the homepage are made, you only need to update the `homepage.js` class.

<CodeGroup labels={["homepage.js"]} lineNumbers={[true]}>

```javascript
import { bookingData } from '../data/booking-data.js'

export class Homepage {
constructor(page) {
this.page = page
this.nameField = page.locator('[data-testid="ContactName"]')
this.emailField = page.locator('[data-testid="ContactEmail"]')
this.phoneField = page.locator('[data-testid="ContactPhone"]');
this.subjectField = page.locator('[data-testid="ContactSubject"]');
this.descField = page.locator('[data-testid="ContactDescription"]');
this.submitButton = page.locator('#submitContact');
this.verificationMessage = page.locator('.row.contact h2')
}

async goto() {
await this.page.goto('https://myexamplewebsite/')
}

async submitForm() {
const { name, email, phone, subject, description } = bookingData

this.nameField.type(name)
this.emailField.type(email)
this.phoneField.type(phone)
this.subjectField.type(subject)
this.descField.type(description)
await this.submitButton.click()
}

getVerificationMessage() {
return this.verificationMessage.innerText()
}
}
```

</CodeGroup>

You can import the `Homepage` class within your test class and invoke the methods you need. This makes the code easier to understand and enforces the separation between your test and business logic.

<CodeGroup labels={["booking-test.js"]} lineNumbers={[true]}>

```javascript
import { chromium } from 'k6/experimental/browser'
import { expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.0/index.js'

import { Homepage } from '../pages/homepage.js'
import { bookingData } from '../data/booking-data.js'

export default async function () {
const browser = chromium.launch()
const page = browser.newPage()

const { name } = bookingData

const homepage = new Homepage(page)
await homepage.goto()
await homepage.submitForm()

expect(homepage.getVerificationMessage()).to.contain(name)

page.close()
browser.close()
}
```

</CodeGroup>

0 comments on commit 1a3e006

Please sign in to comment.