File tree 2 files changed +47
-2
lines changed
2 files changed +47
-2
lines changed Original file line number Diff line number Diff line change
1
+ import type { ServerResponse } from 'http'
1
2
import sinon , { type SinonSpy } from 'sinon'
2
3
3
4
import type { EventSourceClient } from '../src/types.js'
@@ -44,6 +45,47 @@ export function deferClose(es: EventSourceClient, timeout = 25): Promise<void> {
44
45
return new Promise ( ( resolve ) => setTimeout ( ( ) => resolve ( es . close ( ) ) , timeout ) )
45
46
}
46
47
48
+ export async function waitForClose ( res : ServerResponse ) : Promise < void > {
49
+ let resolve
50
+ let reject
51
+ const promise = new Promise < void > ( ( _resolve , _reject ) => {
52
+ resolve = _resolve
53
+ reject = _reject
54
+ } )
55
+
56
+ let hasTimedOut = false
57
+ res . once ( 'close' , ( ) => resolve ( ) )
58
+ const timeout = setTimeout ( ( ) => {
59
+ hasTimedOut = true
60
+ reject ( new Error ( 'Timeout waiting for close' ) )
61
+ } , 15000 )
62
+
63
+ if ( typeof globalThis . Deno === 'undefined' ) {
64
+ return promise
65
+ }
66
+
67
+ // Deno does not trigger close event, apparently, so we'll have to try to write,
68
+ // then catch the error that occurs upon a close
69
+ for ( ; ; ) {
70
+ if ( hasTimedOut ) {
71
+ return promise
72
+ }
73
+
74
+ try {
75
+ res . write ( ':\n' )
76
+ } catch ( err : unknown ) {
77
+ if ( err instanceof Error && err . message . includes ( 'cannot close or enqueue' ) ) {
78
+ clearTimeout ( timeout )
79
+ resolve ( )
80
+ return promise
81
+ }
82
+ throw err
83
+ }
84
+
85
+ await new Promise ( ( waitResolve ) => setTimeout ( waitResolve , 100 ) )
86
+ }
87
+ }
88
+
47
89
export function expect ( thing : unknown ) : {
48
90
toBe ( expected : unknown ) : void
49
91
toBeLessThan ( thanNum : number ) : void
Original file line number Diff line number Diff line change @@ -6,6 +6,7 @@ import {resolve as resolvePath} from 'node:path'
6
6
import esbuild from 'esbuild'
7
7
8
8
import { unicodeLines } from './fixtures.js'
9
+ import { waitForClose } from './helpers.js'
9
10
10
11
const isDeno = typeof globalThis . Deno !== 'undefined'
11
12
const idedListeners = new Map < string , Set < ServerResponse > > ( )
@@ -113,7 +114,7 @@ async function writeCounter(req: IncomingMessage, res: ServerResponse) {
113
114
res . end ( )
114
115
}
115
116
116
- function writeIdentifiedListeners ( req : IncomingMessage , res : ServerResponse ) {
117
+ async function writeIdentifiedListeners ( req : IncomingMessage , res : ServerResponse ) {
117
118
const url = new URL ( req . url || '/' , 'http://localhost' )
118
119
const id = url . searchParams . get ( 'id' )
119
120
if ( ! id ) {
@@ -137,7 +138,9 @@ function writeIdentifiedListeners(req: IncomingMessage, res: ServerResponse) {
137
138
} )
138
139
tryWrite ( res , formatEvent ( { data : '' , retry : 250 } ) )
139
140
tryWrite ( res , formatEvent ( { data : `${ idedListeners . size } ` } ) )
140
- res . on ( 'close' , ( ) => ( idedListeners . get ( id ) || new Set ( ) ) . delete ( res ) )
141
+
142
+ await waitForClose ( res )
143
+ ; ( idedListeners . get ( id ) || new Set ( ) ) . delete ( res )
141
144
return
142
145
}
143
146
You can’t perform that action at this time.
0 commit comments