Skip to main content
Glama
test-utils.ts4.39 kB
import WebSocket from 'ws'; import { getTestMonorepoPath } from '@test/shared/workspace'; import { getWorkspacePath } from '@test/vitest/workspace'; import { WS_MESSAGE_TYPES, TIMEOUTS } from '@/constants'; /** * Test environment utilities and constants */ // Test environment detection export const isTestEnvironment = process.env.VSCODE_TEST === '1'; // Common paths export const TEST_FIXTURES_PATH = getTestMonorepoPath(); export const TEST_MONOREPO_PATH = getTestMonorepoPath(); /** * Gets the test workspace path based on environment */ export { getWorkspacePath as getTestWorkspacePath }; /** * Common WebSocket test utilities */ export interface WsTestOptions { origin?: string; timeout?: number; } /** * Creates a WebSocket connection for testing with timeout */ export const createTestWebSocket = (url: string, options: WsTestOptions = {}): Promise<WebSocket> => { const { origin, timeout = TIMEOUTS.STANDARD } = options; return new Promise((resolve, reject) => { const ws = new WebSocket(url, { origin }); const timeoutId = setTimeout(() => { ws.close(); reject(new Error(`WebSocket connection timed out after ${timeout}ms`)); }, timeout); ws.on('open', () => { clearTimeout(timeoutId); resolve(ws); }); ws.on('error', (error) => { clearTimeout(timeoutId); reject(error); }); }); }; /** * Waits for a specific message type from WebSocket */ export const waitForWsMessage = <T = any>( ws: WebSocket, expectedType: string, timeout: number = TIMEOUTS.STANDARD ): Promise<{ type: string; payload: T }> => { return new Promise((resolve, reject) => { const timeoutId = setTimeout(() => { cleanup(); reject(new Error(`Timeout waiting for message type "${expectedType}" after ${timeout}ms`)); }, timeout); const messageHandler = (data: WebSocket.Data) => { try { const message = JSON.parse(data.toString()); if (message.type === expectedType) { cleanup(); resolve(message); } else if (message.type === WS_MESSAGE_TYPES.ERROR) { cleanup(); reject(new Error(`Received error: ${message.payload}`)); } } catch (error) { cleanup(); reject(error); } }; const errorHandler = (error: Error) => { cleanup(); reject(error); }; const cleanup = () => { clearTimeout(timeoutId); ws.removeListener('message', messageHandler); ws.removeListener('error', errorHandler); }; ws.on('message', messageHandler); ws.on('error', errorHandler); }); }; /** * VS Code mock utilities */ export const createMockVsCodeApi = () => { return { ExtensionContext: class { subscriptions: any[] = []; extensionPath: string = ''; storagePath: string = ''; globalState = { get: () => undefined, update: () => Promise.resolve() }; workspaceState = { get: () => undefined, update: () => Promise.resolve() }; }, window: { createWebviewPanel: () => ({ webview: { html: '', onDidReceiveMessage: () => ({ dispose: () => {} }), postMessage: () => Promise.resolve() }, onDidDispose: () => ({ dispose: () => {} }), dispose: () => {} }), showErrorMessage: () => Promise.resolve(), showInformationMessage: () => Promise.resolve() }, workspace: { getConfiguration: () => ({ get: () => undefined, update: () => Promise.resolve() }), workspaceFolders: [{ uri: { fsPath: getTestMonorepoPath() } }] }, commands: { registerCommand: () => ({ dispose: () => {} }) }, Uri: { file: (path: string) => ({ fsPath: path }), parse: (path: string) => ({ fsPath: path }) }, EventEmitter: class { event = () => ({ dispose: () => {} }); fire() {} dispose() {} }, ViewColumn: { One: 1, Two: 2, Three: 3 }, WebviewPanel: class { constructor() { this.webview = { html: '', onDidReceiveMessage: () => ({ dispose: () => {} }), postMessage: () => Promise.resolve() }; } webview: any; onDidDispose = () => ({ dispose: () => {} }); dispose = () => {}; } }; };

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/patelnav/my-tools-mcp'

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