Skip to content

Commit ca0902c

Browse files
committed
fix: add tests
1 parent b46f40d commit ca0902c

2 files changed

Lines changed: 102 additions & 2 deletions

File tree

src/commands/org/logout.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ export default class Logout extends SfCommand<AuthLogoutResults> {
127127
await processInBatches(loggedOutUsernames, 10, (username) => remover.removeAuth(username));
128128
} catch (error) {
129129
const err = SfError.wrap(error);
130-
if (err.code === 'ELOCKED' && 'file' in err) {
131-
const lockedFile = err.file as string;
130+
if (err.code === 'ELOCKED' && error && typeof error === 'object' && 'file' in error) {
131+
const lockedFile = error.file as string;
132132
err.setData(lockedFile);
133133
err.message = `${err.message} (file: ${lockedFile})`;
134134
}

test/commands/org/logout.test.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)