Open source

Page object model

When working with large test suites, a popular design pattern to improve your code’s maintainability and readability is the page object model.

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.


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.

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

export class Homepage {
  constructor(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(' h2');

  async goto() {

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


  async getVerificationMessage() {
    return this.verificationMessage.innerText();

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.

import { browser } from 'k6/browser';
import { expect } from '';

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

export default async function () {
  const page = await browser.newPage();

  const { name } = bookingData;

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

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

  await page.close();