@@ -174,4 +174,104 @@ describe('org:logout', () => {
174174 expect ( ( e as Error ) . message ) . to . include ( 'No authenticated org found' ) ;
175175 }
176176 } ) ;
177+
178+ describe ( 'batch processing' , ( ) => {
179+ beforeEach ( ( ) => {
180+ authRemoverSpy = $$ . SANDBOX . spy ( AuthRemover . prototype , 'removeAuth' ) ;
181+ stubUx ( $$ . SANDBOX ) ;
182+ } ) ;
183+
184+ it ( 'should process removals in batches of 10' , async ( ) => {
185+ // Create 25 test orgs to test batch processing
186+ const testOrgs = Array . from ( { length : 25 } , ( ) => new MockTestOrgData ( ) ) ;
187+ await $$ . stubAuths ( ...testOrgs ) ;
188+ $$ . setConfigStubContents ( 'Config' , { contents : { } } ) ;
189+
190+ const response = await Logout . run ( [ '-p' , '-a' , '--json' ] ) ;
191+ expect ( response ) . to . have . length ( 25 ) ;
192+ expect ( authRemoverSpy . callCount ) . to . equal ( 25 ) ;
193+ // Verify all usernames are in the response
194+ const usernames = testOrgs . map ( ( org ) => org . username ) ;
195+ expect ( response ) . to . have . members ( usernames ) ;
196+ } ) ;
197+
198+ it ( 'should handle exactly 10 orgs in a single batch' , async ( ) => {
199+ const testOrgs = Array . from ( { length : 10 } , ( ) => new MockTestOrgData ( ) ) ;
200+ await $$ . stubAuths ( ...testOrgs ) ;
201+ $$ . setConfigStubContents ( 'Config' , { contents : { } } ) ;
202+
203+ const response = await Logout . run ( [ '-p' , '-a' , '--json' ] ) ;
204+ expect ( response ) . to . have . length ( 10 ) ;
205+ expect ( authRemoverSpy . callCount ) . to . equal ( 10 ) ;
206+ } ) ;
207+ } ) ;
208+
209+ describe ( 'ELOCKED error handling' , ( ) => {
210+ it ( 'should enrich ELOCKED error with file information' , async ( ) => {
211+ await prepareStubs ( { 'target-org' : testOrg1 . username } ) ;
212+ const lockedFile = '/path/to/alias.json' ;
213+ // Create an error that mimics proper-lockfile ELOCKED error structure
214+ const elockedError = Object . assign ( new Error ( 'Lock file is already being held' ) , {
215+ code : 'ELOCKED' ,
216+ file : lockedFile ,
217+ } ) ;
218+
219+ // Stub removeAuth to throw ELOCKED error
220+ authRemoverSpy . restore ( ) ;
221+ $$ . SANDBOX . stub ( AuthRemover . prototype , 'removeAuth' ) . rejects ( elockedError ) ;
222+
223+ try {
224+ await Logout . run ( [ '-p' , '--json' ] ) ;
225+ expect . fail ( 'Expected error to be thrown' ) ;
226+ } catch ( e ) {
227+ const error = e as Error & { code ?: string ; data ?: string ; file ?: string } ;
228+ expect ( error . code ) . to . equal ( 'ELOCKED' ) ;
229+ expect ( error . data ) . to . equal ( lockedFile ) ;
230+ expect ( error . message ) . to . include ( 'Lock file is already being held' ) ;
231+ expect ( error . message ) . to . include ( `(file: ${ lockedFile } )` ) ;
232+ }
233+ } ) ;
234+
235+ it ( 'should handle ELOCKED error without file property' , async ( ) => {
236+ await prepareStubs ( { 'target-org' : testOrg1 . username } ) ;
237+ const elockedError = new Error ( 'Lock file is already being held' ) as Error & { code ?: string } ;
238+ elockedError . code = 'ELOCKED' ;
239+
240+ // Stub removeAuth to throw ELOCKED error without file property
241+ authRemoverSpy . restore ( ) ;
242+ $$ . SANDBOX . stub ( AuthRemover . prototype , 'removeAuth' ) . rejects ( elockedError ) ;
243+
244+ try {
245+ await Logout . run ( [ '-p' , '--json' ] ) ;
246+ expect . fail ( 'Expected error to be thrown' ) ;
247+ } catch ( e ) {
248+ const error = e as Error & { code ?: string } ;
249+ expect ( error . code ) . to . equal ( 'ELOCKED' ) ;
250+ expect ( error . message ) . to . include ( 'Lock file is already being held' ) ;
251+ // Should not have file in message if file property doesn't exist
252+ expect ( error . message ) . to . not . include ( '(file:' ) ;
253+ }
254+ } ) ;
255+
256+ it ( 'should re-throw non-ELOCKED errors unchanged' , async ( ) => {
257+ await prepareStubs ( { 'target-org' : testOrg1 . username } ) ;
258+ const otherError = new Error ( 'Some other error' ) as Error & { code ?: string } ;
259+ otherError . code = 'ESOMEOTHER' ;
260+
261+ // Stub removeAuth to throw a different error
262+ authRemoverSpy . restore ( ) ;
263+ $$ . SANDBOX . stub ( AuthRemover . prototype , 'removeAuth' ) . rejects ( otherError ) ;
264+
265+ try {
266+ await Logout . run ( [ '-p' , '--json' ] ) ;
267+ expect . fail ( 'Expected error to be thrown' ) ;
268+ } catch ( e ) {
269+ const error = e as Error & { code ?: string } ;
270+ expect ( error . code ) . to . equal ( 'ESOMEOTHER' ) ;
271+ expect ( error . message ) . to . equal ( 'Some other error' ) ;
272+ // Should not have file information appended
273+ expect ( error . message ) . to . not . include ( '(file:' ) ;
274+ }
275+ } ) ;
276+ } ) ;
177277} ) ;
0 commit comments