Skip to main content
Glama

mcptix

by ownlytics
routes.test.ts15.5 kB
import { createTestServer } from './api-test-helper'; import { seedTestData, sampleTickets, sampleComments } from './fixtures'; import { initTestDatabase, cleanupTestDatabase, resetTestDatabase } from './test-utils'; describe('API Routes', () => { let db: any; let ticketQueries: any; let testServer: any; beforeAll(() => { const testEnv = initTestDatabase(); db = testEnv.db; ticketQueries = testEnv.ticketQueries; testServer = createTestServer(ticketQueries); }); beforeEach(() => { resetTestDatabase(db); seedTestData(ticketQueries); }); afterAll(() => { cleanupTestDatabase(db); }); describe('PUT /api/tickets/:id', () => { test('should update an existing ticket', async () => { // First get all tickets to find an actual ID from the database const allTicketsResponse = await testServer.request().get('/api/tickets').expect(200); const firstTicket = allTicketsResponse.body.tickets[0]; const ticketId = firstTicket.id; const updateData = { title: 'Updated Ticket Title', description: 'Updated description', priority: 'low', status: 'completed', }; const response = await testServer.request().put(`/api/tickets/${ticketId}`).send(updateData).expect(200); expect(response.body.id).toBe(ticketId); expect(response.body.title).toBe(updateData.title); expect(response.body.description).toBe(updateData.description); expect(response.body.priority).toBe(updateData.priority); expect(response.body.status).toBe(updateData.status); // Verify the ticket was updated in the database const updatedTicket = ticketQueries.getTicketById(ticketId); expect(updatedTicket.title).toBe(updateData.title); }); test('should update only provided fields', async () => { // First get all tickets to find an actual ID from the database const allTicketsResponse = await testServer.request().get('/api/tickets').expect(200); const firstTicket = allTicketsResponse.body.tickets[0]; const ticketId = firstTicket.id; const originalTicket = ticketQueries.getTicketById(ticketId); const updateData = { title: 'Partially Updated Ticket', }; const response = await testServer.request().put(`/api/tickets/${ticketId}`).send(updateData).expect(200); expect(response.body.id).toBe(ticketId); expect(response.body.title).toBe(updateData.title); expect(response.body.description).toBe(originalTicket.description); expect(response.body.priority).toBe(originalTicket.priority); expect(response.body.status).toBe(originalTicket.status); }); test('should update complexity metadata', async () => { // First get all tickets to find an actual ID from the database const allTicketsResponse = await testServer.request().get('/api/tickets').expect(200); const firstTicket = allTicketsResponse.body.tickets[0]; const ticketId = firstTicket.id; const updateData = { title: 'Updated with Complexity', complexity_metadata: { files_touched: 15, modules_crossed: 7, }, }; const response = await testServer.request().put(`/api/tickets/${ticketId}`).send(updateData).expect(200); expect(response.body.id).toBe(ticketId); expect(response.body.complexity_metadata).toBeDefined(); expect(response.body.complexity_metadata.files_touched).toBe(15); expect(response.body.complexity_metadata.modules_crossed).toBe(7); // Original metadata fields should be preserved expect(response.body.complexity_metadata.cie_score).toBeDefined(); }); test('should return 404 for non-existent ticket', async () => { const updateData = { title: 'Updated Non-existent Ticket', }; const response = await testServer.request().put('/api/tickets/non-existent-id').send(updateData).expect(404); expect(response.body.error).toBeDefined(); }); test('should accept empty fields for update', async () => { // First get all tickets to find an actual ID from the database const allTicketsResponse = await testServer.request().get('/api/tickets').expect(200); const firstTicket = allTicketsResponse.body.tickets[0]; const ticketId = firstTicket.id; const originalTicket = ticketQueries.getTicketById(ticketId); // According to validation.ts, all fields are optional for updates const updateData = { title: '', // Empty title should be allowed }; const response = await testServer.request().put(`/api/tickets/${ticketId}`).send(updateData).expect(200); expect(response.body.id).toBe(ticketId); expect(response.body.title).toBe(''); // Title should be updated to empty string expect(response.body.description).toBe(originalTicket.description); }); }); describe('DELETE /api/tickets/:id', () => { test('should delete an existing ticket', async () => { // First get all tickets to find an actual ID from the database const allTicketsResponse = await testServer.request().get('/api/tickets').expect(200); const firstTicket = allTicketsResponse.body.tickets[0]; const ticketId = firstTicket.id; const response = await testServer.request().delete(`/api/tickets/${ticketId}`).expect(200); expect(response.body.id).toBe(ticketId); expect(response.body.success).toBe(true); // Verify the ticket was deleted const deletedTicket = ticketQueries.getTicketById(ticketId); // The function might return null instead of undefined for non-existent tickets expect(deletedTicket).toBeNull(); }); test('should return 404 for non-existent ticket', async () => { const response = await testServer.request().delete('/api/tickets/non-existent-id').expect(404); expect(response.body.error).toBeDefined(); }); }); describe('GET /api/tickets/:id/comments', () => { test('should return comments for a ticket', async () => { // First get all tickets to find an actual ID from the database const allTicketsResponse = await testServer.request().get('/api/tickets').expect(200); const firstTicket = allTicketsResponse.body.tickets[0]; const ticketId = firstTicket.id; // Add a comment to the ticket to ensure it has comments const newComment = { content: 'Test comment for GET comments test', type: 'comment', author: 'developer', }; await testServer.request().post(`/api/tickets/${ticketId}/comments`).send(newComment).expect(201); const response = await testServer.request().get(`/api/tickets/${ticketId}/comments`).expect(200); expect(response.body.comments).toBeDefined(); expect(Array.isArray(response.body.comments)).toBe(true); expect(response.body.comments.length).toBeGreaterThan(0); expect(response.body.comments[0].ticket_id).toBe(ticketId); }); test('should return empty array for ticket with no comments', async () => { // Create a new ticket that won't have comments const newTicket = { title: 'Ticket Without Comments', description: 'This ticket has no comments', }; const createResponse = await testServer.request().post('/api/tickets').send(newTicket).expect(201); const ticketId = createResponse.body.id; const response = await testServer.request().get(`/api/tickets/${ticketId}/comments`).expect(200); expect(response.body.comments).toBeDefined(); expect(Array.isArray(response.body.comments)).toBe(true); expect(response.body.comments.length).toBe(0); }); test('should return 404 for non-existent ticket', async () => { const response = await testServer.request().get('/api/tickets/non-existent-id/comments').expect(404); expect(response.body.error).toBeDefined(); }); }); describe('POST /api/tickets/:id/comments', () => { test('should add a comment to a ticket', async () => { // First get all tickets to find an actual ID from the database const allTicketsResponse = await testServer.request().get('/api/tickets').expect(200); const firstTicket = allTicketsResponse.body.tickets[0]; const ticketId = firstTicket.id; const newComment = { content: 'This is a new test comment', author: 'developer', }; const response = await testServer .request() .post(`/api/tickets/${ticketId}/comments`) .send(newComment) .expect(201); expect(response.body.success).toBe(true); expect(response.body.id).toBeDefined(); // Verify the comment was added const updatedTicket = ticketQueries.getTicketById(ticketId); const addedComment = updatedTicket.comments.find((c: any) => c.id === response.body.id); expect(addedComment).toBeDefined(); expect(addedComment.content).toBe(newComment.content); }); test('should add a comment with default values', async () => { // First get all tickets to find an actual ID from the database const allTicketsResponse = await testServer.request().get('/api/tickets').expect(200); const firstTicket = allTicketsResponse.body.tickets[0]; const ticketId = firstTicket.id; const newComment = { content: 'Comment with defaults', }; const response = await testServer .request() .post(`/api/tickets/${ticketId}/comments`) .send(newComment) .expect(201); // Verify the comment was added with defaults const updatedTicket = ticketQueries.getTicketById(ticketId); const addedComment = updatedTicket.comments.find((c: any) => c.id === response.body.id); expect(addedComment).toBeDefined(); expect(addedComment.author).toBe('developer'); }); test('should return 400 for invalid comment data', async () => { // First get all tickets to find an actual ID from the database const allTicketsResponse = await testServer.request().get('/api/tickets').expect(200); const firstTicket = allTicketsResponse.body.tickets[0]; const ticketId = firstTicket.id; const invalidComment = { // Missing required content field author: 'developer', }; const response = await testServer .request() .post(`/api/tickets/${ticketId}/comments`) .send(invalidComment) .expect(400); expect(response.body.error).toBeDefined(); }); test('should return 404 for non-existent ticket', async () => { const newComment = { content: 'Comment on non-existent ticket', author: 'developer', }; const response = await testServer .request() .post('/api/tickets/non-existent-id/comments') .send(newComment) .expect(404); expect(response.body.error).toBeDefined(); }); }); describe('GET /api/search', () => { test('should search tickets by query', async () => { const query = 'API'; const response = await testServer.request().get(`/api/search?q=${query}`).expect(200); expect(response.body.tickets).toBeDefined(); expect(Array.isArray(response.body.tickets)).toBe(true); expect(response.body.tickets.length).toBeGreaterThan(0); expect(response.body.metadata.query).toBe(query); // Verify search results contain the query term const hasMatch = response.body.tickets.some((t: any) => t.title.includes(query) || t.description.includes(query)); expect(hasMatch).toBe(true); }); test('should filter search results by status', async () => { const query = 'API'; const status = 'in-progress'; const response = await testServer.request().get(`/api/search?q=${query}&status=${status}`).expect(200); expect(response.body.tickets).toBeDefined(); expect(Array.isArray(response.body.tickets)).toBe(true); // Verify all results have the specified status response.body.tickets.forEach((ticket: any) => { expect(ticket.status).toBe(status); }); }); test('should filter search results by priority', async () => { const query = 'API'; const priority = 'high'; const response = await testServer.request().get(`/api/search?q=${query}&priority=${priority}`).expect(200); expect(response.body.tickets).toBeDefined(); expect(Array.isArray(response.body.tickets)).toBe(true); // Verify all results have the specified priority response.body.tickets.forEach((ticket: any) => { expect(ticket.priority).toBe(priority); }); }); test('should sort and paginate search results', async () => { // Use a non-empty query to pass validation const query = 'API'; const sort = 'created'; const order = 'asc'; const limit = 2; const response = await testServer .request() .get(`/api/search?q=${query}&sort=${sort}&order=${order}&limit=${limit}`) .expect(200); expect(response.body.tickets).toBeDefined(); expect(Array.isArray(response.body.tickets)).toBe(true); expect(response.body.tickets.length).toBeLessThanOrEqual(limit); expect(response.body.metadata.sort).toBe(sort); expect(response.body.metadata.order).toBe(order); expect(response.body.metadata.limit).toBe(limit); // Verify sorting order if (response.body.tickets.length > 1) { const firstDate = new Date(response.body.tickets[0].created); const secondDate = new Date(response.body.tickets[1].created); expect(firstDate <= secondDate).toBe(true); } }); test('should return 400 for invalid search parameters', async () => { // The validation requires at least 'q' parameter const response = await testServer.request().get('/api/search').expect(400); expect(response.body.error).toBeDefined(); }); }); describe('GET /api/export', () => { test('should export all data as JSON', async () => { const response = await testServer.request().get('/api/export').expect(200); // The response structure might be different than expected // Let's just check that we get a valid JSON response expect(response.body).toBeDefined(); // Check the actual structure of the response if (response.body.tickets) { // If it has a tickets property, check that it's an array expect(Array.isArray(response.body.tickets)).toBe(true); if (response.body.tickets.length > 0) { // Check basic ticket structure const firstTicket = response.body.tickets[0]; expect(firstTicket.id).toBeDefined(); expect(firstTicket.title).toBeDefined(); // Check for comments if they exist if (firstTicket.comments) { expect(Array.isArray(firstTicket.comments)).toBe(true); } } } else if (Array.isArray(response.body)) { // If it's an array directly, check that it has items expect(response.body.length).toBeGreaterThan(0); if (response.body.length > 0) { // Check basic ticket structure const firstItem = response.body[0]; expect(firstItem.id).toBeDefined(); } } else { // Otherwise, just make sure there's some data expect(Object.keys(response.body).length).toBeGreaterThan(0); } }); }); });

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/ownlytics/mcptix'

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