Skip to content

Commit d088f0d

Browse files
authored
chore: ai-action unit tests [DX-308] (#101)
* chore: tests complete * chore: vi fake timers implemented
1 parent 676f190 commit d088f0d

10 files changed

+1366
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest';
2+
import { createAiActionTool } from './createAiAction.js';
3+
import { formatResponse } from '../../utils/formatters.js';
4+
import { VariableType } from '../../utils/ai-actions.js';
5+
import {
6+
setupMockClient,
7+
mockAiActionCreate,
8+
mockAiAction,
9+
mockArgs,
10+
mockComplexAiAction,
11+
} from './mockClient.js';
12+
13+
vi.mock('../../../src/utils/tools.js');
14+
vi.mock('../../../src/config/contentful.js');
15+
16+
describe('createAiAction', () => {
17+
beforeEach(() => {
18+
setupMockClient();
19+
});
20+
21+
it('should create an AI action successfully with basic configuration', async () => {
22+
const testArgs = {
23+
...mockArgs,
24+
name: 'Translation AI Action',
25+
description: 'Translates content between languages',
26+
instruction: {
27+
template:
28+
'Translate {{var.sourceContent}} from {{var.sourceLocale}} to {{var.targetLocale}}',
29+
variables: [
30+
{
31+
id: 'sourceContent',
32+
name: 'Source Content',
33+
type: VariableType.TEXT,
34+
description: 'Content to translate',
35+
},
36+
{
37+
id: 'sourceLocale',
38+
type: VariableType.LOCALE,
39+
},
40+
{
41+
id: 'targetLocale',
42+
type: VariableType.LOCALE,
43+
},
44+
],
45+
},
46+
configuration: {
47+
modelType: 'gpt-4',
48+
modelTemperature: 0.3,
49+
},
50+
};
51+
52+
mockAiActionCreate.mockResolvedValue(mockAiAction);
53+
54+
const result = await createAiActionTool(testArgs);
55+
56+
const expectedResponse = formatResponse('AI action created successfully', {
57+
aiAction: mockAiAction,
58+
});
59+
expect(result).toEqual({
60+
content: [
61+
{
62+
type: 'text',
63+
text: expectedResponse,
64+
},
65+
],
66+
});
67+
});
68+
69+
it('should create an AI action with complex variable types', async () => {
70+
const testArgs = {
71+
...mockArgs,
72+
name: 'Complex AI Action',
73+
description: 'An AI action with various variable types',
74+
instruction: {
75+
template:
76+
'Process {{var.entryRef}} with {{var.smartContext}} for {{var.mediaRef}}',
77+
variables: [
78+
{
79+
id: 'entryRef',
80+
name: 'Entry Reference',
81+
type: VariableType.REFERENCE,
82+
description: 'Reference to entry',
83+
},
84+
{
85+
id: 'smartContext',
86+
name: 'Smart Context',
87+
type: VariableType.SMART_CONTEXT,
88+
description: 'AI context',
89+
},
90+
{
91+
id: 'mediaRef',
92+
name: 'Media Reference',
93+
type: VariableType.MEDIA_REFERENCE,
94+
description: 'Media asset reference',
95+
},
96+
],
97+
},
98+
configuration: {
99+
modelType: 'gpt-3.5-turbo',
100+
modelTemperature: 0.7,
101+
},
102+
testCases: [
103+
{
104+
name: 'Test case 1',
105+
variables: {},
106+
},
107+
],
108+
};
109+
110+
mockAiActionCreate.mockResolvedValue(mockComplexAiAction);
111+
112+
const result = await createAiActionTool(testArgs);
113+
114+
const expectedResponse = formatResponse('AI action created successfully', {
115+
aiAction: mockComplexAiAction,
116+
});
117+
expect(result).toEqual({
118+
content: [
119+
{
120+
type: 'text',
121+
text: expectedResponse,
122+
},
123+
],
124+
});
125+
});
126+
127+
it('should handle errors when AI action creation fails', async () => {
128+
const testArgs = {
129+
...mockArgs,
130+
name: 'Invalid AI Action',
131+
description: 'An AI action that will fail',
132+
instruction: {
133+
template: 'Invalid template with {{var.nonExistentVariable}}',
134+
variables: [
135+
{
136+
id: 'existingVariable',
137+
type: VariableType.TEXT,
138+
},
139+
],
140+
},
141+
configuration: {
142+
modelType: 'invalid-model',
143+
modelTemperature: 2.0, // Invalid temperature
144+
},
145+
};
146+
147+
const error = new Error('Invalid model configuration');
148+
mockAiActionCreate.mockRejectedValue(error);
149+
150+
const result = await createAiActionTool(testArgs);
151+
152+
expect(result).toEqual({
153+
isError: true,
154+
content: [
155+
{
156+
type: 'text',
157+
text: 'Error creating AI action: Invalid model configuration',
158+
},
159+
],
160+
});
161+
});
162+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest';
2+
import { deleteAiActionTool } from './deleteAiAction.js';
3+
import { formatResponse } from '../../utils/formatters.js';
4+
import {
5+
setupMockClient,
6+
mockAiActionDelete,
7+
mockArgs,
8+
mockAiAction,
9+
mockAiActionGet,
10+
} from './mockClient.js';
11+
12+
vi.mock('../../../src/utils/tools.js');
13+
vi.mock('../../../src/config/contentful.js');
14+
15+
describe('deleteAiAction', () => {
16+
beforeEach(() => {
17+
setupMockClient();
18+
});
19+
20+
it('should delete an AI action successfully', async () => {
21+
mockAiActionGet.mockResolvedValue(mockAiAction);
22+
mockAiActionDelete.mockResolvedValue(undefined);
23+
24+
const result = await deleteAiActionTool(mockArgs);
25+
26+
const expectedResponse = formatResponse('AI action deleted successfully', {
27+
aiAction: mockAiAction,
28+
});
29+
expect(result).toEqual({
30+
content: [
31+
{
32+
type: 'text',
33+
text: expectedResponse,
34+
},
35+
],
36+
});
37+
});
38+
39+
it('should handle errors when AI action deletion fails', async () => {
40+
const error = new Error('AI action not found');
41+
mockAiActionDelete.mockRejectedValue(error);
42+
43+
const result = await deleteAiActionTool(mockArgs);
44+
45+
expect(result).toEqual({
46+
isError: true,
47+
content: [
48+
{
49+
type: 'text',
50+
text: 'Error deleting AI action: AI action not found',
51+
},
52+
],
53+
});
54+
});
55+
});
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest';
2+
import { getAiActionTool } from './getAiAction.js';
3+
import { formatResponse } from '../../utils/formatters.js';
4+
import {
5+
setupMockClient,
6+
mockAiActionGet,
7+
mockAiAction,
8+
mockArgs,
9+
} from './mockClient.js';
10+
11+
vi.mock('../../../src/utils/tools.js');
12+
vi.mock('../../../src/config/contentful.js');
13+
14+
describe('getAiAction', () => {
15+
beforeEach(() => {
16+
setupMockClient();
17+
});
18+
19+
it('should retrieve an AI action successfully', async () => {
20+
mockAiActionGet.mockResolvedValue(mockAiAction);
21+
22+
const result = await getAiActionTool(mockArgs);
23+
24+
const expectedResponse = formatResponse(
25+
'AI action retrieved successfully',
26+
{
27+
aiAction: mockAiAction,
28+
},
29+
);
30+
expect(result).toEqual({
31+
content: [
32+
{
33+
type: 'text',
34+
text: expectedResponse,
35+
},
36+
],
37+
});
38+
});
39+
40+
it('should handle errors when AI action is not found', async () => {
41+
const error = new Error('AI action not found');
42+
mockAiActionGet.mockRejectedValue(error);
43+
44+
const result = await getAiActionTool(mockArgs);
45+
46+
expect(result).toEqual({
47+
isError: true,
48+
content: [
49+
{
50+
type: 'text',
51+
text: 'Error retrieving AI action: AI action not found',
52+
},
53+
],
54+
});
55+
});
56+
});
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest';
2+
import { getAiActionInvocationTool } from './getAiActionInvocation.js';
3+
import { formatResponse } from '../../utils/formatters.js';
4+
import {
5+
setupMockClient,
6+
mockAiActionInvocationGet,
7+
mockAiActionInvocation,
8+
mockArgs,
9+
} from './mockClient.js';
10+
11+
vi.mock('../../../src/utils/tools.js');
12+
vi.mock('../../../src/config/contentful.js');
13+
14+
describe('getAiActionInvocation', () => {
15+
beforeEach(() => {
16+
setupMockClient();
17+
});
18+
19+
it('should retrieve an AI action invocation successfully', async () => {
20+
const testArgs = {
21+
...mockArgs,
22+
invocationId: 'test-invocation-id',
23+
};
24+
25+
mockAiActionInvocationGet.mockResolvedValue(mockAiActionInvocation);
26+
27+
const result = await getAiActionInvocationTool(testArgs);
28+
29+
const expectedResponse = formatResponse(
30+
'AI action invocation retrieved successfully',
31+
{
32+
aiActionInvocation: mockAiActionInvocation,
33+
},
34+
);
35+
expect(result).toEqual({
36+
content: [
37+
{
38+
type: 'text',
39+
text: expectedResponse,
40+
},
41+
],
42+
});
43+
});
44+
45+
it('should handle errors when invocation is not found', async () => {
46+
const testArgs = {
47+
...mockArgs,
48+
invocationId: 'non-existent-invocation',
49+
};
50+
51+
const error = new Error('Invocation not found');
52+
mockAiActionInvocationGet.mockRejectedValue(error);
53+
54+
const result = await getAiActionInvocationTool(testArgs);
55+
56+
expect(result).toEqual({
57+
isError: true,
58+
content: [
59+
{
60+
type: 'text',
61+
text: 'Error retrieving AI action invocation: Invocation not found',
62+
},
63+
],
64+
});
65+
});
66+
});

0 commit comments

Comments
 (0)