@@ -340,6 +340,39 @@ describe('installing a CLI update', () => {
340340 expect ( output . join ( '' ) ) . not . toContain ( 'Updated Sim' )
341341 } )
342342
343+ it . each ( [ 'registry' , 'installer' ] ) (
344+ 'preserves the original %s failure when releasing the lock also fails' ,
345+ async ( phase ) => {
346+ const failure = new CliUpdateError ( `${ phase } permission denied` )
347+ const run = vi . fn ( ) . mockResolvedValueOnce ( join ( directory , 'node_modules' ) )
348+ if ( phase === 'installer' ) run . mockResolvedValueOnce ( JSON . stringify ( '2.1.5' ) )
349+ run . mockImplementationOnce ( async ( ) => {
350+ writeFileSync ( join ( `${ packageRoot } .lock` , 'obstruction' ) , '' )
351+ throw failure
352+ } )
353+
354+ await expect ( installUpdate ( { ...options ( ) , run } ) ) . rejects . toBe ( failure )
355+ expect ( output . join ( '' ) ) . toContain ( 'Cannot release the Sim update lock' )
356+ expect ( output . join ( '' ) ) . not . toContain ( 'Updated Sim' )
357+ }
358+ )
359+
360+ it ( 'fails with a CLI error when only releasing the lock fails' , async ( ) => {
361+ const run = vi
362+ . fn ( )
363+ . mockResolvedValueOnce ( join ( directory , 'node_modules' ) )
364+ . mockImplementationOnce ( async ( ) => {
365+ writeFileSync ( join ( `${ packageRoot } .lock` , 'obstruction' ) , '' )
366+ return JSON . stringify ( '2.1.2' )
367+ } )
368+
369+ await expect ( installUpdate ( { ...options ( ) , run } ) ) . rejects . toMatchObject ( {
370+ constructor : CliUpdateError ,
371+ message : expect . stringContaining ( 'Cannot release the Sim update lock' ) ,
372+ cause : expect . objectContaining ( { code : 'ENOTEMPTY' } ) ,
373+ } )
374+ } )
375+
343376 it . each ( [ 'invalid' , '2.1.5-dev.1.1' ] ) (
344377 'rejects an invalid or wrong-channel installed version: %s' ,
345378 async ( version ) => {
0 commit comments