@@ -7,6 +7,35 @@ import jimp from 'jimp';
77import * as fs from 'fs/promises' ;
88import fetch from 'node-fetch' ;
99
10+ class PromiseQueue {
11+
12+ constructor ( func , ...args ) {
13+
14+ this . func = func . bind ( this , ...args ) ;
15+ this . promises = [ ] ;
16+
17+ }
18+
19+ add ( ...args ) {
20+
21+ const promise = this . func ( ...args ) ;
22+ this . promises . push ( promise ) ;
23+ promise . then ( ( ) => this . promises . splice ( this . promises . indexOf ( promise ) , 1 ) ) ;
24+
25+ }
26+
27+ async waitForAll ( ) {
28+
29+ while ( this . promises . length > 0 ) {
30+
31+ await Promise . all ( this . promises ) ;
32+
33+ }
34+
35+ }
36+
37+ }
38+
1039/* CONFIG VARIABLES START */
1140
1241const idleTime = 9 ; // 9 seconds - for how long there should be no network requests
@@ -42,6 +71,8 @@ const exceptionList = [
4271
4372 // Unknown
4473 // TODO: most of these can be fixed just by increasing idleTime and parseTime
74+ 'webgl_animation_skinning_blending' ,
75+ 'webgl_buffergeometry_glbufferattribute' ,
4576 'webgl_clipping_advanced' ,
4677 'webgl_lensflares' ,
4778 'webgl_lines_sphere' ,
@@ -53,8 +84,10 @@ const exceptionList = [
5384 'webgl_morphtargets_face' ,
5485 'webgl_nodes_materials_standard' ,
5586 'webgl_postprocessing_crossfade' ,
87+ 'webgl_postprocessing_dof2' ,
5688 'webgl_raymarching_reflect' ,
5789 'webgl_renderer_pathtracer' ,
90+ 'webgl_shadowmap' ,
5891 'webgl_shadowmap_progressive' ,
5992 'webgl_test_memory2' ,
6093 'webgl_tiled_forward'
@@ -78,12 +111,14 @@ const port = 1234;
78111const pixelThreshold = 0.1 ; // threshold error in one pixel
79112const maxDifferentPixels = 0.3 ; // at most 0.3% different pixels
80113
81- const networkTimeout = 90 ; // 90 seconds , set to 0 to disable
82- const renderTimeout = 4. 5; // 4. 5 seconds, set to 0 to disable
114+ const networkTimeout = 5 ; // 5 minutes , set to 0 to disable
115+ const renderTimeout = 5 ; // 5 seconds, set to 0 to disable
83116
84117const numAttempts = 2 ; // perform 2 attempts before failing
85118
86- const numCIJobs = 8 ; // GitHub Actions run the script in 8 threads
119+ const numPages = 8 ; // use 8 browser pages
120+
121+ const numCIJobs = 4 ; // GitHub Actions run the script in 4 threads
87122
88123const width = 400 ;
89124const height = 250 ;
@@ -177,21 +212,26 @@ async function main() {
177212 const injection = await fs . readFile ( 'test/e2e/deterministic-injection.js' , 'utf8' ) ;
178213 const build = ( await fs . readFile ( 'build/three.module.js' , 'utf8' ) ) . replace ( / M a t h \. r a n d o m \( \) \* 0 x f f f f f f f f / g, 'Math._random() * 0xffffffff' ) ;
179214
180- /* Prepare page */
215+ /* Prepare pages */
181216
182217 const errorMessagesCache = [ ] ;
183218
184- const page = ( await browser . pages ( ) ) [ 0 ] ;
185- await preparePage ( page , injection , build , errorMessagesCache ) ;
219+ const pages = await browser . pages ( ) ;
220+ while ( pages . length < numPages && pages . length < files . length ) pages . push ( await browser . newPage ( ) ) ;
221+
222+ for ( const page of pages ) await preparePage ( page , injection , build , errorMessagesCache ) ;
186223
187224 /* Loop for each file */
188225
189226 const failedScreenshots = [ ] ;
190227
191- for ( const file of files ) await makeAttempt ( page , failedScreenshots , cleanPage , isMakeScreenshot , file ) ;
228+ const queue = new PromiseQueue ( makeAttempt , pages , failedScreenshots , cleanPage , isMakeScreenshot ) ;
229+ for ( const file of files ) queue . add ( file ) ;
230+ await queue . waitForAll ( ) ;
192231
193232 /* Finish */
194233
234+ failedScreenshots . sort ( ) ;
195235 const list = failedScreenshots . join ( ' ' ) ;
196236
197237 if ( isMakeScreenshot && failedScreenshots . length ) {
@@ -281,7 +321,7 @@ async function preparePage( page, injection, build, errorMessages ) {
281321 const args = await Promise . all ( msg . args ( ) . map ( async arg => {
282322 try {
283323 return await arg . executionContext ( ) . evaluate ( arg => arg instanceof Error ? arg . message : arg , arg ) ;
284- } catch ( e ) { // Execution context might have been already destroyed
324+ } catch ( e ) { // Execution context might have been already destroyed
285325 return arg ;
286326 }
287327 } ) ) ;
@@ -293,9 +333,9 @@ async function preparePage( page, injection, build, errorMessages ) {
293333
294334 text = file + ': ' + text . replace ( / \[ \. W e b G L - ( .+ ?) \] / g, '' ) ;
295335
296- if ( errorMessages . includes ( text ) ) {
336+ if ( text === ` ${ file } : JSHandle@error` ) {
297337
298- return ;
338+ text = ` ${ file } : Unknown error` ;
299339
300340 }
301341
@@ -305,6 +345,12 @@ async function preparePage( page, injection, build, errorMessages ) {
305345
306346 }
307347
348+ if ( errorMessages . includes ( text ) ) {
349+
350+ return ;
351+
352+ }
353+
308354 errorMessages . push ( text ) ;
309355
310356 if ( type === 'warning' ) {
@@ -353,11 +399,31 @@ async function preparePage( page, injection, build, errorMessages ) {
353399
354400}
355401
356- async function makeAttempt ( page , failedScreenshots , cleanPage , isMakeScreenshot , file , attemptID = 0 ) {
402+ async function makeAttempt ( pages , failedScreenshots , cleanPage , isMakeScreenshot , file , attemptID = 0 ) {
403+
404+ const page = await new Promise ( ( resolve , reject ) => {
405+
406+ const interval = setInterval ( ( ) => {
407+
408+ for ( const page of pages ) {
409+
410+ if ( page . file === undefined ) {
411+
412+ page . file = file ; // acquire lock
413+ clearInterval ( interval ) ;
414+ resolve ( page ) ;
415+ break ;
416+
417+ }
418+
419+ }
420+
421+ } , 100 ) ;
422+
423+ } ) ;
357424
358425 try {
359426
360- page . file = file ;
361427 page . pageSize = 0 ;
362428 page . error = undefined ;
363429
@@ -367,7 +433,7 @@ async function makeAttempt( page, failedScreenshots, cleanPage, isMakeScreenshot
367433
368434 await page . goto ( `http://localhost:${ port } /examples/${ file } .html` , {
369435 waitUntil : 'networkidle0' ,
370- timeout : networkTimeout * 1000
436+ timeout : networkTimeout * 60000
371437 } ) ;
372438
373439 } catch ( e ) {
@@ -383,7 +449,7 @@ async function makeAttempt( page, failedScreenshots, cleanPage, isMakeScreenshot
383449 await page . evaluate ( cleanPage ) ;
384450
385451 await page . waitForNetworkIdle ( {
386- timeout : networkTimeout * 1000 ,
452+ timeout : networkTimeout * 60000 ,
387453 idleTime : idleTime * 1000
388454 } ) ;
389455
@@ -431,7 +497,7 @@ async function makeAttempt( page, failedScreenshots, cleanPage, isMakeScreenshot
431497
432498 console.yellow( `Render timeout exceeded in file ${ file }` );
433499
434- } */
500+ } */ // TODO: fix this
435501
436502 }
437503
@@ -507,12 +573,14 @@ async function makeAttempt( page, failedScreenshots, cleanPage, isMakeScreenshot
507573 } else {
508574
509575 console . yellow ( `${ e } , another attempt...` ) ;
510- await makeAttempt ( page , failedScreenshots , cleanPage , isMakeScreenshot , file , attemptID + 1 ) ;
576+ this . add ( file , attemptID + 1 ) ;
511577
512578 }
513579
514580 }
515581
582+ page . file = undefined ; // release lock
583+
516584}
517585
518586function close ( exitCode = 1 ) {
0 commit comments