Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/sim/app/api/chat/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('Chat API Utils', () => {
})

describe('Auth token utils', () => {
it.concurrent('should encrypt and validate auth tokens', async () => {
it('should encrypt and validate auth tokens', async () => {
const { encryptAuthToken, validateAuthToken } = await import('@/app/api/chat/utils')

const subdomainId = 'test-subdomain-id'
Expand All @@ -82,7 +82,7 @@ describe('Chat API Utils', () => {
expect(isInvalidSubdomain).toBe(false)
})

it.concurrent('should reject expired tokens', async () => {
it('should reject expired tokens', async () => {
const { validateAuthToken } = await import('@/app/api/chat/utils')

const subdomainId = 'test-subdomain-id'
Expand Down
265 changes: 94 additions & 171 deletions apps/sim/app/api/copilot/chat/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,33 +200,30 @@ describe('Copilot Chat API Route', () => {
messages: [],
})

// Verify sim agent was called
expect(global.fetch).toHaveBeenCalledWith(
'http://localhost:8000/api/chat-completion-streaming',
// Verify sim agent was called and includes prefetchResults
expect(global.fetch).toHaveBeenCalled()
const fetchArgs = (global.fetch as any).mock.calls[0]
expect(fetchArgs[0]).toBe('http://localhost:8000/api/chat-completion-streaming')
const payload = JSON.parse(fetchArgs[1].body)
expect(payload).toEqual(
expect.objectContaining({
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'test-sim-agent-key',
},
body: JSON.stringify({
messages: [
{
role: 'user',
content: 'Hello',
},
],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
mode: 'agent',
provider: 'openai',
depth: 0,
origin: 'http://localhost:3000',
}),
messages: [
{
role: 'user',
content: 'Hello',
},
],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
mode: 'agent',
provider: 'openai',
depth: 0,
origin: 'http://localhost:3000',
})
)
expect(payload.prefetchResults).toBeDefined()
})

it('should load existing chat and include conversation history', async () => {
Expand Down Expand Up @@ -270,27 +267,28 @@ describe('Copilot Chat API Route', () => {

expect(response.status).toBe(200)

// Verify conversation history was included
expect(global.fetch).toHaveBeenCalledWith(
'http://localhost:8000/api/chat-completion-streaming',
// Verify conversation history was included and prefetchResults present
const fetchArgs = (global.fetch as any).mock.calls[0]
expect(fetchArgs[0]).toBe('http://localhost:8000/api/chat-completion-streaming')
const payload = JSON.parse(fetchArgs[1].body)
expect(payload.messages).toEqual([
{ role: 'user', content: 'Previous message' },
{ role: 'assistant', content: 'Previous response' },
{ role: 'user', content: 'New message' },
])
expect(payload).toEqual(
expect.objectContaining({
body: JSON.stringify({
messages: [
{ role: 'user', content: 'Previous message' },
{ role: 'assistant', content: 'Previous response' },
{ role: 'user', content: 'New message' },
],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
mode: 'agent',
provider: 'openai',
depth: 0,
origin: 'http://localhost:3000',
}),
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
mode: 'agent',
provider: 'openai',
depth: 0,
origin: 'http://localhost:3000',
})
)
expect(payload.prefetchResults).toBeDefined()
})

it('should include implicit feedback in messages', async () => {
Expand Down Expand Up @@ -327,26 +325,27 @@ describe('Copilot Chat API Route', () => {
const { POST } = await import('@/app/api/copilot/chat/route')
await POST(req)

// Verify implicit feedback was included as system message
expect(global.fetch).toHaveBeenCalledWith(
'http://localhost:8000/api/chat-completion-streaming',
// Verify implicit feedback was included as system message and prefetchResults present
const fetchArgs = (global.fetch as any).mock.calls[0]
expect(fetchArgs[0]).toBe('http://localhost:8000/api/chat-completion-streaming')
const payload = JSON.parse(fetchArgs[1].body)
expect(payload.messages).toEqual([
{ role: 'system', content: 'User seems confused about the workflow' },
{ role: 'user', content: 'Hello' },
])
expect(payload).toEqual(
expect.objectContaining({
body: JSON.stringify({
messages: [
{ role: 'system', content: 'User seems confused about the workflow' },
{ role: 'user', content: 'Hello' },
],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
mode: 'agent',
provider: 'openai',
depth: 0,
origin: 'http://localhost:3000',
}),
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
mode: 'agent',
provider: 'openai',
depth: 0,
origin: 'http://localhost:3000',
})
)
expect(payload.prefetchResults).toBeDefined()
})

it('should handle sim agent API errors', async () => {
Expand Down Expand Up @@ -427,22 +426,23 @@ describe('Copilot Chat API Route', () => {
const { POST } = await import('@/app/api/copilot/chat/route')
await POST(req)

expect(global.fetch).toHaveBeenCalledWith(
'http://localhost:8000/api/chat-completion-streaming',
const fetchArgs = (global.fetch as any).mock.calls[0]
expect(fetchArgs[0]).toBe('http://localhost:8000/api/chat-completion-streaming')
const payload = JSON.parse(fetchArgs[1].body)
expect(payload).toEqual(
expect.objectContaining({
body: JSON.stringify({
messages: [{ role: 'user', content: 'What is this workflow?' }],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
mode: 'ask',
provider: 'openai',
depth: 0,
origin: 'http://localhost:3000',
}),
messages: [{ role: 'user', content: 'What is this workflow?' }],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
mode: 'ask',
provider: 'openai',
depth: 0,
origin: 'http://localhost:3000',
})
)
expect(payload.prefetchResults).toBeDefined()
})
})

Expand Down Expand Up @@ -479,67 +479,19 @@ describe('Copilot Chat API Route', () => {
const authMocks = mockAuth()
authMocks.setAuthenticated()

// Mock database response (what comes from DB)
const mockDbChats = [
// Mock returned chats
const chats = [
{
id: 'chat-1',
title: 'First Chat',
title: 'Chat 1',
model: 'claude-3-haiku-20240307',
messages: [
{ role: 'user', content: 'Message 1' },
{ role: 'assistant', content: 'Response 1' },
{ role: 'user', content: 'Message 2' },
{ role: 'assistant', content: 'Response 2' },
],
createdAt: new Date('2024-01-01'),
updatedAt: new Date('2024-01-02'),
},
{
id: 'chat-2',
title: 'Second Chat',
model: 'claude-3-haiku-20240307',
messages: [
{ role: 'user', content: 'Message 1' },
{ role: 'assistant', content: 'Response 1' },
],
createdAt: new Date('2024-01-03'),
updatedAt: new Date('2024-01-04'),
messages: [{ role: 'user', content: 'Hello' }],
createdAt: new Date(),
updatedAt: new Date(),
},
]

// Expected transformed response (what the route returns)
const expectedChats = [
{
id: 'chat-1',
title: 'First Chat',
model: 'claude-3-haiku-20240307',
messages: [
{ role: 'user', content: 'Message 1' },
{ role: 'assistant', content: 'Response 1' },
{ role: 'user', content: 'Message 2' },
{ role: 'assistant', content: 'Response 2' },
],
messageCount: 4,
previewYaml: null,
createdAt: new Date('2024-01-01'),
updatedAt: new Date('2024-01-02'),
},
{
id: 'chat-2',
title: 'Second Chat',
model: 'claude-3-haiku-20240307',
messages: [
{ role: 'user', content: 'Message 1' },
{ role: 'assistant', content: 'Response 1' },
],
messageCount: 2,
previewYaml: null,
createdAt: new Date('2024-01-03'),
updatedAt: new Date('2024-01-04'),
},
]

mockOrderBy.mockResolvedValue(mockDbChats)
mockOrderBy.mockResolvedValue(chats)

const req = new NextRequest('http://localhost:3000/api/copilot/chat?workflowId=workflow-123')

Expand All @@ -548,52 +500,24 @@ describe('Copilot Chat API Route', () => {

expect(response.status).toBe(200)
const responseData = await response.json()
expect(responseData).toEqual({
success: true,
chats: [
{
id: 'chat-1',
title: 'First Chat',
model: 'claude-3-haiku-20240307',
messages: [
{ role: 'user', content: 'Message 1' },
{ role: 'assistant', content: 'Response 1' },
{ role: 'user', content: 'Message 2' },
{ role: 'assistant', content: 'Response 2' },
],
messageCount: 4,
previewYaml: null,
createdAt: '2024-01-01T00:00:00.000Z',
updatedAt: '2024-01-02T00:00:00.000Z',
},
{
id: 'chat-2',
title: 'Second Chat',
model: 'claude-3-haiku-20240307',
messages: [
{ role: 'user', content: 'Message 1' },
{ role: 'assistant', content: 'Response 1' },
],
messageCount: 2,
previewYaml: null,
createdAt: '2024-01-03T00:00:00.000Z',
updatedAt: '2024-01-04T00:00:00.000Z',
},
],
})

// Verify database query was made correctly
expect(mockSelect).toHaveBeenCalled()
expect(mockWhere).toHaveBeenCalled()
expect(mockOrderBy).toHaveBeenCalled()
expect(responseData.success).toBe(true)
expect(Array.isArray(responseData.chats)).toBe(true)
expect(responseData.chats.length).toBe(1)
expect(responseData.chats[0]).toEqual(
expect.objectContaining({
id: 'chat-1',
title: 'Chat 1',
model: 'claude-3-haiku-20240307',
messageCount: 1,
})
)
})

it('should handle database errors when fetching chats', async () => {
const authMocks = mockAuth()
authMocks.setAuthenticated()

// Mock database error
mockOrderBy.mockRejectedValue(new Error('Database query failed'))
mockOrderBy.mockRejectedValue(new Error('Database error'))

const req = new NextRequest('http://localhost:3000/api/copilot/chat?workflowId=workflow-123')

Expand All @@ -618,10 +542,9 @@ describe('Copilot Chat API Route', () => {

expect(response.status).toBe(200)
const responseData = await response.json()
expect(responseData).toEqual({
success: true,
chats: [],
})
expect(responseData.success).toBe(true)
expect(Array.isArray(responseData.chats)).toBe(true)
expect(responseData.chats.length).toBe(0)
})
})
})
Loading