contentful-mcp
by ivo-toby
- contentful-mcp
- test
- integration
import { describe, it, expect, vi, beforeEach } from "vitest"
import { aiActionHandlers } from "../../src/handlers/ai-action-handlers"
import { aiActionsClient } from "../../src/config/ai-actions-client"
// Mock the AI Actions client
vi.mock("../../src/config/ai-actions-client", () => ({
aiActionsClient: {
listAiActions: vi.fn(),
getAiAction: vi.fn(),
createAiAction: vi.fn(),
updateAiAction: vi.fn(),
deleteAiAction: vi.fn(),
publishAiAction: vi.fn(),
unpublishAiAction: vi.fn(),
invokeAiAction: vi.fn(),
getAiActionInvocation: vi.fn(),
pollInvocation: vi.fn(),
},
}))
// Mock data
const mockAiAction = {
sys: {
id: "action1",
type: "AiAction" as const,
createdAt: "2023-01-01T00:00:00Z",
updatedAt: "2023-01-02T00:00:00Z",
version: 1,
space: { sys: { id: "space1", linkType: "Space", type: "Link" as const } },
createdBy: { sys: { id: "user1", linkType: "User", type: "Link" as const } },
updatedBy: { sys: { id: "user1", linkType: "User", type: "Link" as const } },
},
name: "Test Action",
description: "A test action",
instruction: {
template: "Template with {{var}}",
variables: [{ id: "var", type: "Text" }],
},
configuration: {
modelType: "gpt-4",
modelTemperature: 0.5,
},
}
const mockAiActionCollection = {
sys: { type: "Array" as const },
items: [mockAiAction],
total: 1,
skip: 0,
limit: 10,
}
const mockInvocation = {
sys: {
id: "inv1",
type: "AiActionInvocation" as const,
space: { sys: { id: "space1", linkType: "Space", type: "Link" as const } },
environment: { sys: { id: "master", linkType: "Environment", type: "Link" as const } },
aiAction: { sys: { id: "action1", linkType: "AiAction", type: "Link" as const } },
status: "COMPLETED" as const,
},
result: {
type: "text" as const,
content: "Generated content",
metadata: {
invocationResult: {
aiAction: {
sys: {
id: "action1",
linkType: "AiAction",
type: "Link" as const,
version: 1,
},
},
outputFormat: "PlainText" as const,
promptTokens: 50,
completionTokens: 100,
modelId: "gpt-4",
modelProvider: "OpenAI",
},
},
},
}
describe("AI Action Handlers", () => {
beforeEach(() => {
vi.resetAllMocks()
})
it("should list AI Actions", async () => {
const clientSpy = vi
.mocked(aiActionsClient.listAiActions)
.mockResolvedValueOnce(mockAiActionCollection)
const result = await aiActionHandlers.listAiActions({
spaceId: "space1",
limit: 10,
})
expect(clientSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
limit: 10,
skip: undefined,
status: undefined,
})
expect(result).toEqual(mockAiActionCollection)
})
it("should get an AI Action", async () => {
const clientSpy = vi.mocked(aiActionsClient.getAiAction).mockResolvedValueOnce(mockAiAction)
const result = await aiActionHandlers.getAiAction({
spaceId: "space1",
aiActionId: "action1",
})
expect(clientSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
aiActionId: "action1",
})
expect(result).toEqual(mockAiAction)
})
it("should create an AI Action", async () => {
const clientSpy = vi.mocked(aiActionsClient.createAiAction).mockResolvedValueOnce(mockAiAction)
const actionData = {
spaceId: "space1",
name: "New Action",
description: "A new action",
instruction: {
template: "Template",
variables: [],
},
configuration: {
modelType: "gpt-4",
modelTemperature: 0.5,
},
}
const result = await aiActionHandlers.createAiAction(actionData)
expect(clientSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
actionData: {
name: "New Action",
description: "A new action",
instruction: {
template: "Template",
variables: [],
},
configuration: {
modelType: "gpt-4",
modelTemperature: 0.5,
},
testCases: undefined,
},
})
expect(result).toEqual(mockAiAction)
})
it("should update an AI Action", async () => {
vi.mocked(aiActionsClient.getAiAction).mockResolvedValueOnce(mockAiAction)
const updateSpy = vi.mocked(aiActionsClient.updateAiAction).mockResolvedValueOnce({
...mockAiAction,
name: "Updated Action",
})
const actionData = {
spaceId: "space1",
aiActionId: "action1",
name: "Updated Action",
description: "An updated action",
instruction: {
template: "Updated template",
variables: [],
},
configuration: {
modelType: "gpt-4",
modelTemperature: 0.7,
},
}
const result = await aiActionHandlers.updateAiAction(actionData)
expect(updateSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
aiActionId: "action1",
version: 1,
actionData: {
name: "Updated Action",
description: "An updated action",
instruction: {
template: "Updated template",
variables: [],
},
configuration: {
modelType: "gpt-4",
modelTemperature: 0.7,
},
testCases: undefined,
},
})
expect(result).toEqual({
...mockAiAction,
name: "Updated Action",
})
})
it("should delete an AI Action", async () => {
vi.mocked(aiActionsClient.getAiAction).mockResolvedValueOnce(mockAiAction)
const deleteSpy = vi.mocked(aiActionsClient.deleteAiAction).mockResolvedValueOnce()
const result = await aiActionHandlers.deleteAiAction({
spaceId: "space1",
aiActionId: "action1",
})
expect(deleteSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
aiActionId: "action1",
version: 1,
})
expect(result).toEqual({ success: true })
})
it("should publish an AI Action", async () => {
vi.mocked(aiActionsClient.getAiAction).mockResolvedValueOnce(mockAiAction)
const publishSpy = vi.mocked(aiActionsClient.publishAiAction).mockResolvedValueOnce({
...mockAiAction,
sys: {
...mockAiAction.sys,
publishedAt: "2023-01-03T00:00:00Z",
publishedVersion: 1,
},
})
const result = await aiActionHandlers.publishAiAction({
spaceId: "space1",
aiActionId: "action1",
})
expect(publishSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
aiActionId: "action1",
version: 1,
})
expect(result).toHaveProperty("sys.publishedAt", "2023-01-03T00:00:00Z")
})
it("should unpublish an AI Action", async () => {
const unpublishSpy = vi
.mocked(aiActionsClient.unpublishAiAction)
.mockResolvedValueOnce(mockAiAction)
const result = await aiActionHandlers.unpublishAiAction({
spaceId: "space1",
aiActionId: "action1",
})
expect(unpublishSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
aiActionId: "action1",
})
expect(result).toEqual(mockAiAction)
})
it("should invoke an AI Action with key-value variables", async () => {
const invokeSpy = vi
.mocked(aiActionsClient.invokeAiAction)
.mockResolvedValueOnce(mockInvocation)
const result = await aiActionHandlers.invokeAiAction({
spaceId: "space1",
aiActionId: "action1",
variables: {
var1: "value1",
var2: "value2",
},
})
expect(invokeSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
aiActionId: "action1",
invocationData: {
outputFormat: "Markdown",
variables: [
{ id: "var1", value: "value1" },
{ id: "var2", value: "value2" },
],
},
})
expect(result).toEqual(mockInvocation)
})
it("should invoke an AI Action with raw variables", async () => {
const invokeSpy = vi
.mocked(aiActionsClient.invokeAiAction)
.mockResolvedValueOnce(mockInvocation)
const rawVariables = [
{
id: "refVar",
value: {
entityType: "Entry",
entityId: "entry123",
},
},
]
const result = await aiActionHandlers.invokeAiAction({
spaceId: "space1",
aiActionId: "action1",
rawVariables,
})
expect(invokeSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
aiActionId: "action1",
invocationData: {
outputFormat: "Markdown",
variables: rawVariables,
},
})
expect(result).toEqual(mockInvocation)
})
it("should poll for completion when invoking asynchronously", async () => {
const inProgressInvocation = {
...mockInvocation,
sys: {
...mockInvocation.sys,
status: "IN_PROGRESS",
},
result: undefined,
}
vi.mocked(aiActionsClient.invokeAiAction).mockResolvedValueOnce(inProgressInvocation)
vi.mocked(aiActionsClient.pollInvocation).mockResolvedValueOnce(mockInvocation)
const result = await aiActionHandlers.invokeAiAction({
spaceId: "space1",
aiActionId: "action1",
variables: { var: "value" },
waitForCompletion: true,
})
expect(aiActionsClient.pollInvocation).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
aiActionId: "action1",
invocationId: "inv1",
})
expect(result).toEqual(mockInvocation)
})
it("should not poll when waitForCompletion is false", async () => {
const inProgressInvocation = {
...mockInvocation,
sys: {
...mockInvocation.sys,
status: "IN_PROGRESS",
},
result: undefined,
}
vi.mocked(aiActionsClient.invokeAiAction).mockResolvedValueOnce(inProgressInvocation)
const result = await aiActionHandlers.invokeAiAction({
spaceId: "space1",
aiActionId: "action1",
variables: { var: "value" },
waitForCompletion: false,
})
expect(aiActionsClient.pollInvocation).not.toHaveBeenCalled()
expect(result).toEqual(inProgressInvocation)
})
it("should get an AI Action invocation", async () => {
const getSpy = vi
.mocked(aiActionsClient.getAiActionInvocation)
.mockResolvedValueOnce(mockInvocation)
const result = await aiActionHandlers.getAiActionInvocation({
spaceId: "space1",
aiActionId: "action1",
invocationId: "inv1",
})
expect(getSpy).toHaveBeenCalledWith({
spaceId: "space1",
environmentId: "master",
aiActionId: "action1",
invocationId: "inv1",
})
expect(result).toEqual(mockInvocation)
})
it("should handle errors correctly", async () => {
vi.mocked(aiActionsClient.getAiAction).mockRejectedValueOnce({
message: "Not found",
response: {
data: {
message: "AI Action not found",
},
},
})
const result = await aiActionHandlers.getAiAction({
spaceId: "space1",
aiActionId: "nonexistent",
})
expect(result).toEqual({
isError: true,
message: "AI Action not found",
})
})
})