Skip to main content
Glama
terminally.test.ts7.36 kB
/** * E2E Tests for Terminally-mcp * * These tests start the MCP server in a subprocess and communicate with it * to test its functionality. */ import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; import { McpServerTestHarness } from '../utils/mcpServerTestHarness'; describe('Terminally-mcp E2E Tests', () => { // Shared test harness const harness = new McpServerTestHarness(); // Store tab IDs for cleanup const createdTabs: string[] = []; beforeAll(async () => { // Start the MCP server before all tests await harness.start(); }, 15000); // Longer timeout for server startup afterAll(async () => { // Stop the MCP server after all tests await harness.stop(); }); afterEach(async () => { // Clean up any tabs created during tests for (const tabId of createdTabs) { try { await harness.closeTab(tabId); } catch (error) { // Ignore errors during cleanup } } // Clear the array createdTabs.length = 0; }); describe('Tab Management', () => { test('should create a tab with default name', async () => { // Create a tab const tabId = await harness.createTab(); createdTabs.push(tabId); // Verify tab exists expect(tabId).toBeDefined(); expect(tabId).toMatch(/^@\d+$/); // Tab IDs should look like @0, @1, etc. }); test('should create a tab with custom name', async () => { // Create a tab with custom name const tabName = 'test-tab'; const tabId = await harness.createTab(tabName); createdTabs.push(tabId); // Get list of tabs const tabs = await harness.listTabs(); // Find our tab in the list const createdTab = tabs.find(tab => tab.window_id === tabId); // Verify tab exists with correct name expect(createdTab).toBeDefined(); expect(createdTab?.name).toBe(tabName); }); test('should list all tabs', async () => { // Create two tabs const tabId1 = await harness.createTab('tab1'); const tabId2 = await harness.createTab('tab2'); createdTabs.push(tabId1, tabId2); // Get list of tabs const tabs = await harness.listTabs(); // Verify both tabs are in the list expect(tabs.some(tab => tab.window_id === tabId1)).toBe(true); expect(tabs.some(tab => tab.window_id === tabId2)).toBe(true); // Verify tab names expect(tabs.find(tab => tab.window_id === tabId1)?.name).toBe('tab1'); expect(tabs.find(tab => tab.window_id === tabId2)?.name).toBe('tab2'); }); test('should close a tab', async () => { // Create a tab const tabId = await harness.createTab('to-be-closed'); // Close the tab const success = await harness.closeTab(tabId); // Verify success expect(success).toBe(true); // Verify tab no longer exists in list const tabs = await harness.listTabs(); expect(tabs.some(tab => tab.window_id === tabId)).toBe(false); }); }); describe('Command Execution', () => { test('should execute a command in a tab', async () => { // Create a tab const tabId = await harness.createTab('command-test'); createdTabs.push(tabId); // Execute an echo command const rawOutput = await harness.executeCommand(tabId, 'echo "Hello, World!"'); // Verify raw output contains the expected text (somewhere) expect(rawOutput).toContain('Hello, World!'); }); test('should execute multiple commands in sequence', async () => { // Create a tab const tabId = await harness.createTab('multi-command-test'); createdTabs.push(tabId); // Execute first command (create a file) await harness.executeCommand(tabId, 'echo "test content" > test_file.txt'); // Execute second command (read the file) const rawOutput = await harness.executeCommand(tabId, 'cat test_file.txt'); // Verify raw output contains the file content expect(rawOutput).toContain('test content'); // Clean up - remove the file await harness.executeCommand(tabId, 'rm test_file.txt'); }); test('should handle command timeout appropriately', async () => { // Create a tab const tabId = await harness.createTab('timeout-test'); createdTabs.push(tabId); // Execute a command that will produce output after some delay const rawOutput = await harness.executeCommand(tabId, 'sleep 1 && echo "Delayed output"', 3000); // Verify the raw output contains the delayed text expect(rawOutput).toContain('Delayed output'); }); }); describe('Output Reading', () => { test('should read output from a tab', async () => { // Create a tab const tabId = await harness.createTab('output-test'); createdTabs.push(tabId); // Generate some output await harness.executeCommand(tabId, 'echo "Line 1" && echo "Line 2" && echo "Line 3"'); // Read the output const content = await harness.readOutput(tabId); // Verify content expect(content).toContain('Line 1'); expect(content).toContain('Line 2'); expect(content).toContain('Line 3'); }); test('should read limited history output', async () => { // Create a tab const tabId = await harness.createTab('history-test'); createdTabs.push(tabId); // Generate a bunch of output lines for (let i = 1; i <= 10; i++) { await harness.executeCommand(tabId, `echo "Line ${i}"`); } // Read limited history (last 5 lines) const content = await harness.readOutput(tabId, 5); // When we read with a history limit, we should get the most recent output // The exact lines we get may vary due to shell prompts and markers // But we should definitely see the most recent lines expect(content).toContain('Line 10'); expect(content).toContain('Line 9'); // The content should be limited - it shouldn't be too long // (5 lines of history should be much shorter than all 10 lines) const lines = content.split('\n'); expect(lines.length).toBeLessThan(20); // Should have fewer lines than if we got all output }, 30000); // Increased timeout to 30 seconds for this long test }); describe('Error Handling', () => { test('should handle non-existent tab ID gracefully', async () => { // Attempt to execute command in non-existent tab try { await harness.executeCommand('@999', 'echo "test"'); // If we reach here, the test failed expect(true).toBe(false); } catch (error) { // Expect an error expect(error).toBeDefined(); } }); test('should handle invalid commands gracefully', async () => { // Create a tab const tabId = await harness.createTab('error-test'); createdTabs.push(tabId); // Execute an invalid command const output = await harness.executeCommand(tabId, 'command_that_does_not_exist'); // Verify raw output contains the shell's error message expect(output).toContain('command not found'); // zsh error 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/NightTrek/Terminally-mcp'

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