Skip to main content
Glama
2389-research

MCP Agent Social Media Server

index.test.ts16.8 kB
// ABOUTME: Tests for main entry point index.ts - simplified approach without complex mocking // ABOUTME: Tests exports, imports, and basic functionality that can be safely tested import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { jest } from '@jest/globals'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); describe('Main Index Module', () => { // Store original environment const originalEnv = process.env; const originalArgv = process.argv; const _originalExit = process.exit; const _originalStderr = process.stderr; beforeEach(() => { // Reset environment for each test process.env = { ...originalEnv }; process.argv = [...originalArgv]; // Set up basic required environment process.env.SOCIALMEDIA_API_BASE_URL = 'https://api.test.com'; process.env.SOCIALMEDIA_API_KEY = 'test-key'; process.env.SOCIALMEDIA_TEAM_ID = 'test-team'; process.env.LOG_LEVEL = 'silent'; }); afterEach(() => { // Restore original environment process.env = originalEnv; process.argv = originalArgv; }); describe('Module Loading', () => { test('should be able to test module dependencies', () => { // Test that we can validate module structure const indexPath = path.join(__dirname, '../src/index.ts'); expect(fs.existsSync(indexPath)).toBe(true); }); test('should have proper module file structure', () => { // Test that the module file exists and is readable const indexPath = path.join(__dirname, '../src/index.ts'); const stats = fs.statSync(indexPath); expect(stats.isFile()).toBe(true); expect(stats.size).toBeGreaterThan(0); }); }); describe('Environment Variable Dependencies', () => { test('should recognize required environment variables exist', () => { // Test that we have the basic environment setup expect(process.env.SOCIALMEDIA_API_BASE_URL).toBeTruthy(); expect(process.env.SOCIALMEDIA_API_KEY).toBeTruthy(); expect(process.env.SOCIALMEDIA_TEAM_ID).toBeTruthy(); }); test('should handle MCP transport environment variable', () => { process.env.MCP_TRANSPORT = 'http'; expect(process.env.MCP_TRANSPORT).toBe('http'); process.env.MCP_TRANSPORT = 'stdio'; expect(process.env.MCP_TRANSPORT).toBe('stdio'); process.env.MCP_TRANSPORT = undefined; expect(process.env.MCP_TRANSPORT).toBeUndefined(); }); test('should handle HTTP configuration variables', () => { process.env.MCP_HTTP_PORT = '3001'; process.env.MCP_HTTP_HOST = '0.0.0.0'; process.env.MCP_ENABLE_JSON = 'true'; process.env.MCP_CORS_ORIGIN = 'https://example.com'; expect(process.env.MCP_HTTP_PORT).toBe('3001'); expect(process.env.MCP_HTTP_HOST).toBe('0.0.0.0'); expect(process.env.MCP_ENABLE_JSON).toBe('true'); expect(process.env.MCP_CORS_ORIGIN).toBe('https://example.com'); }); test('should handle missing optional environment variables', () => { // Test that optional variables can be undefined process.env.MCP_TRANSPORT = undefined; process.env.MCP_HTTP_PORT = undefined; process.env.MCP_HTTP_HOST = undefined; process.env.MCP_ENABLE_JSON = undefined; process.env.MCP_CORS_ORIGIN = undefined; expect(process.env.MCP_TRANSPORT).toBeUndefined(); expect(process.env.MCP_HTTP_PORT).toBeUndefined(); expect(process.env.MCP_HTTP_HOST).toBeUndefined(); expect(process.env.MCP_ENABLE_JSON).toBeUndefined(); expect(process.env.MCP_CORS_ORIGIN).toBeUndefined(); }); }); describe('Process Utilities', () => { test('should be able to access process information', () => { expect(process.version).toBeDefined(); expect(process.platform).toBeDefined(); expect(process.pid).toBeDefined(); expect(typeof process.pid).toBe('number'); expect(process.uptime).toBeDefined(); expect(typeof process.uptime()).toBe('number'); }); test('should handle process event setup', () => { const originalOn = process.on; const mockOn = jest.fn(); process.on = mockOn; // Test that event listeners can be set up process.on('SIGINT', () => {}); process.on('SIGTERM', () => {}); process.on('uncaughtException', () => {}); process.on('unhandledRejection', () => {}); expect(mockOn).toHaveBeenCalledWith('SIGINT', expect.any(Function)); expect(mockOn).toHaveBeenCalledWith('SIGTERM', expect.any(Function)); expect(mockOn).toHaveBeenCalledWith('uncaughtException', expect.any(Function)); expect(mockOn).toHaveBeenCalledWith('unhandledRejection', expect.any(Function)); process.on = originalOn; }); test('should handle interval management', () => { // Test that intervals can be created and cleared const interval1 = setInterval(() => {}, 1000); const interval2 = setInterval(() => {}, 2000); expect(interval1).toBeDefined(); expect(interval2).toBeDefined(); clearInterval(interval1); clearInterval(interval2); // Should not throw when clearing intervals expect(() => { clearInterval(interval1); clearInterval(interval2); }).not.toThrow(); }); test('should handle timeout management', () => { // Test that timeouts can be created and cleared const timeout1 = setTimeout(() => {}, 1000); const timeout2 = setTimeout(() => {}, 2000); expect(timeout1).toBeDefined(); expect(timeout2).toBeDefined(); clearTimeout(timeout1); clearTimeout(timeout2); // Should not throw when clearing timeouts expect(() => { clearTimeout(timeout1); clearTimeout(timeout2); }).not.toThrow(); }); }); describe('Stdio Stream Handling', () => { test('should have access to stdio streams', () => { expect(process.stdin).toBeDefined(); expect(process.stdout).toBeDefined(); expect(process.stderr).toBeDefined(); }); test('should be able to set up stream event listeners', () => { const mockStdin = { on: jest.fn(), removeListener: jest.fn(), }; const mockStdout = { on: jest.fn(), removeListener: jest.fn(), }; // Test that event listeners can be attached to streams mockStdin.on('error', () => {}); mockStdin.on('close', () => {}); mockStdin.on('end', () => {}); mockStdout.on('error', () => {}); expect(mockStdin.on).toHaveBeenCalledWith('error', expect.any(Function)); expect(mockStdin.on).toHaveBeenCalledWith('close', expect.any(Function)); expect(mockStdin.on).toHaveBeenCalledWith('end', expect.any(Function)); expect(mockStdout.on).toHaveBeenCalledWith('error', expect.any(Function)); }); test('should handle stream error scenarios', () => { const testError = new Error('Stream test error'); // Test that error objects have expected properties expect(testError).toBeInstanceOf(Error); expect(testError.message).toBe('Stream test error'); expect(testError.stack).toBeDefined(); }); }); describe('Configuration Validation', () => { test('should handle valid configuration', () => { const validConfig = { SOCIALMEDIA_API_BASE_URL: 'https://api.example.com', SOCIALMEDIA_API_KEY: 'valid-key', SOCIALMEDIA_TEAM_ID: 'valid-team', }; // Test that valid configuration structure is accepted for (const [key, value] of Object.entries(validConfig)) { expect(typeof key).toBe('string'); expect(typeof value).toBe('string'); expect(key.length).toBeGreaterThan(0); expect(value.length).toBeGreaterThan(0); } }); test('should handle missing configuration gracefully in test environment', () => { // Test that we can detect missing configuration const originalApiUrl = process.env.SOCIALMEDIA_API_BASE_URL; process.env.SOCIALMEDIA_API_BASE_URL = undefined; expect(process.env.SOCIALMEDIA_API_BASE_URL).toBeUndefined(); // Restore for other tests process.env.SOCIALMEDIA_API_BASE_URL = originalApiUrl; }); test('should validate URL format requirements', () => { const validUrls = [ 'https://api.example.com', 'https://api.example.com/v1', 'http://localhost:3000', 'http://127.0.0.1:8080', ]; const invalidUrls = ['', 'not-a-url', 'ftp://example.com', 'file:///local/path']; for (const url of validUrls) { expect(url).toMatch(/^https?:\/\/.+/); } for (const url of invalidUrls) { expect(url).not.toMatch(/^https?:\/\/.+/); } }); }); describe('Transport Mode Logic', () => { test('should determine stdio as default transport mode', () => { process.env.MCP_TRANSPORT = undefined; const transportMode = process.env.MCP_TRANSPORT || 'stdio'; expect(transportMode).toBe('stdio'); }); test('should recognize http transport mode', () => { process.env.MCP_TRANSPORT = 'http'; const transportMode = process.env.MCP_TRANSPORT || 'stdio'; expect(transportMode).toBe('http'); }); test('should handle HTTP port parsing', () => { process.env.MCP_HTTP_PORT = '3001'; const httpPort = Number.parseInt(process.env.MCP_HTTP_PORT || '3000', 10); expect(httpPort).toBe(3001); expect(typeof httpPort).toBe('number'); process.env.MCP_HTTP_PORT = undefined; const defaultPort = Number.parseInt(process.env.MCP_HTTP_PORT || '3000', 10); expect(defaultPort).toBe(3000); }); test('should handle HTTP host configuration', () => { process.env.MCP_HTTP_HOST = '0.0.0.0'; const httpHost = process.env.MCP_HTTP_HOST || 'localhost'; expect(httpHost).toBe('0.0.0.0'); process.env.MCP_HTTP_HOST = undefined; const defaultHost = process.env.MCP_HTTP_HOST || 'localhost'; expect(defaultHost).toBe('localhost'); }); test('should handle boolean configuration flags', () => { process.env.MCP_ENABLE_JSON = 'true'; const enableJson = process.env.MCP_ENABLE_JSON === 'true'; expect(enableJson).toBe(true); process.env.MCP_ENABLE_JSON = 'false'; const disableJson = process.env.MCP_ENABLE_JSON === 'true'; expect(disableJson).toBe(false); process.env.MCP_ENABLE_JSON = undefined; const defaultJson = process.env.MCP_ENABLE_JSON === 'true'; expect(defaultJson).toBe(false); }); }); describe('Error Handling Utilities', () => { test('should handle error object creation', () => { const testError = new Error('Test error message'); expect(testError).toBeInstanceOf(Error); expect(testError.message).toBe('Test error message'); expect(testError.stack).toBeDefined(); }); test('should handle error serialization', () => { const error = new Error('Serialization test'); const errorInfo = { message: error.message, stack: error.stack, name: error.name, }; expect(errorInfo.message).toBe('Serialization test'); expect(errorInfo.stack).toBeDefined(); expect(errorInfo.name).toBe('Error'); }); test('should handle different error types', () => { const standardError = new Error('Standard error'); const typeError = new TypeError('Type error'); const rangeError = new RangeError('Range error'); expect(standardError.name).toBe('Error'); expect(typeError.name).toBe('TypeError'); expect(rangeError.name).toBe('RangeError'); for (const error of [standardError, typeError, rangeError]) { expect(error).toBeInstanceOf(Error); expect(error.message).toBeDefined(); expect(error.stack).toBeDefined(); } }); }); describe('Cleanup and Shutdown Logic', () => { test('should handle cleanup of resources', () => { const resources: Array<{ cleanup: () => void }> = []; const mockResource = { cleanup: jest.fn() }; resources.push(mockResource); // Simulate cleanup for (const resource of resources) resource.cleanup(); expect(mockResource.cleanup).toHaveBeenCalledTimes(1); }); test('should handle shutdown sequence', () => { const shutdownTasks: Array<() => Promise<void> | void> = []; shutdownTasks.push(() => Promise.resolve()); shutdownTasks.push(() => {}); shutdownTasks.push(() => Promise.resolve()); expect(shutdownTasks).toHaveLength(3); for (const task of shutdownTasks) { expect(typeof task).toBe('function'); } }); test('should handle exit codes', () => { const exitCodes = { SUCCESS: 0, GENERAL_ERROR: 1, CONFIG_ERROR: 1, NETWORK_ERROR: 1, }; expect(exitCodes.SUCCESS).toBe(0); expect(exitCodes.GENERAL_ERROR).toBe(1); expect(exitCodes.CONFIG_ERROR).toBe(1); expect(exitCodes.NETWORK_ERROR).toBe(1); }); }); describe('Timing and Intervals', () => { test('should handle cleanup interval timing', () => { const thirtyMinutesMs = 30 * 60 * 1000; const oneHourMs = 60 * 60 * 1000; expect(thirtyMinutesMs).toBe(1800000); expect(oneHourMs).toBe(3600000); expect(oneHourMs).toBeGreaterThan(thirtyMinutesMs); }); test('should handle keepalive interval timing', () => { const thirtySecondsMs = 30 * 1000; expect(thirtySecondsMs).toBe(30000); expect(thirtySecondsMs).toBeLessThan(60000); }); test('should calculate time differences', () => { const now = Date.now(); const earlier = now - 1000; const later = now + 1000; expect(now - earlier).toBe(1000); expect(later - now).toBe(1000); expect(later - earlier).toBe(2000); }); }); describe('Server Information', () => { test('should generate server metadata', () => { const serverInfo = { name: 'mcp-agent-social', toolsCount: 3, resourcesCount: 6, promptsCount: 8, rootsEnabled: true, transport: 'stdio', }; expect(serverInfo.name).toBe('mcp-agent-social'); expect(serverInfo.toolsCount).toBe(3); expect(serverInfo.resourcesCount).toBe(6); expect(serverInfo.promptsCount).toBe(8); expect(serverInfo.rootsEnabled).toBe(true); expect(serverInfo.transport).toBe('stdio'); }); test('should handle version information', () => { // Test version string format validation const versionPatterns = ['1.0.0', '1.1.0', '2.0.0-beta.1', '1.0.0-alpha.1']; for (const version of versionPatterns) { expect(version).toMatch(/^\d+\.\d+\.\d+/); } }); }); describe('Signal Handling', () => { test('should recognize standard signals', () => { const signals = ['SIGINT', 'SIGTERM', 'SIGUSR1', 'SIGUSR2']; for (const signal of signals) { expect(typeof signal).toBe('string'); expect(signal.startsWith('SIG')).toBe(true); } }); test('should handle signal information', () => { const signalHandlers = new Map(); signalHandlers.set('SIGINT', 'Interrupt signal'); signalHandlers.set('SIGTERM', 'Termination signal'); signalHandlers.set('uncaughtException', 'Uncaught exception handler'); signalHandlers.set('unhandledRejection', 'Unhandled promise rejection'); expect(signalHandlers.size).toBe(4); expect(signalHandlers.get('SIGINT')).toBe('Interrupt signal'); expect(signalHandlers.get('SIGTERM')).toBe('Termination signal'); }); }); describe('Module Integration Points', () => { test('should validate expected module files exist', () => { // Test that the main dependencies exist as files const modules = [ 'src/api-client.ts', 'src/config.ts', 'src/logger.ts', 'src/metrics.ts', 'src/session-manager.ts', ]; for (const modulePath of modules) { const fullPath = path.join(__dirname, '..', modulePath); expect(fs.existsSync(fullPath)).toBe(true); } }); test('should handle component initialization order', () => { const initOrder = [ 'config-validation', 'logger-setup', 'session-manager', 'api-client', 'server-creation', 'transport-connection', 'signal-handlers', 'intervals', ]; expect(initOrder).toHaveLength(8); expect(initOrder[0]).toBe('config-validation'); expect(initOrder[initOrder.length - 1]).toBe('intervals'); }); }); });

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/2389-research/mcp-socialmedia'

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