@@ -20,6 +20,7 @@ interface Options {
20
20
tolerance : number ;
21
21
width : number ;
22
22
viewHeight : number ;
23
+ concurrency : number ;
23
24
summaryFile : string ;
24
25
}
25
26
@@ -31,6 +32,7 @@ function parseArgs(): Options {
31
32
tolerance : 0 ,
32
33
width : 1280 ,
33
34
viewHeight : 1024 ,
35
+ concurrency : 4 ,
34
36
summaryFile : "visual_diffs/results.json" ,
35
37
} ;
36
38
for ( let i = 0 ; i < args . length ; i ++ ) {
@@ -56,6 +58,10 @@ function parseArgs(): Options {
56
58
case "--view-height" :
57
59
opts . viewHeight = Number ( args [ ++ i ] ) ;
58
60
break ;
61
+ case "-c" :
62
+ case "--concurrency" :
63
+ opts . concurrency = Number ( args [ ++ i ] ) ;
64
+ break ;
59
65
case "-s" :
60
66
case "--summary-file" :
61
67
opts . summaryFile = args [ ++ i ] ;
@@ -125,36 +131,56 @@ function compareImages(
125
131
return true ;
126
132
}
127
133
134
+ async function promisePool < T > (
135
+ items : T [ ] ,
136
+ concurrency : number ,
137
+ iteratorFn : ( item : T ) => Promise < void >
138
+ ) {
139
+ const executing : Promise < void > [ ] = [ ] ;
140
+
141
+ for ( const item of items ) {
142
+ const p = iteratorFn ( item ) . then ( ( ) => {
143
+ executing . splice ( executing . indexOf ( p ) , 1 ) ;
144
+ } ) ;
145
+ executing . push ( p ) ;
146
+ if ( executing . length >= concurrency ) {
147
+ await Promise . race ( executing ) ;
148
+ }
149
+ }
150
+ await Promise . all ( executing ) ;
151
+ }
152
+
128
153
async function run ( ) {
129
154
const opts = parseArgs ( ) ;
130
155
if ( ! opts . previewUrl ) {
131
156
throw new Error ( "Missing preview URL" ) ;
132
157
}
133
158
if ( ! opts . previewUrl . endsWith ( "/" ) ) opts . previewUrl += "/" ;
134
159
135
- const sitemapXml = await fetchSitemap ( "https://docusaurus-openapi.tryingpan.dev/sitemap.xml" ) ;
160
+ const sitemapXml = await fetchSitemap (
161
+ "https://docusaurus-openapi.tryingpan.dev/sitemap.xml"
162
+ ) ;
136
163
const paths = parseUrlsFromSitemap ( await sitemapXml ) ;
137
164
console . log ( `Found ${ paths . length } paths.` ) ;
138
165
139
166
const browser = await chromium . launch ( ) ;
140
167
const context = await browser . newContext ( {
141
168
viewport : { width : opts . width , height : opts . viewHeight } ,
142
169
} ) ;
143
- const page = await context . newPage ( ) ;
144
-
145
170
let total = 0 ;
146
171
let matches = 0 ;
147
172
let mismatches = 0 ;
148
173
let skipped = 0 ;
149
174
const pages : { path : string ; status : string } [ ] = [ ] ;
150
175
151
- for ( const url of paths ) {
176
+ async function processPath ( url : string ) {
152
177
total += 1 ;
153
178
const cleanPath =
154
179
new URL ( url ) . pathname . replace ( / ^ \/ / , "" ) . replace ( / \/ $ / , "" ) || "root" ;
155
180
const prodSnap = path . join ( opts . outputDir , "prod" , `${ cleanPath } .png` ) ;
156
181
const prevSnap = path . join ( opts . outputDir , "preview" , `${ cleanPath } .png` ) ;
157
182
const diffImg = path . join ( opts . outputDir , "diff" , `${ cleanPath } .png` ) ;
183
+ const page = await context . newPage ( ) ;
158
184
try {
159
185
await screenshotFullPage ( page , url , prodSnap ) ;
160
186
await screenshotFullPage (
@@ -176,8 +202,11 @@ async function run() {
176
202
skipped += 1 ;
177
203
pages . push ( { path : `/${ cleanPath } ` , status : "skip" } ) ;
178
204
}
205
+ await page . close ( ) ;
179
206
}
180
207
208
+ await promisePool ( paths , opts . concurrency , processPath ) ;
209
+
181
210
await browser . close ( ) ;
182
211
console . log (
183
212
`Total: ${ total } , Matches: ${ matches } , Diffs: ${ mismatches } , Skipped: ${ skipped } `
0 commit comments