Pascal Birchler 59a4df1339 Build/Test Tools: Measure additional load time metrics in performance 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
2023-08-16 08:46:22 +00:00

79 lines
1.9 KiB
JavaScript

/**
* Computes the median number from an array numbers.
*
* @param {number[]} array
*
* @return {number} Median.
*/
function median( array ) {
const mid = Math.floor( array.length / 2 );
const numbers = [ ...array ].sort( ( a, b ) => a - b );
return array.length % 2 !== 0
? numbers[ mid ]
: ( numbers[ mid - 1 ] + numbers[ mid ] ) / 2;
}
/**
* Gets the result file name.
*
* @param {string} File name.
*
* @return {string} Result file name.
*/
function getResultsFilename( fileName ) {
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,
};