The Coverage class enables collecting JavaScript and CSS coverage information during test execution. This helps identify which parts of your code are executed during tests.
Overview
Access coverage through the page object:
const coverage = page.coverage;
JavaScript Coverage
startJSCoverage
Starts collecting JavaScript coverage.
await coverage.startJSCoverage();
await coverage.startJSCoverage({
resetOnNavigation: false,
reportAnonymousScripts: true
});
options.resetOnNavigation
Whether to reset coverage on every navigation.
options.reportAnonymousScripts
Whether to report anonymous scripts.
Returns: Promise<void>
stopJSCoverage
Stops collecting JavaScript coverage and returns results.
const jsCoverage = await coverage.stopJSCoverage();
for (const entry of jsCoverage) {
console.log(`${entry.url}: ${entry.ranges.length} ranges`);
}
Returns: Promise<JSCoverageEntry[]>
Each entry contains:
ranges
Array<{ start: number, end: number }>
Executed code ranges. Each range specifies:
start: Start offset in the script
end: End offset in the script
CSS Coverage
startCSSCoverage
Starts collecting CSS coverage.
await coverage.startCSSCoverage();
await coverage.startCSSCoverage({
resetOnNavigation: false
});
options.resetOnNavigation
Whether to reset coverage on every navigation.
Returns: Promise<void>
stopCSSCoverage
Stops collecting CSS coverage and returns results.
const cssCoverage = await coverage.stopCSSCoverage();
for (const entry of cssCoverage) {
console.log(`${entry.url}: ${entry.ranges.length} ranges`);
}
Returns: Promise<CSSCoverageEntry[]>
Each entry contains:
ranges
Array<{ start: number, end: number }>
Used CSS ranges. Each range specifies:
start: Start offset in the stylesheet
end: End offset in the stylesheet
Examples
Collecting JavaScript coverage
import { test } from '@playwright/test';
import * as fs from 'fs';
test('collect JS coverage', async ({ page }) => {
await page.coverage.startJSCoverage();
await page.goto('https://example.com');
await page.click('#button');
const coverage = await page.coverage.stopJSCoverage();
// Save coverage data
fs.writeFileSync('coverage.json', JSON.stringify(coverage, null, 2));
});
Collecting CSS coverage
test('collect CSS coverage', async ({ page }) => {
await page.coverage.startCSSCoverage();
await page.goto('https://example.com');
const coverage = await page.coverage.stopCSSCoverage();
// Calculate unused CSS
let totalBytes = 0;
let usedBytes = 0;
for (const entry of coverage) {
totalBytes += entry.source.length;
for (const range of entry.ranges) {
usedBytes += range.end - range.start;
}
}
console.log(`Used CSS: ${(usedBytes / totalBytes * 100).toFixed(2)}%`);
});
Collecting both JS and CSS coverage
test('collect all coverage', async ({ page }) => {
await Promise.all([
page.coverage.startJSCoverage(),
page.coverage.startCSSCoverage()
]);
await page.goto('https://example.com');
await page.click('#interactive-element');
const [jsCoverage, cssCoverage] = await Promise.all([
page.coverage.stopJSCoverage(),
page.coverage.stopCSSCoverage()
]);
console.log(`JS files: ${jsCoverage.length}`);
console.log(`CSS files: ${cssCoverage.length}`);
});
Coverage across multiple pages
test('coverage across pages', async ({ page }) => {
await page.coverage.startJSCoverage({
resetOnNavigation: false
});
await page.goto('https://example.com/page1');
await page.click('[href="/page2"]');
await page.waitForURL('**/page2');
const coverage = await page.coverage.stopJSCoverage();
// Coverage includes data from both pages
console.log(`Total coverage entries: ${coverage.length}`);
});
Filtering coverage results
test('filter coverage', async ({ page }) => {
await page.coverage.startJSCoverage();
await page.goto('https://example.com');
const coverage = await page.coverage.stopJSCoverage();
// Filter to only your application code
const appCoverage = coverage.filter(entry =>
entry.url.includes('example.com') &&
!entry.url.includes('node_modules')
);
console.log(`App coverage entries: ${appCoverage.length}`);
});
Calculating coverage percentage
function calculateCoverage(coverage: any[]) {
let totalBytes = 0;
let usedBytes = 0;
for (const entry of coverage) {
totalBytes += entry.source.length;
for (const range of entry.ranges) {
usedBytes += range.end - range.start;
}
}
return {
totalBytes,
usedBytes,
percentage: (usedBytes / totalBytes * 100).toFixed(2)
};
}
test('coverage percentage', async ({ page }) => {
await page.coverage.startJSCoverage();
await page.goto('https://example.com');
const coverage = await page.coverage.stopJSCoverage();
const stats = calculateCoverage(coverage);
console.log(`Coverage: ${stats.percentage}%`);
console.log(`Used: ${stats.usedBytes} / ${stats.totalBytes} bytes`);
});