Devtools Service
A WebdriverIO service that allows you to run Chrome DevTools commands in your tests
With Chrome v63 and up the browser started to support multi clients allowing arbitrary clients to access the Chrome DevTools Protocol. This provides interesting opportunities to automate Chrome beyond the WebDriver protocol. With this service you can enhance the wdio browser object to leverage that access and call Chrome DevTools commands within your tests to e.g. intercept requests, throttle network capabilities or take CSS/JS coverage.
Since Firefox 86, a subset of Chrome DevTools Protocol has been implemented by passing the capability "moz:debuggerAddress": true
.
Note: this service currently only supports Chrome v63 and up, Chromium, and Firefox 86 and up! Given that cloud vendors don't expose access to the Chrome DevTools Protocol this service also usually only works when running tests locally or through a Selenium Grid v4 or higher.
Installation
The easiest way is to keep @wdio/devtools-service
as a devDependency in your package.json
, via:
npm install @wdio/devtools-service --save-dev
Instructions on how to install WebdriverIO
can be found here.
Configuration
In order to use the service you just need to add the service to your service list in your wdio.conf.js
, like:
// wdio.conf.js
export const config = {
// ...
services: ['devtools'],
// ...
};
Usage
The @wdio/devtools-service
offers you a variety of features that helps you to automate Chrome beyond the WebDriver protocol. It gives you access to the Chrome DevTools protocol as well as to a Puppeteer instance that you can use to automate Chrome with the Puppeteer automation interface.
Performance Testing
The DevTools service allows you to capture performance data from every page load or page transition that was caused by a click. To enable it call browser.enablePerformanceAudits(<options>)
. After you are done capturing all necessary performance data disable it to revert the throttling settings, e.g.:
import assert from 'node:assert'
describe('JSON.org page', () => {
before(async () => {
await browser.enablePerformanceAudits()
})
it('should load within performance budget', async () => {
/**
* this page load will take a bit longer as the DevTools service will
* capture all metrics in the background
*/
await browser.url('http://json.org')
let metrics = await browser.getMetrics()
assert.ok(metrics.speedIndex < 1500) // check that speedIndex is below 1.5ms
let score = await browser.getPerformanceScore() // get Lighthouse Performance score
assert.ok(score >= .99) // Lighthouse Performance score is at 99% or higher
$('=Esperanto').click()
metrics = await browser.getMetrics()
assert.ok(metrics.speedIndex < 1500)
score = await browser.getPerformanceScore()
assert.ok(score >= .99)
})
after(async () => {
await browser.disablePerformanceAudits()
})
})
You can emulate a mobile device by using the emulateDevice
command, throttling CPU and network as well as setting mobile
as form factor:
await browser.emulateDevice('iPhone X')
await browser.enablePerformanceAudits({
networkThrottling: 'Good 3G',
cpuThrottling: 4,
formFactor: 'mobile'
})
The following commands with their results are available:
getMetrics
Get most common used performance metrics.
console.log(await browser.getMetrics())
/**
* { timeToFirstByte: 566,
* serverResponseTime: 566,
* domContentLoaded: 3397,
* firstVisualChange: 2610,
* firstPaint: 2822,
* firstContentfulPaint: 2822,
* firstMeaningfulPaint: 2822,
* largestContentfulPaint: 2822,
* lastVisualChange: 15572,
* interactive: 6135,
* load: 8429,
* speedIndex: 3259,
* totalBlockingTime: 31,
* maxPotentialFID: 161,
* cumulativeLayoutShift: 2822 }
*/
getDiagnostics
Get some useful diagnostics about the page load.
console.log(await browser.getDiagnostics())
/**
* { numRequests: 8,
* numScripts: 0,
* numStylesheets: 0,
* numFonts: 0,
* numTasks: 237,
* numTasksOver10ms: 5,
* numTasksOver25ms: 2,
* numTasksOver50ms: 2,
* numTasksOver100ms: 0,
* numTasksOver500ms: 0,
* rtt: 147.20600000000002,
* throughput: 47729.68474448835,
* maxRtt: 176.085,
* maxServerLatency: 1016.813,
* totalByteWeight: 62929,
* totalTaskTime: 254.07899999999978,
* mainDocumentTransferSize: 8023 }
*/
getMainThreadWorkBreakdown
Returns a list with a breakdown of all main thread task and their total duration.
console.log(await browser.getMainThreadWorkBreakdown())
/**
* [ { group: 'styleLayout', duration: 130.59099999999998 },
* { group: 'other', duration: 44.819 },
* { group: 'paintCompositeRender', duration: 13.732000000000005 },
* { group: 'parseHTML', duration: 3.9080000000000004 },
* { group: 'scriptEvaluation', duration: 2.437999999999999 },
* { group: 'scriptParseCompile', duration: 0.20800000000000002 } ]
*/
getPerformanceScore
Returns the Lighthouse Performance Score which is a weighted mean of the following metrics: firstContentfulPaint
, speedIndex
, largestContentfulPaint
, cumulativeLayoutShift
, totalBlockingTime
, interactive
, maxPotentialFID
or cumulativeLayoutShift
.
console.log(await browser.getPerformanceScore())
/**
* 0.897826278457836
*/
enablePerformanceAudits
Enables auto performance audits for all page loads that are cause by calling the url
command or clicking on a link or anything that causes a page load. You can pass in a config object to determine some throttling options. The default throttling profile is Good 3G
network with a 4x CPU trottling.
await browser.enablePerformanceAudits({
networkThrottling: 'Good 3G',
cpuThrottling: 4,
cacheEnabled: true,
formFactor: 'mobile'
})