Skip to content

Commit

Permalink
Build/Test Tools: Measure additional load time metrics in performance…
Browse files Browse the repository at this point in the history
… tests.

Three new metrics are being collected and reported as part of this change:

- Time To First Byte (TTFB) - the time between the request for a resource and when the first byte of a response begins to arrive
- Largest Contentful Paint (LCP) — the render time of the largest image or text block visible within the viewport
- The difference between the two (LCP minus TTFB)

Props joemcgill, flixos90, oandregal, mukesh27, youknowriad, swissspidy.
Fixes #58360.

git-svn-id: https://develop.svn.wordpress.org/trunk@56399 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
swissspidy committed Aug 16, 2023
1 parent 5fab140 commit 59a4df1
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 17 deletions.
28 changes: 21 additions & 7 deletions tests/performance/specs/home-block-theme.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
*/
const { basename, join } = require( 'path' );
const { writeFileSync } = require( 'fs' );
const { getResultsFilename } = require( './../utils' );
const {
getResultsFilename,
getTimeToFirstByte,
getLargestContentfulPaint,
} = require( './../utils' );

/**
* WordPress dependencies.
Expand All @@ -15,14 +19,19 @@ describe( 'Server Timing - Twenty Twenty Three', () => {
wpBeforeTemplate: [],
wpTemplate: [],
wpTotal: [],
timeToFirstByte: [],
largestContentfulPaint: [],
lcpMinusTtfb: [],
};

beforeAll( async () => {
await activateTheme( 'twentytwentythree' );
} );

afterAll( async () => {
const resultsFilename = getResultsFilename( basename( __filename, '.js' ) );
const resultsFilename = getResultsFilename(
basename( __filename, '.js' )
);
writeFileSync(
join( __dirname, resultsFilename ),
JSON.stringify( results, null, 2 )
Expand All @@ -40,14 +49,19 @@ describe( 'Server Timing - Twenty Twenty Three', () => {
const [ navigationTiming ] = JSON.parse( navigationTimingJson );

results.wpBeforeTemplate.push(
navigationTiming.serverTiming[0].duration
navigationTiming.serverTiming[ 0 ].duration
);
results.wpTemplate.push(
navigationTiming.serverTiming[1].duration
);
results.wpTotal.push(
navigationTiming.serverTiming[2].duration
navigationTiming.serverTiming[ 1 ].duration
);
results.wpTotal.push( navigationTiming.serverTiming[ 2 ].duration );

const ttfb = await getTimeToFirstByte();
const lcp = await getLargestContentfulPaint();

results.timeToFirstByte.push( ttfb );
results.largestContentfulPaint.push( lcp );
results.lcpMinusTtfb.push( lcp - ttfb );
}
} );
} );
32 changes: 24 additions & 8 deletions tests/performance/specs/home-classic-theme.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
const { basename, join } = require( 'path' );
const { writeFileSync } = require( 'fs' );
const { exec } = require( 'child_process' );
const { getResultsFilename } = require( './../utils' );
const {
getResultsFilename,
getTimeToFirstByte,
getLargestContentfulPaint,
} = require( './../utils' );

/**
* WordPress dependencies.
Expand All @@ -16,15 +20,22 @@ describe( 'Server Timing - Twenty Twenty One', () => {
wpBeforeTemplate: [],
wpTemplate: [],
wpTotal: [],
timeToFirstByte: [],
largestContentfulPaint: [],
lcpMinusTtfb: [],
};

beforeAll( async () => {
await activateTheme( 'twentytwentyone' );
await exec( 'npm run env:cli -- menu location assign all-pages primary' );
await exec(
'npm run env:cli -- menu location assign all-pages primary'
);
} );

afterAll( async () => {
const resultsFilename = getResultsFilename( basename( __filename, '.js' ) );
const resultsFilename = getResultsFilename(
basename( __filename, '.js' )
);
writeFileSync(
join( __dirname, resultsFilename ),
JSON.stringify( results, null, 2 )
Expand All @@ -42,14 +53,19 @@ describe( 'Server Timing - Twenty Twenty One', () => {
const [ navigationTiming ] = JSON.parse( navigationTimingJson );

results.wpBeforeTemplate.push(
navigationTiming.serverTiming[0].duration
navigationTiming.serverTiming[ 0 ].duration
);
results.wpTemplate.push(
navigationTiming.serverTiming[1].duration
);
results.wpTotal.push(
navigationTiming.serverTiming[2].duration
navigationTiming.serverTiming[ 1 ].duration
);
results.wpTotal.push( navigationTiming.serverTiming[ 2 ].duration );

const ttfb = await getTimeToFirstByte();
const lcp = await getLargestContentfulPaint();

results.timeToFirstByte.push( ttfb );
results.largestContentfulPaint.push( lcp );
results.lcpMinusTtfb.push( lcp - ttfb );
}
} );
} );
49 changes: 47 additions & 2 deletions tests/performance/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,58 @@ function median( array ) {
* @return {string} Result file name.
*/
function getResultsFilename( fileName ) {
const prefixArg = process.argv.find( ( arg ) => arg.startsWith( '--prefix' ) );
const fileNamePrefix = prefixArg ? `${prefixArg.split( '=' )[1]}-` : '';
const prefixArg = process.argv.find( ( arg ) =>
arg.startsWith( '--prefix' )
);
const fileNamePrefix = prefixArg ? `${ prefixArg.split( '=' )[ 1 ] }-` : '';
const resultsFilename = fileNamePrefix + fileName + '.results.json';
return resultsFilename;
}

/**
* Returns time to first byte (TTFB) using the Navigation Timing API.
*
* @see https://web.dev/ttfb/#measure-ttfb-in-javascript
*
* @return {Promise<number>}
*/
async function getTimeToFirstByte() {
return page.evaluate( () => {
const { responseStart, startTime } =
performance.getEntriesByType( 'navigation' )[ 0 ];
return responseStart - startTime;
} );
}

/**
* Returns the Largest Contentful Paint (LCP) value using the dedicated API.
*
* @see https://w3c.github.io/largest-contentful-paint/
* @see https://web.dev/lcp/#measure-lcp-in-javascript
*
* @return {Promise<number>}
*/
async function getLargestContentfulPaint() {
return page.evaluate(
() =>
new Promise( ( resolve ) => {
new PerformanceObserver( ( entryList ) => {
const entries = entryList.getEntries();
// The last entry is the largest contentful paint.
const largestPaintEntry = entries.at( -1 );

resolve( largestPaintEntry?.startTime || 0 );
} ).observe( {
type: 'largest-contentful-paint',
buffered: true,
} );
} )
);
}

module.exports = {
median,
getResultsFilename,
getTimeToFirstByte,
getLargestContentfulPaint,
};

0 comments on commit 59a4df1

Please sign in to comment.