Skip to content

Commit 7dea3e4

Browse files
fix: add guard for empty available versions and unit tests
1 parent bf3e742 commit 7dea3e4

File tree

3 files changed

+137
-2
lines changed

3 files changed

+137
-2
lines changed

messages/agent.activation.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ Agent %s has been deleted and can't be activated.
1313
# error.agentIsDefault
1414

1515
Agent %s is the default Agentforce agent in your org and you can't change its activation status.
16+
17+
# error.noVersionsAvailable
18+
19+
No versions available to %s. All versions are already in the target state.

src/agentActivation.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ export const getVersionForActivation = async (config: {
164164
return { version: availableChoices[0].value.version };
165165
}
166166

167+
// If no versions are available, throw an error
168+
if (availableChoices.length === 0) {
169+
const action = status === 'Active' ? 'activate' : 'deactivate';
170+
throw messages.createError('error.noVersionsAvailable', [action]);
171+
}
172+
167173
// If JSON mode is enabled, automatically select the latest available version
168174
if (jsonEnabled) {
169175
// Find the latest (highest version number) available version

test/agentActivation.test.ts

Lines changed: 127 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
*/
1616

1717
import { expect } from 'chai';
18-
import { type BotMetadata, type BotVersionMetadata } from '@salesforce/agents';
19-
import { getAgentChoices, getVersionChoices } from '../src/agentActivation.js';
18+
import sinon from 'sinon';
19+
import { type BotMetadata, type BotVersionMetadata, type ProductionAgent } from '@salesforce/agents';
20+
import { getAgentChoices, getVersionChoices, getVersionForActivation } from '../src/agentActivation.js';
2021

2122
describe('agentActivation', () => {
2223
describe('getVersionChoices', () => {
@@ -268,4 +269,128 @@ describe('agentActivation', () => {
268269
expect(choices[2].value.DeveloperName).to.equal('Zebra_Agent');
269270
});
270271
});
272+
273+
describe('getVersionForActivation', () => {
274+
let mockAgent: sinon.SinonStubbedInstance<ProductionAgent>;
275+
276+
beforeEach(() => {
277+
mockAgent = {
278+
getBotMetadata: sinon.stub(),
279+
} as unknown as sinon.SinonStubbedInstance<ProductionAgent>;
280+
});
281+
282+
afterEach(() => {
283+
sinon.restore();
284+
});
285+
286+
it('should return version flag when provided', async () => {
287+
const result = await getVersionForActivation({
288+
agent: mockAgent as unknown as ProductionAgent,
289+
status: 'Active',
290+
versionFlag: 5,
291+
});
292+
293+
expect(result.version).to.equal(5);
294+
expect(result.warning).to.be.undefined;
295+
expect(mockAgent.getBotMetadata.called).to.be.false;
296+
});
297+
298+
it('should auto-select when only one version exists', async () => {
299+
mockAgent.getBotMetadata.resolves({
300+
BotVersions: {
301+
records: [{ VersionNumber: 3, Status: 'Inactive', IsDeleted: false } as BotVersionMetadata],
302+
},
303+
} as BotMetadata);
304+
305+
const result = await getVersionForActivation({
306+
agent: mockAgent as unknown as ProductionAgent,
307+
status: 'Active',
308+
});
309+
310+
expect(result.version).to.equal(3);
311+
expect(result.warning).to.be.undefined;
312+
});
313+
314+
it('should auto-select when only one available choice exists', async () => {
315+
mockAgent.getBotMetadata.resolves({
316+
BotVersions: {
317+
records: [
318+
{ VersionNumber: 1, Status: 'Active', IsDeleted: false } as BotVersionMetadata,
319+
{ VersionNumber: 2, Status: 'Inactive', IsDeleted: false } as BotVersionMetadata,
320+
],
321+
},
322+
} as BotMetadata);
323+
324+
const result = await getVersionForActivation({
325+
agent: mockAgent as unknown as ProductionAgent,
326+
status: 'Active',
327+
});
328+
329+
// Only version 2 is available (inactive), version 1 is already active
330+
expect(result.version).to.equal(2);
331+
expect(result.warning).to.be.undefined;
332+
});
333+
334+
it('should auto-select latest version in JSON mode', async () => {
335+
mockAgent.getBotMetadata.resolves({
336+
BotVersions: {
337+
records: [
338+
{ VersionNumber: 1, Status: 'Inactive', IsDeleted: false } as BotVersionMetadata,
339+
{ VersionNumber: 2, Status: 'Inactive', IsDeleted: false } as BotVersionMetadata,
340+
{ VersionNumber: 3, Status: 'Inactive', IsDeleted: false } as BotVersionMetadata,
341+
],
342+
},
343+
} as BotMetadata);
344+
345+
const result = await getVersionForActivation({
346+
agent: mockAgent as unknown as ProductionAgent,
347+
status: 'Active',
348+
jsonEnabled: true,
349+
});
350+
351+
expect(result.version).to.equal(3);
352+
expect(result.warning).to.include('automatically selected latest available version: 3');
353+
});
354+
355+
it('should filter out deleted versions', async () => {
356+
mockAgent.getBotMetadata.resolves({
357+
BotVersions: {
358+
records: [
359+
{ VersionNumber: 1, Status: 'Inactive', IsDeleted: true } as BotVersionMetadata,
360+
{ VersionNumber: 2, Status: 'Inactive', IsDeleted: false } as BotVersionMetadata,
361+
],
362+
},
363+
} as BotMetadata);
364+
365+
const result = await getVersionForActivation({
366+
agent: mockAgent as unknown as ProductionAgent,
367+
status: 'Active',
368+
});
369+
370+
// Only version 2 should be considered (version 1 is deleted)
371+
expect(result.version).to.equal(2);
372+
});
373+
374+
it('should throw error when no versions are available', async () => {
375+
mockAgent.getBotMetadata.resolves({
376+
BotVersions: {
377+
records: [
378+
{ VersionNumber: 1, Status: 'Active', IsDeleted: false } as BotVersionMetadata,
379+
{ VersionNumber: 2, Status: 'Active', IsDeleted: false } as BotVersionMetadata,
380+
],
381+
},
382+
} as BotMetadata);
383+
384+
try {
385+
await getVersionForActivation({
386+
agent: mockAgent as unknown as ProductionAgent,
387+
status: 'Active',
388+
jsonEnabled: true,
389+
});
390+
expect.fail('Expected error to be thrown');
391+
} catch (error) {
392+
expect((error as Error).message).to.include('No versions available to activate');
393+
}
394+
});
395+
});
271396
});

0 commit comments

Comments
 (0)