Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add performance tests for localized site #5624

Closed
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/performance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ jobs:
run: |
npm run env:cli -- rewrite structure '/%year%/%monthnum%/%postname%/' --path=/var/www/${{ env.LOCAL_DIR }}

- name: Install additional languages
run: |
npm run env:cli -- language core install de_DE --path=/var/www/${{ env.LOCAL_DIR }}
npm run env:cli -- language plugin install de_DE --all --path=/var/www/${{ env.LOCAL_DIR }}
npm run env:cli -- language theme install de_DE --all --path=/var/www/${{ env.LOCAL_DIR }}
swissspidy marked this conversation as resolved.
Show resolved Hide resolved

- name: Install MU plugin
run: |
mkdir ./${{ env.LOCAL_DIR }}/wp-content/mu-plugins
Expand Down
35 changes: 29 additions & 6 deletions tests/performance/compare-results.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ const parseFile = ( fileName ) =>
);

// The list of test suites to log.
const testSuites = [ 'home-block-theme', 'home-classic-theme' ];
const testSuites = [
'admin',
'admin-l10n',
'home-block-theme',
'home-block-theme-l10n',
'home-classic-theme',
'home-classic-theme-l10n',
];

// The current commit's results.
const testResults = Object.fromEntries(
Expand Down Expand Up @@ -128,6 +135,22 @@ console.log( 'Performance Test Results\n' );

console.log( 'Note: Due to the nature of how GitHub Actions work, some variance in the results is expected.\n' );

/**
* Nicely format a given metric's value.
* @param {string} metric Metric.
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
* @param {number} value
*/
function formatValue( metric, value) {
if ( null === value ) {
return 'N/A';
}
if ( 'wpMemoryUsage' === metric ) {
return `${ ( value / Math.pow( 10, 6 ) ).toFixed( 2 ) } MB`;
}

return `${ value.toFixed( 2 ) } ms`;
}

for ( const key of testSuites ) {
const current = testResults[ key ] || {};
const prev = prevResults[ key ] || {};
Expand All @@ -141,15 +164,15 @@ for ( const key of testSuites ) {

for ( const [ metric, values ] of Object.entries( current ) ) {
const value = median( values );
const prevValue = median( prev[ metric ] );
const prevValue = prev[ metric ] ? median( prev[ metric ] ) : null;

const delta = value - prevValue;
const delta = null !== prevValue ? value - prevValue : 0
const percentage = ( delta / value ) * 100;
rows.push( {
Metric: metric,
Before: `${ prevValue.toFixed( 2 ) } ms`,
After: `${ value.toFixed( 2 ) } ms`,
'Diff abs.': `${ delta.toFixed( 2 ) } ms`,
Before: formatValue( metric, prevValue ),
After: formatValue( metric, value ),
'Diff abs.': formatValue( metric, delta ),
'Diff %': `${ percentage.toFixed( 2 ) } %`,
} );
}
Expand Down
4 changes: 4 additions & 0 deletions tests/performance/log-results.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ const { median } = require( './utils' );

// The list of test suites to log.
const testSuites = [
'admin',
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
'admin-l10n',
'home-block-theme',
'home-block-theme-l10n',
'home-classic-theme',
'home-classic-theme-l10n',
];

// A list of results to parse based on test suites.
Expand Down
4 changes: 1 addition & 3 deletions tests/performance/playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ process.env.TEST_RUNS ??= '20';
const config = defineConfig( {
...baseConfig,
globalSetup: require.resolve( './config/global-setup.js' ),
reporter: process.env.CI
? './config/performance-reporter.js'
: [ [ 'list' ], [ './config/performance-reporter.js' ] ],
reporter: [ [ 'list' ], [ './config/performance-reporter.js' ] ],
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
forbidOnly: !! process.env.CI,
workers: 1,
retries: 0,
Expand Down
4 changes: 4 additions & 0 deletions tests/performance/results.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ const { join } = require( 'node:path' );
const { median, getResultsFilename } = require( './utils' );

const testSuites = [
'admin',
'admin-l10n',
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
'home-classic-theme',
'home-classic-theme-l10n',
'home-block-theme',
'home-block-theme-l10n',
];

console.log( '\n>> 🎉 Results 🎉 \n' );
Expand Down
52 changes: 52 additions & 0 deletions tests/performance/specs/admin-l10n.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* WordPress dependencies
*/
import { test } from '@wordpress/e2e-test-utils-playwright';

/**
* Internal dependencies
*/
import { camelCaseDashes } from '../utils';

const results = {
timeToFirstByte: [],
};

test.describe( 'Admin (L10N)', () => {
test.beforeAll( async ( { requestUtils } ) => {
await requestUtils.activateTheme( 'twentytwentyone' );
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
await requestUtils.updateSiteSettings( {
language: 'de_DE',
} );
} );

test.afterAll( async ( { requestUtils }, testInfo ) => {
await testInfo.attach( 'results', {
body: JSON.stringify( results, null, 2 ),
contentType: 'application/json',
} );
await requestUtils.updateSiteSettings( {
language: '',
} );
} );

const iterations = Number( process.env.TEST_RUNS );
for ( let i = 1; i <= iterations; i++ ) {
test( `Measure load time metrics (${ i } of ${ iterations })`, async ( {
admin,
metrics,
} ) => {
await admin.visitAdminPage( '/' );

const serverTiming = await metrics.getServerTiming();

for (const [key, value] of Object.entries( serverTiming ) ) {
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
results[ camelCaseDashes( key ) ] ??= [];
results[ camelCaseDashes( key ) ].push( value );
}

const ttfb = await metrics.getTimeToFirstByte();
results.timeToFirstByte.push( ttfb );
} );
}
} );
46 changes: 46 additions & 0 deletions tests/performance/specs/admin.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* WordPress dependencies
*/
import { test } from '@wordpress/e2e-test-utils-playwright';

/**
* Internal dependencies
*/
import { camelCaseDashes } from '../utils';

const results = {
timeToFirstByte: [],
};

test.describe( 'Admin', () => {
test.beforeAll( async ( { requestUtils } ) => {
await requestUtils.activateTheme( 'twentytwentyone' );
} );

test.afterAll( async ( {}, testInfo ) => {
await testInfo.attach( 'results', {
body: JSON.stringify( results, null, 2 ),
contentType: 'application/json',
} );
} );

const iterations = Number( process.env.TEST_RUNS );
for ( let i = 1; i <= iterations; i++ ) {
test( `Measure load time metrics (${ i } of ${ iterations })`, async ( {
admin,
metrics,
} ) => {
await admin.visitAdminPage( '/' );

const serverTiming = await metrics.getServerTiming();

for (const [key, value] of Object.entries( serverTiming ) ) {
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
results[ camelCaseDashes( key ) ] ??= [];
results[ camelCaseDashes( key ) ].push( value );
}

const ttfb = await metrics.getTimeToFirstByte();
results.timeToFirstByte.push( ttfb );
} );
}
} );
63 changes: 63 additions & 0 deletions tests/performance/specs/home-block-theme-l10n.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* WordPress dependencies
*/
import { test } from '@wordpress/e2e-test-utils-playwright';

/**
* Internal dependencies
*/
import { camelCaseDashes } from '../utils';

const results = {
timeToFirstByte: [],
largestContentfulPaint: [],
lcpMinusTtfb: [],
};

test.describe( 'Front End - Twenty Twenty Three (L10N)', () => {
test.use( {
storageState: {}, // User will be logged out.
} );

test.beforeAll( async ( { requestUtils } ) => {
await requestUtils.activateTheme( 'twentytwentythree' );
await requestUtils.updateSiteSettings( {
language: 'de_DE',
} );
} );

test.afterAll( async ( { requestUtils }, testInfo ) => {
await testInfo.attach( 'results', {
body: JSON.stringify( results, null, 2 ),
contentType: 'application/json',
} );
await requestUtils.activateTheme( 'twentytwentyone' );
await requestUtils.updateSiteSettings( {
language: '',
} );
} );

const iterations = Number( process.env.TEST_RUNS );
for ( let i = 1; i <= iterations; i++ ) {
test( `Measure load time metrics (${ i } of ${ iterations })`, async ( {
page,
metrics,
} ) => {
await page.goto( '/' );

const serverTiming = await metrics.getServerTiming();

for ( const [key, value] of Object.entries( serverTiming ) ) {
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
results[ camelCaseDashes( key ) ] ??= [];
results[ camelCaseDashes( key ) ].push( value );
}

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

results.largestContentfulPaint.push( lcp );
results.timeToFirstByte.push( ttfb );
results.lcpMinusTtfb.push( lcp - ttfb );
} );
}
} );
62 changes: 62 additions & 0 deletions tests/performance/specs/home-classic-theme-l10n.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* WordPress dependencies
*/
import { test } from '@wordpress/e2e-test-utils-playwright';

/**
* Internal dependencies
*/
import { camelCaseDashes } from '../utils';

const results = {
timeToFirstByte: [],
largestContentfulPaint: [],
lcpMinusTtfb: [],
};

test.describe( 'Front End - Twenty Twenty One (L10N)', () => {
test.use( {
storageState: {}, // User will be logged out.
} );

test.beforeAll( async ( { requestUtils } ) => {
await requestUtils.activateTheme( 'twentytwentyone' );
await requestUtils.updateSiteSettings( {
language: 'de_DE',
} );
} );

test.afterAll( async ( { requestUtils }, testInfo ) => {
await testInfo.attach( 'results', {
body: JSON.stringify( results, null, 2 ),
contentType: 'application/json',
} );
await requestUtils.updateSiteSettings( {
language: '',
} );
} );

const iterations = Number( process.env.TEST_RUNS );
for ( let i = 1; i <= iterations; i++ ) {
test( `Measure load time metrics (${ i } of ${ iterations })`, async ( {
page,
metrics,
} ) => {
await page.goto( '/' );

const serverTiming = await metrics.getServerTiming();

for (const [key, value] of Object.entries( serverTiming ) ) {
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
results[ camelCaseDashes( key ) ] ??= [];
results[ camelCaseDashes( key ) ].push( value );
}

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

results.largestContentfulPaint.push( lcp );
results.timeToFirstByte.push( ttfb );
results.lcpMinusTtfb.push( lcp - ttfb );
} );
}
} );
5 changes: 5 additions & 0 deletions tests/performance/wp-content/mu-plugins/server-timing.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ static function () use ( $server_timing_values, $template_start ) {

$server_timing_values['total'] = $server_timing_values['before-template'] + $server_timing_values['template'];

// While values passed via Server-Timing are intended to be durations,
// any numeric value can actually be passed.
// This is a nice little trick as it allows to easily get this information in JS.
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
$server_timing_values['memory-usage'] = memory_get_usage();
swissspidy marked this conversation as resolved.
Show resolved Hide resolved

$header_values = array();
foreach ( $server_timing_values as $slug => $value ) {
if ( is_float( $value ) ) {
Expand Down
Loading