@@ -54,9 +54,13 @@ test('restartWebUiServerAfterFrontendChange waits 3 seconds after stop before re
5454 const events = [ ] ;
5555 const nextServerHandle = { stop : async ( ) => { } } ;
5656 let resolveStop = null ;
57+ let resolveDelay = null ;
5758 const stopDone = new Promise ( ( resolve ) => {
5859 resolveStop = resolve ;
5960 } ) ;
61+ const delayDone = new Promise ( ( resolve ) => {
62+ resolveDelay = resolve ;
63+ } ) ;
6064 const currentServerHandle = {
6165 stop : ( ) => {
6266 events . push ( 'stop:start' ) ;
@@ -90,8 +94,9 @@ test('restartWebUiServerAfterFrontendChange waits 3 seconds after stop before re
9094 } ,
9195 wait : ( callback , ms ) => {
9296 events . push ( `wait:${ ms } ` ) ;
93- callback ( ) ;
94- return 1 ;
97+ return delayDone . then ( ( ) => {
98+ callback ( ) ;
99+ } ) ;
95100 } ,
96101 logger : {
97102 log : ( ) => { } ,
@@ -102,6 +107,10 @@ test('restartWebUiServerAfterFrontendChange waits 3 seconds after stop before re
102107
103108 assert . deepStrictEqual ( events , [ 'stop:start' ] ) ;
104109 resolveStop ( ) ;
110+ await Promise . resolve ( ) ;
111+ await Promise . resolve ( ) ;
112+ assert . deepStrictEqual ( events , [ 'stop:start' , 'stop:done' , 'wait:3000' ] ) ;
113+ resolveDelay ( ) ;
105114 const result = await pending ;
106115
107116 assert . strictEqual ( result , nextServerHandle ) ;
@@ -113,6 +122,40 @@ test('restartWebUiServerAfterFrontendChange waits 3 seconds after stop before re
113122 ] ) ;
114123} ) ;
115124
125+ test ( 'restartWebUiServerAfterFrontendChange catches async createServer failures' , async ( ) => {
126+ const currentServerHandle = { stop : async ( ) => { } } ;
127+ const loggedErrors = [ ] ;
128+
129+ const result = await restartWebUiServerAfterFrontendChange ( {
130+ serverHandle : currentServerHandle ,
131+ serverOptions : {
132+ htmlPath : '/tmp/index.html' ,
133+ assetsDir : '/tmp/res' ,
134+ webDir : '/tmp/web-ui' ,
135+ host : '127.0.0.1' ,
136+ port : 3737 ,
137+ openBrowser : false
138+ } ,
139+ createServer : async ( ) => {
140+ throw new Error ( 'async create failed' ) ;
141+ } ,
142+ wait : ( callback ) => {
143+ callback ( ) ;
144+ return 1 ;
145+ } ,
146+ logger : {
147+ log : ( ) => { } ,
148+ warn : ( ) => { } ,
149+ error : ( ...args ) => {
150+ loggedErrors . push ( args ) ;
151+ }
152+ }
153+ } ) ;
154+
155+ assert . strictEqual ( result , currentServerHandle ) ;
156+ assert . deepStrictEqual ( loggedErrors , [ [ '! 重启失败:' , 'async create failed' ] ] ) ;
157+ } ) ;
158+
116159test ( 'createSerializedWebUiRestartHandler coalesces overlapping restarts to the latest change' , async ( ) => {
117160 const events = [ ] ;
118161 let restartCount = 0 ;
@@ -151,3 +194,40 @@ test('createSerializedWebUiRestartHandler coalesces overlapping restarts to the
151194 'done:third.js'
152195 ] ) ;
153196} ) ;
197+
198+ test ( 'createSerializedWebUiRestartHandler chains queued callers to the retry after a failure' , async ( ) => {
199+ const events = [ ] ;
200+ let restartCount = 0 ;
201+ let rejectFirstRestart = null ;
202+ const firstRestartDone = new Promise ( ( _ , reject ) => {
203+ rejectFirstRestart = reject ;
204+ } ) ;
205+
206+ const requestRestart = createSerializedWebUiRestartHandler ( async ( info ) => {
207+ restartCount += 1 ;
208+ const label = info && info . filename ? info . filename : 'unknown' ;
209+ events . push ( `start:${ label } ` ) ;
210+ if ( restartCount === 1 ) {
211+ await firstRestartDone ;
212+ return ;
213+ }
214+ events . push ( `done:${ label } ` ) ;
215+ } ) ;
216+
217+ const first = requestRestart ( { filename : 'first.js' } ) ;
218+ const second = requestRestart ( { filename : 'second.js' } ) ;
219+
220+ await Promise . resolve ( ) ;
221+
222+ assert . strictEqual ( first , second ) ;
223+ assert . deepStrictEqual ( events , [ 'start:first.js' ] ) ;
224+
225+ rejectFirstRestart ( new Error ( 'first restart failed' ) ) ;
226+ await first ;
227+
228+ assert . deepStrictEqual ( events , [
229+ 'start:first.js' ,
230+ 'start:second.js' ,
231+ 'done:second.js'
232+ ] ) ;
233+ } ) ;
0 commit comments