@@ -253,45 +253,33 @@ describe("changeMcpEnabled", () => {
253253 expect ( hub . handleMcpEnabledChange . mock . calls ) . toEqual ( [ [ true ] , [ false ] ] )
254254 } )
255255
256- it ( "takes every save that gives up off the change again , while the shared change stays stalled" , async ( ) => {
256+ it ( "lets go of the signal of every save that gives up, while the shared change stays stalled" , async ( ) => {
257257 const { hub, releases } = createHub ( )
258- // The registrations of the saves are kept in sets: what is added to them, and taken out, is watched.
259- const isCaller = ( value : unknown ) =>
260- typeof value === "object" &&
261- value !== null &&
262- "resolve" in value &&
263- "reject" in value &&
264- typeof value . resolve === "function"
265- const added = vi . spyOn ( Set . prototype , "add" )
266- const deleted = vi . spyOn ( Set . prototype , "delete" )
267- try {
268- void changeMcpEnabled ( hub , true ) // stalled
269- const staying = changeMcpEnabled ( hub , false ) // a save that stays: it waits for the change behind it
270-
271- for ( let i = 0 ; i < 200 ; i ++ ) {
272- const giveUp = new AbortController ( )
273- const waiting = changeMcpEnabled ( hub , i % 2 === 0 , giveUp . signal ) // joins the running or the waiting one
274- const rejected = expect ( waiting ) . rejects . toThrow ( "gave up" )
275- giveUp . abort ( new Error ( "gave up" ) )
276- await rejected
277- }
278-
279- const registered = added . mock . calls . map ( ( [ value ] ) => value ) . filter ( isCaller )
280- const taken = new Set ( deleted . mock . calls . map ( ( [ value ] ) => value ) . filter ( isCaller ) )
281- // The 200 that gave up are all taken off; only the save that stayed (and the first call) are still registered.
282- expect ( registered . length ) . toBeGreaterThanOrEqual ( 200 )
283- expect ( registered . filter ( ( caller ) => ! taken . has ( caller ) ) . length ) . toBeLessThanOrEqual ( 2 )
284-
285- // And the change they gave up on goes on for the save that stayed.
286- releases [ 0 ] ( )
287- await vi . waitFor ( ( ) => expect ( releases ) . toHaveLength ( 2 ) )
288- releases [ 1 ] ( )
289- await expect ( staying ) . resolves . toBeUndefined ( )
290- expect ( hub . handleMcpEnabledChange . mock . calls ) . toEqual ( [ [ true ] , [ false ] ] )
291- } finally {
292- added . mockRestore ( )
293- deleted . mockRestore ( )
258+ void changeMcpEnabled ( hub , true ) // stalled
259+ const staying = changeMcpEnabled ( hub , false ) // a save that stays: it waits for the change behind it
260+
261+ for ( let i = 0 ; i < 200 ; i ++ ) {
262+ const giveUp = new AbortController ( )
263+ const add = vi . spyOn ( giveUp . signal , "addEventListener" )
264+ const remove = vi . spyOn ( giveUp . signal , "removeEventListener" )
265+ const waiting = changeMcpEnabled ( hub , i % 2 === 0 , giveUp . signal ) // joins the running or the waiting one
266+ const rejected = expect ( waiting ) . rejects . toThrow ( "gave up" )
267+ giveUp . abort ( new Error ( "gave up" ) )
268+ await rejected
269+
270+ // The listener that the save put on its signal is the one that was taken off again.
271+ const added = add . mock . calls . filter ( ( [ type ] ) => type === "abort" ) . map ( ( [ , listener ] ) => listener )
272+ const removed = remove . mock . calls . filter ( ( [ type ] ) => type === "abort" ) . map ( ( [ , listener ] ) => listener )
273+ expect ( added ) . toHaveLength ( 1 )
274+ expect ( removed ) . toEqual ( added )
294275 }
276+
277+ // And the change they gave up on goes on for the save that stayed.
278+ releases [ 0 ] ( )
279+ await vi . waitFor ( ( ) => expect ( releases ) . toHaveLength ( 2 ) )
280+ releases [ 1 ] ( )
281+ await expect ( staying ) . resolves . toBeUndefined ( )
282+ expect ( hub . handleMcpEnabledChange . mock . calls ) . toEqual ( [ [ true ] , [ false ] ] )
295283 } )
296284
297285 it ( "answers a save that gives up at once, while another save still waits for the same change, which goes on" , async ( ) => {
0 commit comments