Saturday, June 22, 2024

Playwright For React.js Frontend Applications

 

Playwright Automation Testing for React.js Websites




In this blogpost, we will discuss automation testing with Playwright on React.js Frontend.   

We have taken Swag Labs website which is built on React.js JavaScript Framework.

I have written similar articles earlier on Vue.js and Angular. Please see the links below for reference:

I’ll put the post in two points:
  •  Test automation framework with Playwright
  •  Integrate automation tests with CI 


Test automation framework with Playwright: 


Overview: 
I have used Javascript for developing the automation tests. First things first, The locators are the key factor which will make Angular websites different to that of React.js and Vue.js frontends. As we know that ReactJS is a JavaScript front-end web framework which is more popular.

Coming back to our point on locators, Basically, the advantage with playwright is you can grab the locators with "text""css""id", "data-test-id", "xpath"

No matter which locator you use, Playwright will consider all of these locators into one locator like below which is a benefit in terms of code readability.

const element = this.page.locator(selector);

Your selector can be anyone from these - xpath, id, css, text, data-test-id.

Here are some locators for reference

PageObjects:
export const title = '.title'
export const cartQuantityLabel = '.cart_quantity_label'
export const cartItemLabel = '.cart_item_label'
export const cartDescriptionLabel = '.cart_desc_label'
export const cartQuantity = '.cart_quantity'
export const flecceJacketText = "//div[@class='inventory_item_desc']"
export const fleeceJacketPrice = "//div[@class='inventory_item_price']"
export const continueShoppingButton = "[data-test='continue-shopping']"
export const removeButton = "[data-test='remove-sauce-labs-fleece-jacket']"
export const checkoutButton = "[data-test='checkout']"

We are good to go with designing the test automation framework now.

The framework will be using page object design pattern for JavaScript Frontends built on React.js.

The page classes and tests remain the same across all the React.js, Vue.js and Angular applications.

Desigining of Pages: The pages are designed using page classes with extends keyword. This will be common for React.js, Vue.js and Angular applications.

Page:
import BasePage from './basePage'
import fs from 'fs'
import * as loginPageObjects from '../pageobjects/loginPage'

const testData = JSON.parse(fs.readFileSync(`./data/users.json`, `utf-8`))

class LoginPage extends BasePage {
constructor(page) {
super(page)
}

async openApp() {
await super.open()
return await super.waitForPageLoad()
}

async loginPageLogo() {
return await this.isElementVisible(loginPageObjects.loginPageLogo)
}

async loginAsStandardUser() {
await this.waitAndFill(loginPageObjects.username, testData.standard_user)
await this.waitAndFill(loginPageObjects.password, testData.password)
await this.waitAndClick(loginPageObjects.loginButton)
}
}
export default LoginPage


Test:
/* Scenario 1:
Login as a standard user to verify the products page and logout from the application

Scenario Description:
User logs into the website and verifies all the elements on the products page and logs out from the application.
This is like a Smoke test.

Test test.steps:
1. User is on the Login Page
2. Verify the Logo, title, url, username, password fields, login button, login and password credentials on the login page
3. Login as a standard user
4. User is on the Landing/Products page. Verify the Landing page logo and URL
5. Verify the PRODUCTS title and peek image visible on the home page
6. Verify all the options Burger menu item, ALL ITEMS; ABOUT; LOGOUT AND RESET APP STATE are visible on inventory sidebar links on left side of the page
7. Verify the shopping cart icon and product sort container visible on the top right of the page
8. Verify the Inventory Product item list is visible
9. Verify the footer text and swag bot footer is visible
10. Click on “About” navbar link from the “inventory sidebar panel” and check whether user is navigated to saucelabs page
11. Verify the Facebook logo visible
12. Click on Facebook social link and verify user is navigated to Facebook page
13. User logout from the application and verify the login page
*/

import test from '../testFixtures/fixture'
import { expect } from '@playwright/test'
import fs from 'fs'
import * as loginPageObjects from '../pageobjects/loginPage'
import * as productsPagePageObjects from '../pageobjects/productsPage'
import * as config from '../config'

const testData = JSON.parse(fs.readFileSync(`./data/users.json`, `utf-8`))

