Skip to main content
Glama
index.test.js9.82 kB
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import request from 'supertest'; import express from 'express'; import helmet from 'helmet'; // Mock dependencies before importing vi.mock('dotenv', () => ({ default: { config: vi.fn() }, })); vi.mock('../utils/logger.js', () => ({ createContextLogger: vi.fn().mockReturnValue({ info: vi.fn(), error: vi.fn(), warn: vi.fn(), debug: vi.fn(), }), })); // Create a mock app for testing (since index.js starts servers on import) function createTestApp() { const app = express(); app.use( helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], scriptSrc: ["'self'"], imgSrc: ["'self'", 'data:', 'https:'], connectSrc: ["'self'"], fontSrc: ["'self'"], objectSrc: ["'none'"], mediaSrc: ["'self'"], frameSrc: ["'none'"], }, }, hsts: { maxAge: 31536000, includeSubDomains: true, preload: true, }, }) ); app.use(express.json({ limit: '1mb', strict: true, type: 'application/json' })); app.use(express.urlencoded({ extended: true, limit: '1mb', parameterLimit: 100 })); // Health check endpoint app.get('/health', (req, res) => { res.status(200).json({ status: 'ok', message: 'Server is running' }); }); // Mock routes app.use('/api/posts', (req, res) => res.json({ route: 'posts' })); app.use('/api/images', (req, res) => res.json({ route: 'images' })); app.use('/api/tags', (req, res) => res.json({ route: 'tags' })); // Global error handler app.use((err, req, res, _next) => { const statusCode = err.statusCode || err.response?.status || 500; res.status(statusCode).json({ message: err.message || 'Internal Server Error', stack: process.env.NODE_ENV === 'development' ? err.stack : undefined, }); }); return app; } describe('index.js Express Application', () => { let app; beforeEach(() => { app = createTestApp(); }); describe('Health Check Endpoint', () => { it('should return 200 status on /health', async () => { const response = await request(app).get('/health'); expect(response.status).toBe(200); }); it('should return ok status in response body', async () => { const response = await request(app).get('/health'); expect(response.body.status).toBe('ok'); }); it('should return server running message', async () => { const response = await request(app).get('/health'); expect(response.body.message).toBe('Server is running'); }); }); describe('Security Headers (Helmet)', () => { it('should set X-Content-Type-Options header', async () => { const response = await request(app).get('/health'); expect(response.headers['x-content-type-options']).toBe('nosniff'); }); it('should set X-Frame-Options header', async () => { const response = await request(app).get('/health'); expect(response.headers['x-frame-options']).toBe('SAMEORIGIN'); }); it('should set Strict-Transport-Security header', async () => { const response = await request(app).get('/health'); expect(response.headers['strict-transport-security']).toContain('max-age=31536000'); }); it('should set Content-Security-Policy header', async () => { const response = await request(app).get('/health'); expect(response.headers['content-security-policy']).toBeDefined(); }); }); describe('Body Parser Middleware', () => { it('should parse JSON body', async () => { // Create app with test route const testApp = express(); testApp.use(express.json({ limit: '1mb' })); testApp.post('/test', (req, res) => { res.json({ received: req.body }); }); const response = await request(testApp) .post('/test') .set('Content-Type', 'application/json') .send({ name: 'test' }); expect(response.body.received).toEqual({ name: 'test' }); }); it('should parse URL-encoded body', async () => { const testApp = express(); testApp.use(express.urlencoded({ extended: true })); testApp.post('/test', (req, res) => { res.json({ received: req.body }); }); const response = await request(testApp) .post('/test') .set('Content-Type', 'application/x-www-form-urlencoded') .send('name=test&value=123'); expect(response.body.received).toEqual({ name: 'test', value: '123' }); }); it('should reject JSON body larger than 1mb', async () => { const testApp = express(); testApp.use(express.json({ limit: '1mb' })); testApp.post('/test', (req, res) => { res.json({ received: true }); }); // Create a large payload (>1MB) const largePayload = { data: 'x'.repeat(1024 * 1024 + 1000) }; const response = await request(testApp) .post('/test') .set('Content-Type', 'application/json') .send(largePayload); expect(response.status).toBe(413); }); }); describe('Route Mounting', () => { it('should mount post routes at /api/posts', async () => { const response = await request(app).get('/api/posts'); expect(response.body.route).toBe('posts'); }); it('should mount image routes at /api/images', async () => { const response = await request(app).get('/api/images'); expect(response.body.route).toBe('images'); }); it('should mount tag routes at /api/tags', async () => { const response = await request(app).get('/api/tags'); expect(response.body.route).toBe('tags'); }); }); describe('Global Error Handler', () => { let originalEnv; beforeEach(() => { originalEnv = process.env.NODE_ENV; }); afterEach(() => { process.env.NODE_ENV = originalEnv; }); it('should return 500 for unhandled errors', async () => { const testApp = express(); testApp.get('/error', (_req, _res, next) => { next(new Error('Test error')); }); testApp.use((err, req, res, _next) => { const statusCode = err.statusCode || 500; res.status(statusCode).json({ message: err.message }); }); const response = await request(testApp).get('/error'); expect(response.status).toBe(500); expect(response.body.message).toBe('Test error'); }); it('should use custom statusCode if provided', async () => { const testApp = express(); testApp.get('/error', (_req, _res, next) => { const error = new Error('Not found'); error.statusCode = 404; next(error); }); testApp.use((err, req, res, _next) => { const statusCode = err.statusCode || 500; res.status(statusCode).json({ message: err.message }); }); const response = await request(testApp).get('/error'); expect(response.status).toBe(404); }); it('should include stack trace in development mode', async () => { process.env.NODE_ENV = 'development'; const testApp = express(); testApp.get('/error', (_req, _res, next) => { next(new Error('Test error')); }); testApp.use((err, req, res, _next) => { res.status(500).json({ message: err.message, stack: process.env.NODE_ENV === 'development' ? err.stack : undefined, }); }); const response = await request(testApp).get('/error'); expect(response.body.stack).toBeDefined(); }); it('should not include stack trace in production mode', async () => { process.env.NODE_ENV = 'production'; const testApp = express(); testApp.get('/error', (_req, _res, next) => { next(new Error('Test error')); }); testApp.use((err, req, res, _next) => { res.status(500).json({ message: err.message, stack: process.env.NODE_ENV === 'development' ? err.stack : undefined, }); }); const response = await request(testApp).get('/error'); expect(response.body.stack).toBeUndefined(); }); it('should use response status from error.response.status', async () => { const testApp = express(); testApp.get('/error', (_req, _res, next) => { const error = new Error('Service unavailable'); error.response = { status: 503 }; next(error); }); testApp.use((err, req, res, _next) => { const statusCode = err.statusCode || err.response?.status || 500; res.status(statusCode).json({ message: err.message }); }); const response = await request(testApp).get('/error'); expect(response.status).toBe(503); }); }); describe('404 Handling', () => { it('should return 404 for unknown routes', async () => { const testApp = express(); testApp.get('/known', (req, res) => res.json({ ok: true })); testApp.use((req, res) => { res.status(404).json({ message: 'Not Found' }); }); const response = await request(testApp).get('/unknown-route'); expect(response.status).toBe(404); }); }); }); describe('Server Startup', () => { it('should export startServers functionality (indirect test)', async () => { // Since index.js auto-starts servers on import, we test the concept indirectly // by verifying the app structure works correctly const app = express(); let serverStarted = false; app.get('/health', (req, res) => res.json({ status: 'ok' })); // Simulate startServers pattern const mockStartServers = async () => { serverStarted = true; }; await mockStartServers(); expect(serverStarted).toBe(true); }); });

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/jgardner04/Ghost-MCP-Server'

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