Performance Testing Authenticated Pages with Lighthouse
This is a continuation of the performance testing series that I have been adding to.
This will be a quick post covering how to run automated
- Lighthouse tests on the command line
- Lighthouse tests against a performance budget
- Running Lighthouse tests for authenticated pages
1) Running Lighthouse Tests via the CLI
Setup
For this example, you will need
- Yarn
- Node 13.12.0
First create a project
mkdir <project-name>
cd <project-name>
If you are using asdf
asdf install nodejs 13.12.0echo v13.12.0 > .tool-versions
Then add lighthouse
as a dependency
yarn global add lighthouse
Next, test this out against a URL
lighthouse <url>
There should be a HTML file listed e.g. www.theguardian.com.au_2020-12-13_17-32-36.report.html
If you open the file in your browser, you’ll see something like this
I won’t go into detail about each metric listed. Refer to
- https://web.dev/performance-scoring/
- Previous writeup: https://medium.com/@clairettran/a-quick-guide-how-to-measure-your-site-performance-d0c1a4d9bae8
JSON results
You also have the option of outputting the test results into a JSON file and in headless mode. Next run
lighthouse <url> --quiet --chrome-flags="--headless" --output json --output html
You’ll see the results
The JSON file will contain the same information, for example speed index
"speed-index": {
"id": "speed-index",
"title": "Speed Index",
"description": "Speed Index shows how quickly the contents of a page are visibly populated. [Learn more](https://web.dev/speed-index/).",
"score": 0.03,
"scoreDisplayMode": "numeric",
"numericValue": 12599.883495028384,
"numericUnit": "millisecond",
"displayValue": "12.6 s"
}
2) Running against a performance budget
Next define a budget
touch budget.json
Contents:
[
{
"path": "/*",
"timings": [
{
"metric": "interactive",
"budget": 3000
},
{
"metric": "first-meaningful-paint",
"budget": 1000
}
]
}
]
Then run on the command line with an additional option
--budget-path=./budget.json
Example:
lighthouse <url> --quiet --chrome-flags="--headless" --output json --output html --budget-path=./budget.json
You will see a new HTML and JSON result file, with budget results
Example:
"timing-budget": {
"id": "timing-budget",
"title": "Timing budget",
"description": "Set a timing budget to help you keep an eye on the performance of your site. Performant sites load fast and respond to user input events quickly. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/budgets).",
"score": null,
"scoreDisplayMode": "informative",
"details": {
"type": "table",
"headings": [
{
"key": "label",
"itemType": "text",
"text": "Metric"
},
{
"key": "measurement",
"itemType": "ms",
"text": "Measurement"
},
{
"key": "overBudget",
"itemType": "ms",
"text": "Over Budget"
}
],
"items": [
{
"metric": "interactive",
"label": "Time to Interactive",
"measurement": 18110,
"overBudget": 15110
},
{
"metric": "first-meaningful-paint",
"label": "First Meaningful Paint",
"measurement": 5030,
"overBudget": 4030
}
]
}
},
The above scenarios work against public pages, however there will be times when you want to test against authenticated pages.
3) Authenticated Pages
There are a few mechanisms to test against authenticated pages (see: https://github.com/GoogleChrome/lighthouse/blob/master/docs/authenticated-pages.md).
The below example will use Puppeteer in conjunction with Lighthouse to test authenticated pages.
First, add Puppeteer to your dependencies
yarn add puppeteer
Then create a new file that will run tests e.g. auth.js
const fs = require('fs');
const puppeteer = require('puppeteer');
const lighthouse = require('lighthouse');const PORT = 8041;//to be filled in or as an environment variable
const EMAIL = ''
const PASSWORD = ''
const LOGINURL = ''
const TARGETURL = ''
Then add a function to login
async function login(browser, origin) {
const page = await browser.newPage();
await page.goto(origin); await page.waitForSelector('input[type="email"]', {visible: true});
const emailInput = await page.$('input[type="email"]');
await emailInput.type(EMAIL);
const passwordInput = await page.$('input[type="password"]');
await passwordInput.type(PASSWORD); await Promise.all([
page.click('#submit'),
page.waitForNavigation(),
]); await page.close();
}
Then create a function that will run puppeteer and lighthouse
async function main() {
const browser = await puppeteer.launch({
args: [`--remote-debugging-port=${PORT}`],
headless: false, //can be set to true
slowMo: 50,
}); await login(browser, LOGINURL);
const url = TARGETURL;
const options = {port: PORT, disableStorageReset: true, output: 'html'} const result = await lighthouse(url, options);
await browser.close(); const reportHtml = result.report;
fs.writeFileSync('report.html', reportHtml);
}
Then after that invoke the main function and export other functions
if (require.main === module) {
try{
main();
} catch(e) {
console.log(e);
}
} else {
module.exports = {
login,
logout,
};
}
Next run this file on the command line
node auth.js
You should see the output
What happens next?
Here are a few options, for what you can do
- CI: You can setup automated tests to run in your build pipeline or as part of a nightly performance test.
- Reporting: The result files can be parsed into reports which can be used to track trends in performance
- Dashboards: The results can be pushed to a dashboard e.g. Grafana backed by a DB
I’m sure there are other uses which could fit your use case :)
Resources
- Lighthouse docs: https://github.com/GoogleChrome/lighthouse
- Performance Scoring: https://web.dev/performance-scoring/
- Lighthouse and performance budgets: https://web.dev/use-lighthouse-for-performance-budgets/
- Using Lighthouse Programmatically: https://github.com/GoogleChrome/lighthouse/blob/master/docs/readme.md#using-programmatically
- Configuration Options: https://github.com/GoogleChrome/lighthouse/blob/master/docs/configuration.md
- Authenticated Pages: https://github.com/GoogleChrome/lighthouse/blob/master/docs/authenticated-pages.md
- Example project: https://github.com/claritee/lighthouse-test