From 1e287767a3aab794bf5b5cd5169361aad4b9c603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Tue, 10 Jan 2023 18:56:51 +0100 Subject: [PATCH 01/13] Add skeleton for front-end tests --- .../specs/performance/front-end.test.js | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 packages/e2e-tests/specs/performance/front-end.test.js diff --git a/packages/e2e-tests/specs/performance/front-end.test.js b/packages/e2e-tests/specs/performance/front-end.test.js new file mode 100644 index 00000000000000..a2dbf64259dd07 --- /dev/null +++ b/packages/e2e-tests/specs/performance/front-end.test.js @@ -0,0 +1,38 @@ +/** + * External dependencies + */ +import { basename, join } from 'path'; +import { writeFileSync } from 'fs'; + +/** + * WordPress dependencies + */ +import { createURL } from '@wordpress/e2e-test-utils'; + +describe( 'Front End Performance', () => { + const results = { + TTFB: [], + }; + + afterAll( async () => { + const resultsFilename = basename( __filename, '.js' ) + '.results.json'; + writeFileSync( + join( __dirname, resultsFilename ), + JSON.stringify( results, null, 2 ) + ); + } ); + + it( 'TTFB', async () => { + let i = 5; + while ( i-- ) { + await page.goto( createURL( '/' ) ); + const navigationTimingJson = await page.evaluate( () => + JSON.stringify( performance.getEntriesByType( 'navigation' ) ) + ); + const [ navigationTiming ] = JSON.parse( navigationTimingJson ); + results.TTFB.push( + navigationTiming.responseStart - navigationTiming.requestStart + ); + } + } ); +} ); From 859e45394ba2f283fc61877816b8ab87a52b3651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 11 Jan 2023 11:18:00 +0100 Subject: [PATCH 02/13] Refactor to make the medians independent of the data points in the test suite --- bin/plugin/commands/performance.js | 91 +++++++----------------------- 1 file changed, 19 insertions(+), 72 deletions(-) diff --git a/bin/plugin/commands/performance.js b/bin/plugin/commands/performance.js index 81aa39820c8b5a..c448786f419dae 100644 --- a/bin/plugin/commands/performance.js +++ b/bin/plugin/commands/performance.js @@ -379,78 +379,25 @@ async function runPerformanceTests( branches, options ) { // Computing medians. for ( const branch of branches ) { - const medians = mapValues( - { - serverResponse: rawResults.map( - ( r ) => r[ branch ].serverResponse - ), - firstPaint: rawResults.map( - ( r ) => r[ branch ].firstPaint - ), - domContentLoaded: rawResults.map( - ( r ) => r[ branch ].domContentLoaded - ), - loaded: rawResults.map( ( r ) => r[ branch ].loaded ), - firstContentfulPaint: rawResults.map( - ( r ) => r[ branch ].firstContentfulPaint - ), - firstBlock: rawResults.map( - ( r ) => r[ branch ].firstBlock - ), - type: rawResults.map( ( r ) => r[ branch ].type ), - minType: rawResults.map( ( r ) => r[ branch ].minType ), - maxType: rawResults.map( ( r ) => r[ branch ].maxType ), - typeContainer: rawResults.map( - ( r ) => r[ branch ].typeContainer - ), - minTypeContainer: rawResults.map( - ( r ) => r[ branch ].minTypeContainer - ), - maxTypeContainer: rawResults.map( - ( r ) => r[ branch ].maxTypeContainer - ), - focus: rawResults.map( ( r ) => r[ branch ].focus ), - minFocus: rawResults.map( ( r ) => r[ branch ].minFocus ), - maxFocus: rawResults.map( ( r ) => r[ branch ].maxFocus ), - inserterOpen: rawResults.map( - ( r ) => r[ branch ].inserterOpen - ), - minInserterOpen: rawResults.map( - ( r ) => r[ branch ].minInserterOpen - ), - maxInserterOpen: rawResults.map( - ( r ) => r[ branch ].maxInserterOpen - ), - inserterSearch: rawResults.map( - ( r ) => r[ branch ].inserterSearch - ), - minInserterSearch: rawResults.map( - ( r ) => r[ branch ].minInserterSearch - ), - maxInserterSearch: rawResults.map( - ( r ) => r[ branch ].maxInserterSearch - ), - inserterHover: rawResults.map( - ( r ) => r[ branch ].inserterHover - ), - minInserterHover: rawResults.map( - ( r ) => r[ branch ].minInserterHover - ), - maxInserterHover: rawResults.map( - ( r ) => r[ branch ].maxInserterHover - ), - listViewOpen: rawResults.map( - ( r ) => r[ branch ].listViewOpen - ), - minListViewOpen: rawResults.map( - ( r ) => r[ branch ].minListViewOpen - ), - maxListViewOpen: rawResults.map( - ( r ) => r[ branch ].maxListViewOpen - ), - }, - median - ); + /** + * @type {string[]} + */ + let dataPointsForTestSuite = []; + if ( rawResults.length > 0 ) { + dataPointsForTestSuite = Object.keys( + rawResults[ 0 ][ branch ] + ); + } + + const resultsByDataPoint = {}; + dataPointsForTestSuite.forEach( ( dataPoint ) => { + // @ts-ignore + resultsByDataPoint[ dataPoint ] = rawResults.map( + // @ts-ignore + ( r ) => r[ branch ][ dataPoint ] + ); + } ); + const medians = mapValues( resultsByDataPoint, median ); // Format results as times. results[ testSuite ][ branch ] = mapValues( medians, formatTime ); From c647035739fdc51cf1d8559ebc98f1a9a5fd49d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 11 Jan 2023 11:21:56 +0100 Subject: [PATCH 03/13] Curate results for front-end suite --- bin/plugin/commands/performance.js | 13 +++++++++++-- .../e2e-tests/specs/performance/front-end.test.js | 6 +++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/bin/plugin/commands/performance.js b/bin/plugin/commands/performance.js index c448786f419dae..f2be83fc69b57c 100644 --- a/bin/plugin/commands/performance.js +++ b/bin/plugin/commands/performance.js @@ -30,6 +30,7 @@ const config = require( '../config' ); /** * @typedef WPRawPerformanceResults * + * @property {number[]} timeToFirstByte Represents the time since the browser started the request until it received a response. * @property {number[]} serverResponse Represents the time the server takes to respond. * @property {number[]} firstPaint Represents the time when the user agent first rendered after navigation. * @property {number[]} domContentLoaded Represents the time immediately after the document's DOMContentLoaded event completes. @@ -48,6 +49,7 @@ const config = require( '../config' ); /** * @typedef WPPerformanceResults * + * @property {number=} timeToFirstByte Represents the time since the browser started the request until it received a response. * @property {number=} serverResponse Represents the time the server takes to respond. * @property {number=} firstPaint Represents the time when the user agent first rendered after navigation. * @property {number=} domContentLoaded Represents the time immediately after the document's DOMContentLoaded event completes. @@ -118,11 +120,18 @@ function formatTime( number ) { /** * Curate the raw performance results. * + * @param {string} testSuite * @param {WPRawPerformanceResults} results * * @return {WPPerformanceResults} Curated Performance results. */ -function curateResults( results ) { +function curateResults( testSuite, results ) { + if ( testSuite === 'front-end' ) { + return { + timeToFirstByte: average( results.timeToFirstByte ), + }; + } + return { serverResponse: average( results.serverResponse ), firstPaint: average( results.firstPaint ), @@ -173,7 +182,7 @@ async function runTestSuite( testSuite, performanceTestDirectory ) { `packages/e2e-tests/specs/performance/${ testSuite }.test.results.json` ) ); - return curateResults( rawResults ); + return curateResults( testSuite, rawResults ); } /** diff --git a/packages/e2e-tests/specs/performance/front-end.test.js b/packages/e2e-tests/specs/performance/front-end.test.js index a2dbf64259dd07..14638db2d630d1 100644 --- a/packages/e2e-tests/specs/performance/front-end.test.js +++ b/packages/e2e-tests/specs/performance/front-end.test.js @@ -11,7 +11,7 @@ import { createURL } from '@wordpress/e2e-test-utils'; describe( 'Front End Performance', () => { const results = { - TTFB: [], + timeToFirstByte: [], }; afterAll( async () => { @@ -22,7 +22,7 @@ describe( 'Front End Performance', () => { ); } ); - it( 'TTFB', async () => { + it( 'Time To First Byte (TTFB)', async () => { let i = 5; while ( i-- ) { await page.goto( createURL( '/' ) ); @@ -30,7 +30,7 @@ describe( 'Front End Performance', () => { JSON.stringify( performance.getEntriesByType( 'navigation' ) ) ); const [ navigationTiming ] = JSON.parse( navigationTimingJson ); - results.TTFB.push( + results.timeToFirstByte.push( navigationTiming.responseStart - navigationTiming.requestStart ); } From 852ef8106ef1cef82f9b19a23dafba9c21806647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 11 Jan 2023 13:02:24 +0100 Subject: [PATCH 04/13] Add front-end as a new test suite --- bin/plugin/commands/performance.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/plugin/commands/performance.js b/bin/plugin/commands/performance.js index f2be83fc69b57c..d46d628b004f21 100644 --- a/bin/plugin/commands/performance.js +++ b/bin/plugin/commands/performance.js @@ -353,7 +353,7 @@ async function runPerformanceTests( branches, options ) { // 4- Running the tests. log( '\n>> Running the tests' ); - const testSuites = [ 'post-editor', 'site-editor' ]; + const testSuites = [ 'post-editor', 'site-editor', 'front-end' ]; /** @type {Record>} */ const results = {}; From aedce8f9d5bee07f7629ead5df8e549519b4055a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 11 Jan 2023 14:16:58 +0100 Subject: [PATCH 05/13] Add new logout util --- packages/e2e-test-utils/README.md | 4 ++++ packages/e2e-test-utils/src/index.js | 1 + packages/e2e-test-utils/src/logout.js | 25 +++++++++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 packages/e2e-test-utils/src/logout.js diff --git a/packages/e2e-test-utils/README.md b/packages/e2e-test-utils/README.md index 96ed7f3dcb1ea4..7ddfdcf8a9c8a7 100644 --- a/packages/e2e-test-utils/README.md +++ b/packages/e2e-test-utils/README.md @@ -552,6 +552,10 @@ _Parameters_ - _username_ `?string`: String to be used as user credential. - _password_ `?string`: String to be used as user credential. +### logout + +Performs log out. + ### mockOrTransform Mocks a request with the supplied mock object, or allows it to run with an optional transform, based on the diff --git a/packages/e2e-test-utils/src/index.js b/packages/e2e-test-utils/src/index.js index 6b217d52c44074..2d20dfe8b099fc 100644 --- a/packages/e2e-test-utils/src/index.js +++ b/packages/e2e-test-utils/src/index.js @@ -59,6 +59,7 @@ export { installTheme } from './install-theme'; export { isCurrentURL } from './is-current-url'; export { isInDefaultBlock } from './is-in-default-block'; export { loginUser } from './login-user'; +export { logout } from './logout'; export { createMenu, deleteAllMenus } from './menus'; export { enableFocusLossObservation, diff --git a/packages/e2e-test-utils/src/logout.js b/packages/e2e-test-utils/src/logout.js new file mode 100644 index 00000000000000..6612389893d92d --- /dev/null +++ b/packages/e2e-test-utils/src/logout.js @@ -0,0 +1,25 @@ +/** + * Internal dependencies + */ +import { createURL } from './create-url'; +import { isCurrentURL } from './is-current-url'; + +/** + * Performs log out. + * + */ +export async function logout() { + // If it is logged and in a page different than the dashboard, + // move to the dashboard. Some pages may be in full-screen mode, + // so they won't have the log-out button available. + if ( ! isCurrentURL( 'wp-login.php' ) && ! isCurrentURL( 'wp-admin' ) ) { + await page.goto( createURL( 'wp-admin' ) ); + } + + await Promise.all( [ + page.hover( '#wp-admin-bar-my-account' ), + page.waitForSelector( '#wp-admin-bar-logout', { visible: true } ), + ] ); + + await page.click( '#wp-admin-bar-logout' ); +} From f052a475e179e4c4de51c38018d0d15c4b32fb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 11 Jan 2023 14:34:09 +0100 Subject: [PATCH 06/13] Logout for front-end test suite --- packages/e2e-tests/specs/performance/front-end.test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/e2e-tests/specs/performance/front-end.test.js b/packages/e2e-tests/specs/performance/front-end.test.js index 14638db2d630d1..2e6bb7afc35199 100644 --- a/packages/e2e-tests/specs/performance/front-end.test.js +++ b/packages/e2e-tests/specs/performance/front-end.test.js @@ -7,13 +7,17 @@ import { writeFileSync } from 'fs'; /** * WordPress dependencies */ -import { createURL } from '@wordpress/e2e-test-utils'; +import { createURL, logout } from '@wordpress/e2e-test-utils'; describe( 'Front End Performance', () => { const results = { timeToFirstByte: [], }; + beforeAll( async () => { + await logout(); + } ); + afterAll( async () => { const resultsFilename = basename( __filename, '.js' ) + '.results.json'; writeFileSync( From 248635c060d2304295ad71d1ad21650917c29160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 11 Jan 2023 17:19:09 +0100 Subject: [PATCH 07/13] Create separate suites per theme (twentytwentyone and twentytwentythree) --- bin/plugin/commands/performance.js | 12 ++++- ...t.js => front-end-twentytwentyone.test.js} | 0 .../front-end-twentytwentythree.test.js | 44 +++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) rename packages/e2e-tests/specs/performance/{front-end.test.js => front-end-twentytwentyone.test.js} (100%) create mode 100644 packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js diff --git a/bin/plugin/commands/performance.js b/bin/plugin/commands/performance.js index d46d628b004f21..554ea454d4cf6a 100644 --- a/bin/plugin/commands/performance.js +++ b/bin/plugin/commands/performance.js @@ -126,7 +126,10 @@ function formatTime( number ) { * @return {WPPerformanceResults} Curated Performance results. */ function curateResults( testSuite, results ) { - if ( testSuite === 'front-end' ) { + if ( + testSuite === 'front-end-twentytwentyone' || + testSuite === 'front-end-twentytwentythree' + ) { return { timeToFirstByte: average( results.timeToFirstByte ), }; @@ -353,7 +356,12 @@ async function runPerformanceTests( branches, options ) { // 4- Running the tests. log( '\n>> Running the tests' ); - const testSuites = [ 'post-editor', 'site-editor', 'front-end' ]; + const testSuites = [ + 'post-editor', + 'site-editor', + 'front-end-twentytwentyone', + 'front-end-twentytwentythree', + ]; /** @type {Record>} */ const results = {}; diff --git a/packages/e2e-tests/specs/performance/front-end.test.js b/packages/e2e-tests/specs/performance/front-end-twentytwentyone.test.js similarity index 100% rename from packages/e2e-tests/specs/performance/front-end.test.js rename to packages/e2e-tests/specs/performance/front-end-twentytwentyone.test.js diff --git a/packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js b/packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js new file mode 100644 index 00000000000000..c64695967137ac --- /dev/null +++ b/packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js @@ -0,0 +1,44 @@ +/** + * External dependencies + */ +import { basename, join } from 'path'; +import { writeFileSync } from 'fs'; + +/** + * WordPress dependencies + */ +import { activateTheme, createURL, logout } from '@wordpress/e2e-test-utils'; + +describe( 'Front End Performance', () => { + const results = { + timeToFirstByte: [], + }; + + beforeAll( async () => { + await activateTheme( 'twentytwentythree' ); + await logout(); + } ); + + afterAll( async () => { + await activateTheme( 'twentytwentyone' ); + const resultsFilename = basename( __filename, '.js' ) + '.results.json'; + writeFileSync( + join( __dirname, resultsFilename ), + JSON.stringify( results, null, 2 ) + ); + } ); + + it( 'Time To First Byte (TTFB)', async () => { + let i = 10; + while ( i-- ) { + await page.goto( createURL( '/' ) ); + const navigationTimingJson = await page.evaluate( () => + JSON.stringify( performance.getEntriesByType( 'navigation' ) ) + ); + const [ navigationTiming ] = JSON.parse( navigationTimingJson ); + results.timeToFirstByte.push( + navigationTiming.responseStart - navigationTiming.requestStart + ); + } + } ); +} ); From dfbff0290d5fe183cf595a50613763e31f3a98ee Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Tue, 17 Jan 2023 16:38:52 +0800 Subject: [PATCH 08/13] Add step to install specific versions of themes --- .github/workflows/performance.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 675642df3c26c9..24d61bbde09079 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -33,6 +33,11 @@ jobs: run: | npm ci + - name: Install specific versions of the themes used in tests + run: | + npm run wp-env -- run tests-cli "wp theme update twentytwentyone --version=1.7" + npm run wp-env -- run tests-cli "wp theme update twentytwentythree --version=1.0" + - name: Compare performance with trunk if: github.event_name == 'pull_request' run: ./bin/plugin/cli.js perf $GITHUB_SHA trunk --tests-branch $GITHUB_SHA From 0c02ea27818a245f39221904c5f62715effd8a74 Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Tue, 17 Jan 2023 17:56:53 +0800 Subject: [PATCH 09/13] Add wp-env start command --- .github/workflows/performance.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 24d61bbde09079..df41794ad58e8e 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -35,6 +35,7 @@ jobs: - name: Install specific versions of the themes used in tests run: | + npm run wp-env start npm run wp-env -- run tests-cli "wp theme update twentytwentyone --version=1.7" npm run wp-env -- run tests-cli "wp theme update twentytwentythree --version=1.0" From 5503617c78bb77a8ee6867460081f2799d9441b7 Mon Sep 17 00:00:00 2001 From: Sarah Norris Date: Tue, 17 Jan 2023 18:53:59 +0800 Subject: [PATCH 10/13] Try wp-env stop --- .github/workflows/performance.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index df41794ad58e8e..d7cbc72127ba55 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -38,6 +38,7 @@ jobs: npm run wp-env start npm run wp-env -- run tests-cli "wp theme update twentytwentyone --version=1.7" npm run wp-env -- run tests-cli "wp theme update twentytwentythree --version=1.0" + npm run wp-env stop - name: Compare performance with trunk if: github.event_name == 'pull_request' From 25d44808034d96c3c56cc7dc32797c9dfef8bf8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 25 Jan 2023 19:18:11 +0100 Subject: [PATCH 11/13] Calculate TTFB using startTime --- .../specs/performance/front-end-twentytwentyone.test.js | 2 +- .../specs/performance/front-end-twentytwentythree.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/e2e-tests/specs/performance/front-end-twentytwentyone.test.js b/packages/e2e-tests/specs/performance/front-end-twentytwentyone.test.js index 2e6bb7afc35199..5a834102848179 100644 --- a/packages/e2e-tests/specs/performance/front-end-twentytwentyone.test.js +++ b/packages/e2e-tests/specs/performance/front-end-twentytwentyone.test.js @@ -35,7 +35,7 @@ describe( 'Front End Performance', () => { ); const [ navigationTiming ] = JSON.parse( navigationTimingJson ); results.timeToFirstByte.push( - navigationTiming.responseStart - navigationTiming.requestStart + navigationTiming.responseStart - navigationTiming.startTime ); } } ); diff --git a/packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js b/packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js index c64695967137ac..2b82fbca4affb5 100644 --- a/packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js +++ b/packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js @@ -37,7 +37,7 @@ describe( 'Front End Performance', () => { ); const [ navigationTiming ] = JSON.parse( navigationTimingJson ); results.timeToFirstByte.push( - navigationTiming.responseStart - navigationTiming.requestStart + navigationTiming.responseStart - navigationTiming.startTime ); } } ); From 47f3a14bc2100b470d60903b11f3c4d463438f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 25 Jan 2023 19:44:40 +0100 Subject: [PATCH 12/13] Rename to classic & block theme --- bin/plugin/commands/performance.js | 10 +++++----- ...entythree.test.js => front-end-block-theme.test.js} | 5 ++++- ...entyone.test.js => front-end-classic-theme.test.js} | 5 ++++- 3 files changed, 13 insertions(+), 7 deletions(-) rename packages/e2e-tests/specs/performance/{front-end-twentytwentythree.test.js => front-end-block-theme.test.js} (83%) rename packages/e2e-tests/specs/performance/{front-end-twentytwentyone.test.js => front-end-classic-theme.test.js} (82%) diff --git a/bin/plugin/commands/performance.js b/bin/plugin/commands/performance.js index 554ea454d4cf6a..ceef55f6413ca4 100644 --- a/bin/plugin/commands/performance.js +++ b/bin/plugin/commands/performance.js @@ -127,11 +127,11 @@ function formatTime( number ) { */ function curateResults( testSuite, results ) { if ( - testSuite === 'front-end-twentytwentyone' || - testSuite === 'front-end-twentytwentythree' + testSuite === 'front-end-classic-theme' || + testSuite === 'front-end-block-theme' ) { return { - timeToFirstByte: average( results.timeToFirstByte ), + timeToFirstByte: median( results.timeToFirstByte ), }; } @@ -359,8 +359,8 @@ async function runPerformanceTests( branches, options ) { const testSuites = [ 'post-editor', 'site-editor', - 'front-end-twentytwentyone', - 'front-end-twentytwentythree', + 'front-end-classic-theme', + 'front-end-block-theme', ]; /** @type {Record>} */ diff --git a/packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js b/packages/e2e-tests/specs/performance/front-end-block-theme.test.js similarity index 83% rename from packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js rename to packages/e2e-tests/specs/performance/front-end-block-theme.test.js index 2b82fbca4affb5..2cd5b151353ede 100644 --- a/packages/e2e-tests/specs/performance/front-end-twentytwentythree.test.js +++ b/packages/e2e-tests/specs/performance/front-end-block-theme.test.js @@ -29,7 +29,10 @@ describe( 'Front End Performance', () => { } ); it( 'Time To First Byte (TTFB)', async () => { - let i = 10; + // We derive the 75th percentile of the TTFB based on these results. + // By running it 16 times, the percentile value would be (75/100)*16=12, + // meaning that we discard the worst 4 values. + let i = 16; while ( i-- ) { await page.goto( createURL( '/' ) ); const navigationTimingJson = await page.evaluate( () => diff --git a/packages/e2e-tests/specs/performance/front-end-twentytwentyone.test.js b/packages/e2e-tests/specs/performance/front-end-classic-theme.test.js similarity index 82% rename from packages/e2e-tests/specs/performance/front-end-twentytwentyone.test.js rename to packages/e2e-tests/specs/performance/front-end-classic-theme.test.js index 5a834102848179..134e356247e3dd 100644 --- a/packages/e2e-tests/specs/performance/front-end-twentytwentyone.test.js +++ b/packages/e2e-tests/specs/performance/front-end-classic-theme.test.js @@ -27,7 +27,10 @@ describe( 'Front End Performance', () => { } ); it( 'Time To First Byte (TTFB)', async () => { - let i = 5; + // We derive the 75th percentile of the TTFB based on these results. + // By running it 16 times, the percentile value would be (75/100)*16=12, + // meaning that we discard the worst 4 values. + let i = 16; while ( i-- ) { await page.goto( createURL( '/' ) ); const navigationTimingJson = await page.evaluate( () => From ebb4a1b13f82b18bffc11ce626fb60c01c3b3e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 25 Jan 2023 19:49:12 +0100 Subject: [PATCH 13/13] Calculate median and 75th percentile for TTFB --- bin/plugin/commands/performance.js | 73 ++++++++++++++++++------------ 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/bin/plugin/commands/performance.js b/bin/plugin/commands/performance.js index ceef55f6413ca4..82ba3a71d7f9d3 100644 --- a/bin/plugin/commands/performance.js +++ b/bin/plugin/commands/performance.js @@ -49,34 +49,35 @@ const config = require( '../config' ); /** * @typedef WPPerformanceResults * - * @property {number=} timeToFirstByte Represents the time since the browser started the request until it received a response. - * @property {number=} serverResponse Represents the time the server takes to respond. - * @property {number=} firstPaint Represents the time when the user agent first rendered after navigation. - * @property {number=} domContentLoaded Represents the time immediately after the document's DOMContentLoaded event completes. - * @property {number=} loaded Represents the time when the load event of the current document is completed. - * @property {number=} firstContentfulPaint Represents the time when the browser first renders any text or media. - * @property {number=} firstBlock Represents the time when Puppeteer first sees a block selector in the DOM. - * @property {number=} type Average type time. - * @property {number=} minType Minimum type time. - * @property {number=} maxType Maximum type time. - * @property {number=} typeContainer Average type time within a container. - * @property {number=} minTypeContainer Minimum type time within a container. - * @property {number=} maxTypeContainer Maximum type time within a container. - * @property {number=} focus Average block selection time. - * @property {number=} minFocus Min block selection time. - * @property {number=} maxFocus Max block selection time. - * @property {number=} inserterOpen Average time to open global inserter. - * @property {number=} minInserterOpen Min time to open global inserter. - * @property {number=} maxInserterOpen Max time to open global inserter. - * @property {number=} inserterSearch Average time to open global inserter. - * @property {number=} minInserterSearch Min time to open global inserter. - * @property {number=} maxInserterSearch Max time to open global inserter. - * @property {number=} inserterHover Average time to move mouse between two block item in the inserter. - * @property {number=} minInserterHover Min time to move mouse between two block item in the inserter. - * @property {number=} maxInserterHover Max time to move mouse between two block item in the inserter. - * @property {number=} listViewOpen Average time to open list view. - * @property {number=} minListViewOpen Min time to open list view. - * @property {number=} maxListViewOpen Max time to open list view. + * @property {number=} timeToFirstByteMedian Represents the time since the browser started the request until it received a response (median). + * @property {number=} timeToFirstByteP75 Represents the time since the browser started the request until it received a response (75th percentile). + * @property {number=} serverResponse Represents the time the server takes to respond. + * @property {number=} firstPaint Represents the time when the user agent first rendered after navigation. + * @property {number=} domContentLoaded Represents the time immediately after the document's DOMContentLoaded event completes. + * @property {number=} loaded Represents the time when the load event of the current document is completed. + * @property {number=} firstContentfulPaint Represents the time when the browser first renders any text or media. + * @property {number=} firstBlock Represents the time when Puppeteer first sees a block selector in the DOM. + * @property {number=} type Average type time. + * @property {number=} minType Minimum type time. + * @property {number=} maxType Maximum type time. + * @property {number=} typeContainer Average type time within a container. + * @property {number=} minTypeContainer Minimum type time within a container. + * @property {number=} maxTypeContainer Maximum type time within a container. + * @property {number=} focus Average block selection time. + * @property {number=} minFocus Min block selection time. + * @property {number=} maxFocus Max block selection time. + * @property {number=} inserterOpen Average time to open global inserter. + * @property {number=} minInserterOpen Min time to open global inserter. + * @property {number=} maxInserterOpen Max time to open global inserter. + * @property {number=} inserterSearch Average time to open global inserter. + * @property {number=} minInserterSearch Min time to open global inserter. + * @property {number=} maxInserterSearch Max time to open global inserter. + * @property {number=} inserterHover Average time to move mouse between two block item in the inserter. + * @property {number=} minInserterHover Min time to move mouse between two block item in the inserter. + * @property {number=} maxInserterHover Max time to move mouse between two block item in the inserter. + * @property {number=} listViewOpen Average time to open list view. + * @property {number=} minListViewOpen Min time to open list view. + * @property {number=} maxListViewOpen Max time to open list view. */ /** @@ -105,6 +106,19 @@ function median( array ) { : ( numbers[ mid - 1 ] + numbers[ mid ] ) / 2; } +/** + * Computes the 75th percentile from an array of numbers. + * + * @param {number[]} array + * + * @return {number} 75th percentile of the given dataset. + */ +function percentile75( array ) { + const ascending = array.sort( ( a, b ) => a - b ); + const position = Math.floor( ( 75 / 100 ) * array.length ); + return ascending[ position ]; +} + /** * Rounds and format a time passed in milliseconds. * @@ -131,7 +145,8 @@ function curateResults( testSuite, results ) { testSuite === 'front-end-block-theme' ) { return { - timeToFirstByte: median( results.timeToFirstByte ), + timeToFirstByteMedian: median( results.timeToFirstByte ), + timeToFirstByteP75: percentile75( results.timeToFirstByte ), }; }