test.describe
.parallel('@smoke: Login as a standard user to verify the products page and logout from the application', () => {
test('Login to App as a standard user', async ({
loginPage,
productsPage
}) => {
await test.step(`Open the APP and check logo`, async () => {
await loginPage.openApp()
await loginPage.loginPageLogo()
expect(await loginPage.getTitle()).toBe(config.title)
expect(await loginPage.getUrl()).toContain(config.baseUrl)
})

await test.step(`Login as a Standard user`, async () => {
await loginPage.loginAsStandardUser()
})

await test.step(`Verify the products page sidebar links visible and click on About link to check user is navigated to saucelabs page`, async () => {
await productsPage.burgerButtonVisible()
await productsPage.burgerButtonClick()
await productsPage.allItemsSideBarLink()
await productsPage.logoutSideBarLink()
await productsPage.resetSideBarLink()
await productsPage.burgerCrossButtonVisible()
await productsPage.burgerCrossButtonClick()
})

await test.step(`Verify Inventory container and the inventory list is visible`, async () => {
await productsPage.inventoryContainerVisible()
await productsPage.backPackItem()
await productsPage.boltTshirtItem()
await productsPage.onesieItem()
await productsPage.bikeLightItem()
await productsPage.fleeceJacketItem()
await productsPage.tshirtRedItem()
})

await test.step(`Verify the footer text+swag bot footer+social channel links are visible`, async () => {
await productsPage.footerTextVisible()
await productsPage.socialChannelLinksVisible()
})

await test.step(`Standard user logout from the application and verify the login page`, async () => {
await productsPage.burgerButtonVisible()
await productsPage.burgerButtonClick()
await productsPage.clickLogoutSideBarLink()
await loginPage.loginPageLogo()
expect(await loginPage.getTitle()).toBe(config.title)
expect(await loginPage.getUrl()).toContain(config.baseUrl)
})
})

test('Click on the "About" side nav bar link to check whether user is navigated to sauce labs page', async ({
loginPage,
productsPage
}) => {
await test.step(`Verify the products page shopping cart icon and product sort container visible `, async () => {
await loginPage.openApp()
await loginPage.loginAsStandardUser()
})
})
})

test('Click on Facebook link and check whether user is navigated to Facebook page', async ({
browser
}) => {
const context = await browser.newContext()
const page = await context.newPage()

await page.goto(config.baseUrl)
await page.fill(loginPageObjects.username, testData.standard_user)
await page.fill(loginPageObjects.password, testData.password)
await page.click(loginPageObjects.loginButton)

const link = page.locator(productsPagePageObjects.facebookLink)
const [newPage] = await Promise.all([
context.waitForEvent('page'),
link.click()
])
await newPage.waitForLoadState('networkidle')
expect(await newPage.title()).toContain(config.facebookTitle)
expect(newPage.url()).toBe(config.facebookUrl)
})


This JavaScript file or test TC_01_productPage.test.js have three tests inside it and because we gave test.describe.parallel the three tests inside this file run in parallel which is a really good feature in playwright saves test execution time. 

Apparently, we can not only run two or more separate tests or files in parallel but also we can run the single javaScript file or test which is having two or more tests inside it in parallel.

Playwright Test Report:

After running the test, you can see the test report like this :


Integrate automation tests with CI: 


GitHub Actions:-
Run the tests on GitHub Actions

Create a folder .github/workflows and inside this folder create a yml file with name "playwright.yml" file as shown below



Go to GitHub Actions and check the run
 

Click on the first one



Click on test 



Click on the playwright-report to get the HTML test report



GitLab:-

I have integrated the automation tests now with GitLab CI. However, you can use any other CI tools like Jenkins, Bitbucket etc...

Basically, Create a file with name ".gitlab-ci.yml" yaml file in your VS code in the root folder.

Let's run the tests in Headless on Chrome, MS EdgeFirefox and Safari Browsers.

.gitlab-ci.yml file
stages:
- test

tests:
stage: test
image: mcr.microsoft.com/playwright:v1.44.1-jammy
script:
- npm install
- npx playwright install webkit
- npx playwright install chrome
- npx playwright install msedge
- npm run test:firefox

Change the last command in the above file accordingly, If you want to run in 
Chrome npm run test:chrome
Firefox  - npm run test:firefox
Safari    - npm run test:safari
MS Edge npm run test:edge


GitLab Pipeline runs on all the four browsers in Headless:




Link to Playwright-JavaScript Repo: Playwright-JavaScript
Link to Playwright-TypeScript Repo: Playwright-TypeScript
Link to GitLab  Repo: GitLab

Concluding on this post, Playwright supports all JavaScript Frameworks - React.js, Vue.Js and Angular !!!

Happy Automation Testing Guys :) !

Robot Framework - Frontend Test Automation Framework generated by AI

  Robot Framework with Browser Library Web Test Automation Framework Developed With The Help Of AI Search Agent. In this article, we will di...