Improve maintainability in Playwright scripts with test data JSON

Thara Perera
3 min readMay 14, 2023

--

After my first article about How to apply Playwright Fixtures with Page Object Model I thought of sharing another technique I tried with Playwright today. Before jumping into practical examples let’s discuss the theory behind this. So what comes to your mind when you hear the word maintainability ? Here is my explanation: I think it is a mandatory aspect we should consider in any test automation solution because as software changes, so do the tests. Maintaining test automation scripts that are poorly designed or implemented can be time-consuming and expensive, and can cause tests to fail, leading to false positives or negatives.

There are many best practices to follow in many phases to create maintainable test automation solutions but today we are going to discuss about test data management aspect.

Think about a login scenario which will be the first case you try to automate in any given context web or mobile. In this example we need a username and password to login and after we have logged in we need to validate the logged in user details. Lets see how we can implement this practically using test data JSON.

Create JSON with your test data

We are going to keep our test data in a separate JSON file For that you need to have basic knowledge of JSON. In the example below I have one data object for a user with username, password, name and role as properties.

//TestData.json
{
"user": {
"username": "JackG",
"password": "jack@123",
"name": "Jack Gomez",
"role": "Customer"
},
"financialDetails": {
"totalBalance": 350,
"creditAvailable": 17800,
"dueToday": 180
}
}

Read test data from JSON in test cases

In test cases you need to import TestData.json as below. Here we use JSON.stringify() to serialize the JSON data into a string and JSON.parse() to parse the serialized string back into a JavaScript object.

Now you can call your test data in your scripts with the correct JSON path. If you examine the below example thoroughly you can see I have read JSON data in 2 ways. One is where I have specified the exact JSON property and in the other way I have passed the whole JSON object. This depends on how you want to access your test data.

//login.spec.js
const { test } = require('../base/base.js');
const testData = JSON.parse(JSON.stringify(require('../test-data/TestData.json')));

test.describe('Login Test Suite', () => {

test('Logint with valid credentials', async ({ loginPage }) => {
await loginPage.GotoLoginPage();
await loginPage.Login(testData.user.username, testData.user.password);
await loginPage.AssertLoggedInUserDetails(testData.user);
});

test.afterAll(async ({ page }) => {
await page.close();
});

});

Passing test data into pages in POM(Page Object Model)

In below code example you can see how I have accessed the test data in two different scenarios.

  1. Exact JSON property is sent through test script so I can access it directly (ex. : Login function).
  2. JSON object is sent through test script so I had to build JSON path to access the values (ex. : AssertLoggedInUserDetails function).
//LoginPage.js
const { expect } = require('@playwright/test');

exports.LoginPage = class LoginPage {

constructor(page) {
this.page = page;
this.txtUsername = page.getByPlaceholder('Enter your username');
this.txtPassword = page.getByPlaceholder('Enter your password');
this.btnSignIn = page.getByRole('link', { name: 'Sign in' });
this.lblName = page.locator(`//div[@class='logged-user-name']`);
this.lblRole = page.locator(`//div[@class='logged-user-role']`);
}
async GotoLoginPage() {
await this.page.goto('https://demo.applitools.com/index.html');
}
async Login(username, password) {
await expect.soft(this.lblLoginFrom).toBeVisible();
await this.txtUsername.fill(username);
await this.txtPassword.fill(password);
await this.btnSignIn.click();
await expect.soft(this.btnSignIn).toBeHidden();
}
async AssertLoggedInUserDetails(userDetails) {
await expect(this.lblName).toContainText(userDetails.name);
await expect(this.lblRole).toContainText(userDetails.role);
}
}

Background was made for me to try out this kind of solution due to the application behavior I used to automate. It was driven by data where we assume we know the correct values and we need to make sure those are appearing in application. So this is how I tried to keep my test data separate from test scripts so whenever test data is changed I only have to change TestData.json and relevant test scripts will fetch updated test data from there on. Another benefit in this approach is we can maintain TestData.json for each environment we need to run our automation.

I’m sharing one of my github project where I tried above concept : https://github.com/Thara90/Playwright_POM

Please feel free share your thoughts in comments below.

Have a good day !!

--

--

Thara Perera

QA professional with 8+ years of industry experience with interest in test automation.