Make WordPress Core

Changeset 56399


Ignore:
Timestamp:
08/16/2023 08:46:22 AM (9 months ago)
Author:
swissspidy
Message:

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.

Location:
trunk/tests/performance
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/performance/specs/home-block-theme.test.js

    r55459 r56399  
    44const { basename, join } = require( 'path' );
    55const { writeFileSync } = require( 'fs' );
    6 const { getResultsFilename } = require( './../utils' );
     6const {
     7    getResultsFilename,
     8    getTimeToFirstByte,
     9    getLargestContentfulPaint,
     10} = require( './../utils' );
    711
    812/**
     
    1620        wpTemplate: [],
    1721        wpTotal: [],
     22        timeToFirstByte: [],
     23        largestContentfulPaint: [],
     24        lcpMinusTtfb: [],
    1825    };
    1926
     
    2330
    2431    afterAll( async () => {
    25         const resultsFilename = getResultsFilename( basename( __filename, '.js' ) );
     32        const resultsFilename = getResultsFilename(
     33            basename( __filename, '.js' )
     34        );
    2635        writeFileSync(
    2736            join( __dirname, resultsFilename ),
     
    4150
    4251            results.wpBeforeTemplate.push(
    43                 navigationTiming.serverTiming[0].duration
     52                navigationTiming.serverTiming[ 0 ].duration
    4453            );
    4554            results.wpTemplate.push(
    46                 navigationTiming.serverTiming[1].duration
     55                navigationTiming.serverTiming[ 1 ].duration
    4756            );
    48             results.wpTotal.push(
    49                 navigationTiming.serverTiming[2].duration
    50             );
     57            results.wpTotal.push( navigationTiming.serverTiming[ 2 ].duration );
     58
     59            const ttfb = await getTimeToFirstByte();
     60            const lcp = await getLargestContentfulPaint();
     61
     62            results.timeToFirstByte.push( ttfb );
     63            results.largestContentfulPaint.push( lcp );
     64            results.lcpMinusTtfb.push( lcp - ttfb );
    5165        }
    5266    } );
  • trunk/tests/performance/specs/home-classic-theme.test.js

    r55459 r56399  
    55const { writeFileSync } = require( 'fs' );
    66const { exec } = require( 'child_process' );
    7 const { getResultsFilename } = require( './../utils' );
     7const {
     8    getResultsFilename,
     9    getTimeToFirstByte,
     10    getLargestContentfulPaint,
     11} = require( './../utils' );
    812
    913/**
     
    1721        wpTemplate: [],
    1822        wpTotal: [],
     23        timeToFirstByte: [],
     24        largestContentfulPaint: [],
     25        lcpMinusTtfb: [],
    1926    };
    2027
    2128    beforeAll( async () => {
    2229        await activateTheme( 'twentytwentyone' );
    23         await exec( 'npm run env:cli -- menu location assign all-pages primary' );
     30        await exec(
     31            'npm run env:cli -- menu location assign all-pages primary'
     32        );
    2433    } );
    2534
    2635    afterAll( async () => {
    27         const resultsFilename = getResultsFilename( basename( __filename, '.js' ) );
     36        const resultsFilename = getResultsFilename(
     37            basename( __filename, '.js' )
     38        );
    2839        writeFileSync(
    2940            join( __dirname, resultsFilename ),
     
    4354
    4455            results.wpBeforeTemplate.push(
    45                 navigationTiming.serverTiming[0].duration
     56                navigationTiming.serverTiming[ 0 ].duration
    4657            );
    4758            results.wpTemplate.push(
    48                 navigationTiming.serverTiming[1].duration
     59                navigationTiming.serverTiming[ 1 ].duration
    4960            );
    50             results.wpTotal.push(
    51                 navigationTiming.serverTiming[2].duration
    52             );
     61            results.wpTotal.push( navigationTiming.serverTiming[ 2 ].duration );
     62
     63            const ttfb = await getTimeToFirstByte();
     64            const lcp = await getLargestContentfulPaint();
     65
     66            results.timeToFirstByte.push( ttfb );
     67            results.largestContentfulPaint.push( lcp );
     68            results.lcpMinusTtfb.push( lcp - ttfb );
    5369        }
    5470    } );
  • trunk/tests/performance/utils.js

    r55459 r56399  
    2222 */
    2323function getResultsFilename( fileName ) {
    24     const prefixArg = process.argv.find( ( arg ) => arg.startsWith( '--prefix' ) );
    25     const fileNamePrefix = prefixArg ? `${prefixArg.split( '=' )[1]}-` : '';
     24    const prefixArg = process.argv.find( ( arg ) =>
     25        arg.startsWith( '--prefix' )
     26    );
     27    const fileNamePrefix = prefixArg ? `${ prefixArg.split( '=' )[ 1 ] }-` : '';
    2628    const resultsFilename = fileNamePrefix + fileName + '.results.json';
    2729    return resultsFilename;
     30}
     31
     32/**
     33 * Returns time to first byte (TTFB) using the Navigation Timing API.
     34 *
     35 * @see https://web.dev/ttfb/#measure-ttfb-in-javascript
     36 *
     37 * @return {Promise<number>}
     38 */
     39async function getTimeToFirstByte() {
     40    return page.evaluate( () => {
     41        const { responseStart, startTime } =
     42            performance.getEntriesByType( 'navigation' )[ 0 ];
     43        return responseStart - startTime;
     44    } );
     45}
     46
     47/**
     48 * Returns the Largest Contentful Paint (LCP) value using the dedicated API.
     49 *
     50 * @see https://w3c.github.io/largest-contentful-paint/
     51 * @see https://web.dev/lcp/#measure-lcp-in-javascript
     52 *
     53 * @return {Promise<number>}
     54 */
     55async function getLargestContentfulPaint() {
     56    return page.evaluate(
     57        () =>
     58            new Promise( ( resolve ) => {
     59                new PerformanceObserver( ( entryList ) => {
     60                    const entries = entryList.getEntries();
     61                    // The last entry is the largest contentful paint.
     62                    const largestPaintEntry = entries.at( -1 );
     63
     64                    resolve( largestPaintEntry?.startTime || 0 );
     65                } ).observe( {
     66                    type: 'largest-contentful-paint',
     67                    buffered: true,
     68                } );
     69            } )
     70    );
    2871}
    2972
     
    3174    median,
    3275    getResultsFilename,
     76    getTimeToFirstByte,
     77    getLargestContentfulPaint,
    3378};
Note: See TracChangeset for help on using the changeset viewer.