7
7
* - https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/supertest/index.d.ts
8
8
*/
9
9
10
- import type { ListenerLike , ServerLike } from "./types.ts" ;
11
- import { assertEquals , STATUS_TEXT , StatusCode } from "../deps.ts" ;
10
+ import type {
11
+ ExpressListenerLike ,
12
+ ExpressServerLike ,
13
+ ListenerLike ,
14
+ ServerLike ,
15
+ } from "./types.ts" ;
16
+ import { assertEquals , getFreePort , STATUS_TEXT , StatusCode } from "../deps.ts" ;
12
17
import { superagent } from "./superagent.ts" ;
13
18
import { close } from "./close.ts" ;
14
- import { isListener , isServer , isStdNativeServer , isString } from "./utils.ts" ;
19
+ import {
20
+ isExpressListener ,
21
+ isExpressServer ,
22
+ isListener ,
23
+ isServer ,
24
+ isStdNativeServer ,
25
+ isString ,
26
+ } from "./utils.ts" ;
15
27
import { exposeSham } from "./xhrSham.js" ;
16
28
29
+ export function random ( min : number , max : number ) : number {
30
+ return Math . round ( Math . random ( ) * ( max - min ) ) + min ;
31
+ }
32
+
17
33
/**
18
34
* Custom expectation checker.
19
35
*/
@@ -201,9 +217,11 @@ export class Test extends SuperRequest {
201
217
#redirects: number ;
202
218
#redirectList: string [ ] ;
203
219
#server! : ServerLike ;
220
+ #serverSetupPromise: Promise < void > ;
221
+ #urlSetupPromise: Promise < void > ;
204
222
205
223
public app : string | ListenerLike | ServerLike ;
206
- public url : string ;
224
+ public url ! : string ;
207
225
208
226
constructor (
209
227
app : string | ListenerLike | ServerLike ,
@@ -220,8 +238,21 @@ export class Test extends SuperRequest {
220
238
this . app = app ;
221
239
this . #asserts = [ ] ;
222
240
241
+ let serverSetupPromiseResolver ! : ( ) => void ;
242
+ let addressSetupPromiseResolver ! : ( ) => void ;
243
+
244
+ this . #serverSetupPromise = new Promise < void > ( ( resolve ) => {
245
+ serverSetupPromiseResolver = resolve ;
246
+ } ) ;
247
+ this . #urlSetupPromise = new Promise < void > ( ( resolve ) => {
248
+ addressSetupPromiseResolver = resolve ;
249
+ } ) ;
250
+
223
251
if ( isString ( app ) ) {
224
252
this . url = `${ app } ${ path } ` ;
253
+
254
+ serverSetupPromiseResolver ( ) ;
255
+ addressSetupPromiseResolver ( ) ;
225
256
} else {
226
257
if ( isStdNativeServer ( app ) ) {
227
258
const listenAndServePromise = app . listenAndServe ( ) . catch ( ( err ) =>
@@ -240,18 +271,60 @@ export class Test extends SuperRequest {
240
271
addrs : app . addrs ,
241
272
async listenAndServe ( ) { } ,
242
273
} ;
274
+
275
+ serverSetupPromiseResolver ( ) ;
276
+ } else if ( isExpressServer ( app ) ) {
277
+ this . #server = app as ExpressServerLike ;
278
+
279
+ const expressResolver = async ( ) => {
280
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1 ) ) ;
281
+ serverSetupPromiseResolver ( ) ;
282
+ } ;
283
+
284
+ if ( ! this . #server. listening ) {
285
+ ( this . #server as ExpressServerLike ) . once (
286
+ "listening" ,
287
+ expressResolver ,
288
+ ) ;
289
+ } else {
290
+ expressResolver ( ) ;
291
+ }
243
292
} else if ( isServer ( app ) ) {
244
293
this . #server = app as ServerLike ;
294
+
295
+ serverSetupPromiseResolver ( ) ;
296
+ } else if ( isExpressListener ( app ) ) {
297
+ secure = false ;
298
+
299
+ const expressResolver = async ( ) => {
300
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1 ) ) ;
301
+ serverSetupPromiseResolver ( ) ;
302
+ } ;
303
+
304
+ getFreePort ( random ( 1024 , 49151 ) ) . then (
305
+ ( freePort ) => {
306
+ this . #server = ( app as ExpressListenerLike ) . listen (
307
+ freePort ,
308
+ expressResolver ,
309
+ ) ;
310
+ } ,
311
+ ) ;
245
312
} else if ( isListener ( app ) ) {
246
313
secure = false ;
314
+
247
315
this . #server = ( app as ListenerLike ) . listen ( ":0" ) ;
316
+
317
+ serverSetupPromiseResolver ( ) ;
248
318
} else {
319
+ serverSetupPromiseResolver ( ) ;
320
+ addressSetupPromiseResolver ( ) ;
321
+
249
322
throw new Error (
250
323
"superdeno is unable to identify or create a valid test server" ,
251
324
) ;
252
325
}
253
326
254
- this . url = this . #serverAddress ( path , host , secure ) ;
327
+ this . #setServerAddress ( addressSetupPromiseResolver , path , host , secure ) ;
255
328
}
256
329
}
257
330
@@ -265,19 +338,28 @@ export class Test extends SuperRequest {
265
338
* @returns {string } URL address
266
339
* @private
267
340
*/
268
- #serverAddress = (
341
+ #setServerAddress = async (
342
+ addressSetupPromiseResolver : ( ) => void ,
269
343
path : string ,
270
344
host ?: string ,
271
345
secure ?: boolean ,
272
346
) => {
347
+ await this . #serverSetupPromise;
348
+
273
349
const address =
274
350
( "addrs" in this . #server
275
351
? this . #server. addrs [ 0 ]
352
+ : "address" in this . #server
353
+ ? this . #server. address ( )
276
354
: this . #server. listener . addr ) as Deno . NetAddr ;
355
+
277
356
const port = address . port ;
278
357
const protocol = secure ? "https" : "http" ;
358
+ const url = `${ protocol } ://${ ( host || "127.0.0.1" ) } :${ port } ${ path } ` ;
279
359
280
- return `${ protocol } ://${ ( host || "127.0.0.1" ) } :${ port } ${ path } ` ;
360
+ this . url = url ;
361
+
362
+ addressSetupPromiseResolver ( ) ;
281
363
} ;
282
364
283
365
/**
@@ -455,29 +537,33 @@ export class Test extends SuperRequest {
455
537
* @public
456
538
*/
457
539
end ( callback ?: CallbackHandler ) : this {
458
- const self = this ;
459
- const end = SuperRequest . prototype . end ;
460
-
461
- end . call (
462
- self ,
463
- function ( err : any , res : any ) {
464
- // Before we close, ensure that we have handled all
465
- // requested redirects
466
- const redirect = isRedirect ( res ?. statusCode ) ;
467
- const max : number = ( self as any ) . _maxRedirects ;
468
-
469
- if ( redirect && self . #redirects++ !== max ) {
470
- return self . #redirect( res , callback ) ;
471
- }
540
+ Promise . allSettled ( [ this . #serverSetupPromise, this . #urlSetupPromise] ) . then (
541
+ ( ) => {
542
+ const self = this ;
543
+ const end = SuperRequest . prototype . end ;
544
+
545
+ end . call (
546
+ self ,
547
+ function ( err : any , res : any ) {
548
+ // Before we close, ensure that we have handled all
549
+ // requested redirects
550
+ const redirect = isRedirect ( res ?. statusCode ) ;
551
+ const max : number = ( self as any ) . _maxRedirects ;
552
+
553
+ if ( redirect && self . #redirects++ !== max ) {
554
+ return self . #redirect( res , callback ) ;
555
+ }
472
556
473
- return close ( self . #server, self . app , undefined , async ( ) => {
474
- await completeXhrPromises ( ) ;
557
+ return close ( self . #server, self . app , undefined , async ( ) => {
558
+ await completeXhrPromises ( ) ;
475
559
476
- // REF: https://github.com/denoland/deno/blob/987716798fb3bddc9abc7e12c25a043447be5280/ext/timers/01_timers.js#L353
477
- await new Promise ( ( resolve ) => setTimeout ( resolve , 20 ) ) ;
560
+ // REF: https://github.com/denoland/deno/blob/987716798fb3bddc9abc7e12c25a043447be5280/ext/timers/01_timers.js#L353
561
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 20 ) ) ;
478
562
479
- self . #assert( err , res , callback ) ;
480
- } ) ;
563
+ self . #assert( err , res , callback ) ;
564
+ } ) ;
565
+ } ,
566
+ ) ;
481
567
} ,
482
568
) ;
483
569
0 commit comments