User Interface(UI) Performance Testing and Automation
Many organizations consider Performance is one of the crucial feature of their product since it is also affect business. Modern Web Applications spend more time in browser then server which make UI performance is also one of the key parameter for business.
Few months ago i have started looking for tool which can measure UI Performance in terms of page rendering , FMP(First Meaningful Paint), TTI(Time to Interactive) along with easy to use, easy to code and can be part of CI(Continuous integration).
After analyzing different tools, I found Lighthouse from Google is the right tool to serve the ask.
Lighthouse
Lighthouse is an open-source, automated tool for improving the quality of web pages. You can run it against any web page. It has audits for performance, accessibility, progressive web apps, and more.It can run Lighthouse in Chrome DevTools, from the command line, or as a Node module. If you would like to learn more about Lighthouse, you can visit below link:
Lighthouse can be use with Node Module along with chrome browser. This will help us to measure performance of any web page or website. However It is not solving our problem. Still many questions are unanswered such as:
- How can we test web application where user needs to Sign In first ?
- Lighthouse is run in private browser window. How can we maintain cookies and other authentication details ?
- How can we capture performance of multiple pages where manual user interaction required such as page routing, page navigation ?
By investigating above questions, we need some kind of browser automation where we can script certain details and browser can execute it. After spending sometimes in research, I found another tool from Google called "Puppeteer".
Puppeteer
Puppeteer can do many things for us such as browser automation, form submission, Keyboard inputs, navigation within SPA etc,. If you would like to learn more about Puppeteer, you can visit below link:
If you run Puppeteer, It will also run in its private browser window.
If Lighthouse and Puppeteer are running in its own private browser window then how can we solve problem ?
So we need a chrome instance which can be shared between Puppeteer and Lighthouse. If we have shared instance then we can solve our problem. I will explain step by step to do UI performance testing in below section.
Step by Step guide for UI Performance Testing and Automation
- Step 1: Create a java script file and include below modules which are required for Performance Testing and Automation.
const puppeteer = require('puppeteer');
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
const request = require('request');
const util = require('util');
const fs = require('fs');
I have used node server and npm to install all above packages.
- Step 2: Let's create anonymous async function. We will write our script within this function
(async () => {
//TODO: scripts
})()
- Step 3: Create a constant object for Lighthouse and Chrome parameters
const opts = {
chromeFlags: ['--headless'], //We are using headless chrome
logLevel: 'info',
output: 'html', // Lighthouse report format
emulatedFormFactor: 'desktop', // Performance for desktop or mobile
disableStorageReset: true, // Option to clear cache/storage
onlyCategories: ['performance','accessibility','best-practices']
};
- Step 4: Let's launch Chrome instance using Chrome Launcher
const chrome = await chromeLauncher.launch(opts);
opts.port = chrome.port;
We will use opts.port upcoming steps to connect with Puppeteer and Lighthouse
- Step 5: In this step, we will retrieve Debug URL from chrome instance which we have launched in previous step and we will use this URL to connect with Puppeteer.
//Connect with puppeteer
const resp = await util.promisify(request)(`https://localhost:${opts.port}/json/version`);
const { webSocketDebuggerUrl } = JSON.parse(resp.body);
const browser = await puppeteer.connect(
{ browserWSEndpoint: webSocketDebuggerUrl,
slowMo: 200 //Slowdown script execution in puppeteer
});
const page = await browser.newPage()
- Step 6: We can use page object to perform browser automation and execute various actions/script such as Sign In, page navigation etc.
//Sample script. This is different from applicaiton to applications.
await page.goto('https://myserver.com');
await page.setViewport({ width: 1920, height: 1098 })
await page.type('.row > .card > #form-id > div > #login-username', 'test')
await page.type('.row > .card > #form-id > div > #login-password', 'xxx')
await page.click('.row > .card > #form-id > div > #submit_login')
- Step 7: In previous step, we have performed submit action and browser navigated us to a dashboard page. Now we need to capture performance of dashboard page using Lighthouse.
const lhrDashboard= await lighthouse('https://myserver.com/Dashboard', opts);
fs.writeFileSync('./report/dashboard.html', lhrDashboard.report);
In above step, we have launched lighthouse using our chrome Instance, capture performance details and stored same in form of HTML report
- Step 8: Let's not forget to disconnect our browser and kill chrome instance at the end of execution
await browser.disconnect();
await chrome.kill();
We can configure same in Jenkins or equivalent tools for continuous execution and automation.
Here is the sample report from Lighthouse