Skip to main content
Glama
conversation-api.test.ts6.5 kB
import { TestServer } from '../test-utils/test-server.js'; describe('Conversation API', () => { let server: TestServer; beforeEach(async () => { server = new TestServer(); await server.start(); }); afterEach(async () => { await server.stop(); }); describe('GET /api/conversation', () => { it('should return empty array when no messages exist', async () => { const response = await fetch(`${server.url}/api/conversation`); const data = await response.json() as any; expect(response.status).toBe(200); expect(data.messages).toEqual([]); }); it('should include user message after posting utterance', async () => { // Enable voice input await fetch(`${server.url}/api/voice-input`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ active: true }) }); // Add a user utterance await fetch(`${server.url}/api/potential-utterances`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Hello world' }) }); // Fetch conversation const response = await fetch(`${server.url}/api/conversation`); const data = await response.json() as any; expect(response.status).toBe(200); expect(data.messages.length).toBe(1); expect(data.messages[0]).toMatchObject({ role: 'user', text: 'Hello world', status: 'pending' }); expect(data.messages[0].id).toBeDefined(); expect(data.messages[0].timestamp).toBeDefined(); }); it('should include assistant message after speak is called', async () => { // Enable voice responses await fetch(`${server.url}/api/voice-responses`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled: true }) }); // Call speak endpoint await fetch(`${server.url}/api/speak`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Assistant response' }) }); // Fetch conversation const response = await fetch(`${server.url}/api/conversation`); const data = await response.json() as any; expect(response.status).toBe(200); expect(data.messages.length).toBe(1); expect(data.messages[0]).toMatchObject({ role: 'assistant', text: 'Assistant response' }); expect(data.messages[0].id).toBeDefined(); expect(data.messages[0].timestamp).toBeDefined(); expect(data.messages[0].status).toBeUndefined(); // Assistant messages don't have status }); it('should sync status updates between utterances and messages', async () => { // Enable voice input and responses await fetch(`${server.url}/api/voice-input`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ active: true }) }); await fetch(`${server.url}/api/voice-responses`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled: true }) }); // Add user message const addResponse = await fetch(`${server.url}/api/potential-utterances`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'User message' }) }); const addData = await addResponse.json() as any; const messageId = addData.utterance.id; // Check status is pending in conversation let convResponse = await fetch(`${server.url}/api/conversation`); let convData = await convResponse.json() as any; expect(convData.messages[0].status).toBe('pending'); // Dequeue (should mark as delivered) await fetch(`${server.url}/api/dequeue-utterances`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); // Check status is delivered in conversation convResponse = await fetch(`${server.url}/api/conversation`); convData = await convResponse.json() as any; expect(convData.messages[0].status).toBe('delivered'); // Speak (should mark as responded) await fetch(`${server.url}/api/speak`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Response' }) }); // Check status is responded in conversation convResponse = await fetch(`${server.url}/api/conversation`); convData = await convResponse.json() as any; const userMessage = convData.messages.find((m: any) => m.id === messageId); expect(userMessage.status).toBe('responded'); }); it('should return messages in chronological order (oldest first)', async () => { // Enable voice input and responses await fetch(`${server.url}/api/voice-input`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ active: true }) }); await fetch(`${server.url}/api/voice-responses`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled: true }) }); // Add messages with small delays to ensure proper ordering await fetch(`${server.url}/api/potential-utterances`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'First message' }) }); await new Promise(resolve => setTimeout(resolve, 10)); await fetch(`${server.url}/api/speak`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Assistant reply' }) }); await new Promise(resolve => setTimeout(resolve, 10)); await fetch(`${server.url}/api/potential-utterances`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Third message' }) }); // Fetch conversation const response = await fetch(`${server.url}/api/conversation`); const data = await response.json() as any; expect(data.messages.length).toBe(3); expect(data.messages[0].text).toBe('First message'); expect(data.messages[1].text).toBe('Assistant reply'); expect(data.messages[2].text).toBe('Third message'); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/johnmatthewtennant/mcp-voice-hooks'

If you have feedback or need assistance with the MCP directory API, please join our Discord server