@@ -9,7 +9,6 @@ import getPort from "get-port";
9
9
import stripIndent from "strip-indent" ;
10
10
import { sync as spawnSync , spawn } from "cross-spawn" ;
11
11
import type { JsonObject } from "type-fest" ;
12
- import { createRequestListener } from "@mjackson/node-fetch-server" ;
13
12
14
13
import {
15
14
type ServerBuild ,
@@ -26,6 +25,65 @@ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
26
25
const root = path . join ( __dirname , "../.." ) ;
27
26
const TMP_DIR = path . join ( root , ".tmp" , "integration" ) ;
28
27
28
+ export async function spawnTestServer ( {
29
+ command,
30
+ regex,
31
+ validate,
32
+ env = { } ,
33
+ cwd,
34
+ timeout = 20000 ,
35
+ } : {
36
+ command : string [ ] ;
37
+ regex : RegExp ;
38
+ validate ?: ( matches : RegExpMatchArray ) => void | Promise < void > ;
39
+ env ?: Record < string , string > ;
40
+ cwd ?: string ;
41
+ timeout ?: number ;
42
+ } ) : Promise < { stop : VoidFunction } > {
43
+ return new Promise ( ( accept , reject ) => {
44
+ let serverProcess = spawn ( command [ 0 ] , command . slice ( 1 ) , {
45
+ env : { ...process . env , ...env } ,
46
+ cwd,
47
+ stdio : "pipe" ,
48
+ } ) ;
49
+
50
+ let started = false ;
51
+ let stdout = "" ;
52
+ let rejectTimeout = setTimeout ( ( ) => {
53
+ reject ( new Error ( `Timed out waiting for server to start (${ timeout } ms)` ) ) ;
54
+ } , timeout ) ;
55
+
56
+ serverProcess . stderr . pipe ( process . stderr ) ;
57
+ serverProcess . stdout . on ( "data" , ( chunk : Buffer ) => {
58
+ if ( started ) return ;
59
+ let newChunk = chunk . toString ( ) ;
60
+ stdout += newChunk ;
61
+ let match = stdout . match ( regex ) ;
62
+ if ( match ) {
63
+ clearTimeout ( rejectTimeout ) ;
64
+ started = true ;
65
+
66
+ Promise . resolve ( validate ?.( match ) )
67
+ . then ( ( ) => {
68
+ accept ( {
69
+ stop : ( ) => {
70
+ serverProcess . kill ( ) ;
71
+ } ,
72
+ } ) ;
73
+ } )
74
+ . catch ( ( error : unknown ) => {
75
+ reject ( error ) ;
76
+ } ) ;
77
+ }
78
+ } ) ;
79
+
80
+ serverProcess . on ( "error" , ( error : unknown ) => {
81
+ clearTimeout ( rejectTimeout ) ;
82
+ reject ( error ) ;
83
+ } ) ;
84
+ } ) ;
85
+ }
86
+
29
87
export interface FixtureInit {
30
88
buildStdio ?: Writable ;
31
89
files ?: { [ filename : string ] : string } ;
@@ -230,66 +288,29 @@ export async function createAppFixture(fixture: Fixture, mode?: ServerMode) {
230
288
stop : VoidFunction ;
231
289
} > => {
232
290
if ( fixture . useReactRouterServe ) {
233
- return new Promise ( async ( accept , reject ) => {
234
- let port = await getPort ( ) ;
235
-
236
- let nodebin = process . argv [ 0 ] ;
237
- let serveProcess = spawn (
238
- nodebin ,
239
- [
240
- "node_modules/@react-router/serve/dist/cli.js" ,
241
- "build/server/index.js" ,
242
- ] ,
243
- {
244
- env : {
245
- ...process . env ,
246
- NODE_ENV : mode || "production" ,
247
- PORT : port . toFixed ( 0 ) ,
248
- } ,
249
- cwd : fixture . projectDir ,
250
- stdio : "pipe" ,
251
- }
252
- ) ;
253
- // Wait for `started at http://localhost:${port}` to be printed
254
- // and extract the port from it.
255
- let started = false ;
256
- let stdout = "" ;
257
- let rejectTimeout = setTimeout ( ( ) => {
258
- reject (
259
- new Error ( "Timed out waiting for react-router-serve to start" )
260
- ) ;
261
- } , 20000 ) ;
262
- serveProcess . stderr . pipe ( process . stderr ) ;
263
- serveProcess . stdout . on ( "data" , ( chunk ) => {
264
- if ( started ) return ;
265
- let newChunk = chunk . toString ( ) ;
266
- stdout += newChunk ;
267
- let match : RegExpMatchArray | null = stdout . match (
268
- / \[ r e a c t - r o u t e r - s e r v e \] h t t p : \/ \/ l o c a l h o s t : ( \d + ) \s /
269
- ) ;
270
- if ( match ) {
271
- clearTimeout ( rejectTimeout ) ;
272
- started = true ;
273
- let parsedPort = parseInt ( match [ 1 ] , 10 ) ;
274
-
275
- if ( port !== parsedPort ) {
276
- reject (
277
- new Error (
278
- `Expected react-router-serve to start on port ${ port } , but it started on port ${ parsedPort } `
279
- )
280
- ) ;
281
- return ;
282
- }
283
-
284
- accept ( {
285
- stop : ( ) => {
286
- serveProcess . kill ( ) ;
287
- } ,
288
- port,
289
- } ) ;
291
+ let port = await getPort ( ) ;
292
+ let { stop } = await spawnTestServer ( {
293
+ cwd : fixture . projectDir ,
294
+ command : [
295
+ process . argv [ 0 ] ,
296
+ "node_modules/@react-router/serve/dist/cli.js" ,
297
+ "build/server/index.js" ,
298
+ ] ,
299
+ env : {
300
+ NODE_ENV : mode || "production" ,
301
+ PORT : port . toFixed ( 0 ) ,
302
+ } ,
303
+ regex : / \[ r e a c t - r o u t e r - s e r v e \] h t t p : \/ \/ l o c a l h o s t : ( \d + ) \s / ,
304
+ validate : ( matches ) => {
305
+ let parsedPort = parseInt ( matches [ 1 ] , 10 ) ;
306
+ if ( port !== parsedPort ) {
307
+ throw new Error (
308
+ `Expected react-router-serve to start on port ${ port } , but it started on port ${ parsedPort } `
309
+ ) ;
290
310
}
291
- } ) ;
311
+ } ,
292
312
} ) ;
313
+ return { stop, port } ;
293
314
}
294
315
295
316
if ( fixture . isSpaMode ) {
@@ -334,21 +355,25 @@ export async function createAppFixture(fixture: Fixture, mode?: ServerMode) {
334
355
}
335
356
336
357
if ( fixture . templateName . includes ( "parcel" ) ) {
337
- return new Promise ( async ( accept ) => {
338
- let port = await getPort ( ) ;
339
- let app = express ( ) ;
340
- app . use ( express . static ( path . join ( fixture . projectDir , "public" ) ) ) ;
341
- app . use (
342
- "/client" ,
343
- express . static ( path . join ( fixture . projectDir , "build/client" ) )
344
- ) ;
345
-
346
- app . all ( "*" , createRequestListener ( fixture . handler ) ) ;
347
-
348
- let server = app . listen ( port ) ;
349
-
350
- accept ( { stop : server . close . bind ( server ) , port } ) ;
358
+ let port = await getPort ( ) ;
359
+ let { stop } = await spawnTestServer ( {
360
+ cwd : fixture . projectDir ,
361
+ command : [ process . argv [ 0 ] , "start.js" ] ,
362
+ env : {
363
+ NODE_ENV : mode || "production" ,
364
+ PORT : port . toFixed ( 0 ) ,
365
+ } ,
366
+ regex : / S e r v e r l i s t e n i n g o n p o r t ( \d + ) \s / ,
367
+ validate : ( matches ) => {
368
+ let parsedPort = parseInt ( matches [ 1 ] , 10 ) ;
369
+ if ( port !== parsedPort ) {
370
+ throw new Error (
371
+ `Expected Parcel build server to start on port ${ port } , but it started on port ${ parsedPort } `
372
+ ) ;
373
+ }
374
+ } ,
351
375
} ) ;
376
+ return { stop, port } ;
352
377
}
353
378
354
379
const build = fixture . build ;
0 commit comments