@@ -8,25 +8,51 @@ import * as babelPresetEnv from '@babel/preset-env';
88import * as babelPresetReact from '@babel/preset-react' ;
99
1010type PerformanceResults = {
11- renderTime : number ;
11+ renderTime : number [ ] ;
1212 webVitals : {
13- cls : number ;
14- lcp : number ;
15- inp : number ;
16- fid : number ;
17- ttfb : number ;
13+ cls : number [ ] ;
14+ lcp : number [ ] ;
15+ inp : number [ ] ;
16+ fid : number [ ] ;
17+ ttfb : number [ ] ;
1818 } ;
1919 reactProfiler : {
20- id : number ;
21- phase : number ;
22- actualDuration : number ;
23- baseDuration : number ;
24- startTime : number ;
25- commitTime : number ;
20+ id : number [ ] ;
21+ phase : number [ ] ;
22+ actualDuration : number [ ] ;
23+ baseDuration : number [ ] ;
24+ startTime : number [ ] ;
25+ commitTime : number [ ] ;
2626 } ;
2727 error : Error | null ;
2828} ;
2929
30+ type EvaluationResults = {
31+ renderTime : number | null ;
32+ webVitals : {
33+ cls : number | null ;
34+ lcp : number | null ;
35+ inp : number | null ;
36+ fid : number | null ;
37+ ttfb : number | null ;
38+ } ;
39+ reactProfiler : {
40+ id : number | null ;
41+ phase : number | null ;
42+ actualDuration : number | null ;
43+ baseDuration : number | null ;
44+ startTime : number | null ;
45+ commitTime : number | null ;
46+ } ;
47+ error : Error | null ;
48+ } ;
49+
50+ function delay ( time : number ) {
51+ return new Promise ( function ( resolve ) {
52+ setTimeout ( resolve , time ) ;
53+ } ) ;
54+ }
55+
3056export async function measurePerformance (
3157 code : string ,
3258 iterations : number ,
@@ -72,21 +98,21 @@ export async function measurePerformance(
7298 const html = buildHtml ( transpiled ) ;
7399
74100 let performanceResults : PerformanceResults = {
75- renderTime : 0 ,
101+ renderTime : [ ] ,
76102 webVitals : {
77- cls : 0 ,
78- lcp : 0 ,
79- inp : 0 ,
80- fid : 0 ,
81- ttfb : 0 ,
103+ cls : [ ] ,
104+ lcp : [ ] ,
105+ inp : [ ] ,
106+ fid : [ ] ,
107+ ttfb : [ ] ,
82108 } ,
83109 reactProfiler : {
84- id : 0 ,
85- phase : 0 ,
86- actualDuration : 0 ,
87- baseDuration : 0 ,
88- startTime : 0 ,
89- commitTime : 0 ,
110+ id : [ ] ,
111+ phase : [ ] ,
112+ actualDuration : [ ] ,
113+ baseDuration : [ ] ,
114+ startTime : [ ] ,
115+ commitTime : [ ] ,
90116 } ,
91117 error : null ,
92118 } ;
@@ -96,38 +122,73 @@ export async function measurePerformance(
96122 await page . waitForFunction (
97123 'window.__RESULT__ !== undefined && (window.__RESULT__.renderTime !== null || window.__RESULT__.error !== null)' ,
98124 ) ;
125+
99126 // ui chaos monkey
100- await page . waitForFunction ( `window.__RESULT__ !== undefined && (function() {
101- for (const el of [...document.querySelectorAll('a'), ...document.querySelectorAll('button')]) {
102- console.log(el);
103- el.click();
127+ const selectors = await page . evaluate ( ( ) => {
128+ window . __INTERACTABLE_SELECTORS__ = [ ] ;
129+ const elements = Array . from ( document . querySelectorAll ( 'a' ) ) . concat (
130+ Array . from ( document . querySelectorAll ( 'button' ) ) ,
131+ ) ;
132+ for ( const el of elements ) {
133+ window . __INTERACTABLE_SELECTORS__ . push ( el . tagName . toLowerCase ( ) ) ;
104134 }
105- return true;
106- })() ` ) ;
107- const evaluationResult : PerformanceResults = await page . evaluate ( ( ) => {
135+ return window . __INTERACTABLE_SELECTORS__ ;
136+ } ) ;
137+
138+ await Promise . all (
139+ selectors . map ( async ( selector : string ) => {
140+ try {
141+ await page . click ( selector ) ;
142+ } catch ( e ) {
143+ console . log ( `warning: Could not click ${ selector } : ${ e . message } ` ) ;
144+ }
145+ } ) ,
146+ ) ;
147+ await delay ( 500 ) ;
148+
149+ // Visit a new page for 1s to background the current page so that WebVitals can finish being calculated
150+ const tempPage = await browser . newPage ( ) ;
151+ await tempPage . evaluate ( ( ) => {
152+ return new Promise ( resolve => {
153+ setTimeout ( ( ) => {
154+ resolve ( true ) ;
155+ } , 1000 ) ;
156+ } ) ;
157+ } ) ;
158+ await tempPage . close ( ) ;
159+
160+ const evaluationResult : EvaluationResults = await page . evaluate ( ( ) => {
108161 return ( window as any ) . __RESULT__ ;
109162 } ) ;
110163
111- // TODO: investigate why webvital metrics are not populating correctly
112- performanceResults . renderTime += evaluationResult . renderTime ;
113- performanceResults . webVitals . cls += evaluationResult . webVitals . cls || 0 ;
114- performanceResults . webVitals . lcp += evaluationResult . webVitals . lcp || 0 ;
115- performanceResults . webVitals . inp += evaluationResult . webVitals . inp || 0 ;
116- performanceResults . webVitals . fid += evaluationResult . webVitals . fid || 0 ;
117- performanceResults . webVitals . ttfb += evaluationResult . webVitals . ttfb || 0 ;
118-
119- performanceResults . reactProfiler . id +=
120- evaluationResult . reactProfiler . actualDuration || 0 ;
121- performanceResults . reactProfiler . phase +=
122- evaluationResult . reactProfiler . phase || 0 ;
123- performanceResults . reactProfiler . actualDuration +=
124- evaluationResult . reactProfiler . actualDuration || 0 ;
125- performanceResults . reactProfiler . baseDuration +=
126- evaluationResult . reactProfiler . baseDuration || 0 ;
127- performanceResults . reactProfiler . startTime +=
128- evaluationResult . reactProfiler . startTime || 0 ;
129- performanceResults . reactProfiler . commitTime +=
130- evaluationResult . reactProfiler . commitTime || 0 ;
164+ if ( evaluationResult . renderTime !== null ) {
165+ performanceResults . renderTime . push ( evaluationResult . renderTime ) ;
166+ }
167+
168+ const webVitalMetrics = [ 'cls' , 'lcp' , 'inp' , 'fid' , 'ttfb' ] as const ;
169+ for ( const metric of webVitalMetrics ) {
170+ if ( evaluationResult . webVitals [ metric ] !== null ) {
171+ performanceResults . webVitals [ metric ] . push (
172+ evaluationResult . webVitals [ metric ] ,
173+ ) ;
174+ }
175+ }
176+
177+ const profilerMetrics = [
178+ 'id' ,
179+ 'phase' ,
180+ 'actualDuration' ,
181+ 'baseDuration' ,
182+ 'startTime' ,
183+ 'commitTime' ,
184+ ] as const ;
185+ for ( const metric of profilerMetrics ) {
186+ if ( evaluationResult . reactProfiler [ metric ] !== null ) {
187+ performanceResults . reactProfiler [ metric ] . push (
188+ evaluationResult . reactProfiler [ metric ] ,
189+ ) ;
190+ }
191+ }
131192
132193 performanceResults . error = evaluationResult . error ;
133194 }
@@ -159,14 +220,14 @@ function buildHtml(transpiled: string) {
159220 renderTime: null,
160221 webVitals: {},
161222 reactProfiler: {},
162- error: null
223+ error: null,
163224 };
164225
165- webVitals.onCLS((metric ) => { window.__RESULT__.webVitals.cls = metric ; });
166- webVitals.onLCP((metric ) => { window.__RESULT__.webVitals.lcp = metric ; });
167- webVitals.onINP((metric ) => { window.__RESULT__.webVitals.inp = metric ; });
168- webVitals.onFID((metric ) => { window.__RESULT__.webVitals.fid = metric ; });
169- webVitals.onTTFB((metric ) => { window.__RESULT__.webVitals.ttfb = metric ; });
226+ webVitals.onCLS(({value} ) => { window.__RESULT__.webVitals.cls = value ; });
227+ webVitals.onLCP(({value} ) => { window.__RESULT__.webVitals.lcp = value ; });
228+ webVitals.onINP(({value} ) => { window.__RESULT__.webVitals.inp = value ; });
229+ webVitals.onFID(({value} ) => { window.__RESULT__.webVitals.fid = value ; });
230+ webVitals.onTTFB(({value} ) => { window.__RESULT__.webVitals.ttfb = value ; });
170231
171232 try {
172233 ${ transpiled }
0 commit comments