@toolprint/hypertool-mcp
Version:
HyperTool MCP proxy server for routing requests between clients and multiple underlying MCP servers
159 lines • 4.69 kB
JavaScript
/**
* Lightweight test utilities for HyperTool MCP tests
* Replaces heavyweight TestEnvironment with focused utilities
*/
import { vol } from "memfs";
import { join } from "path";
/**
* Creates minimal filesystem structure for tests
* Much lighter than TestEnvironment - only creates what's needed
*/
export function createMinimalFs(options = {}) {
const baseDir = options.baseDir || "/tmp/hypertool-test";
const configRoot = join(baseDir, ".hypertool");
// Reset memfs for clean state
vol.reset();
// Create only the essential directories
vol.mkdirSync(configRoot, { recursive: true });
if (options.createRegistry) {
const appsDir = join(configRoot, "apps");
vol.mkdirSync(appsDir, { recursive: true });
// Create minimal registry
const registry = {
version: "1.0.0",
applications: {
cursor: {
name: "Cursor IDE",
enabled: true,
platforms: {
all: {
configPath: "~/.cursor/mcp.json",
format: "standard",
},
},
detection: {
type: "directory",
path: "~/.cursor",
},
},
},
};
vol.writeFileSync(join(appsDir, "registry.json"), JSON.stringify(registry, null, 2));
}
if (options.createConfig) {
vol.writeFileSync(join(configRoot, "config.json"), JSON.stringify({ version: "1.0.0", applications: {} }, null, 2));
}
return {
baseDir,
configRoot,
cleanup: () => vol.reset(),
};
}
/**
* Creates a mock application structure
* Lightweight alternative to TestEnvironment.createMockApp
*/
export function createMockApp(appId, files) {
for (const [path, content] of Object.entries(files)) {
const dir = path.substring(0, path.lastIndexOf("/"));
if (dir) {
vol.mkdirSync(dir, { recursive: true });
}
vol.writeFileSync(path, content);
}
}
/**
* Quick file operations for tests
*/
export const testFs = {
write: (path, content) => {
const dir = path.substring(0, path.lastIndexOf("/"));
if (dir)
vol.mkdirSync(dir, { recursive: true });
vol.writeFileSync(path, content);
},
read: (path) => {
return vol.readFileSync(path, "utf-8");
},
exists: (path) => {
try {
vol.statSync(path);
return true;
}
catch {
return false;
}
},
mkdir: (path) => {
vol.mkdirSync(path, { recursive: true });
},
reset: () => vol.reset(),
};
/**
* Mock environment config for tests
* Avoids the heavyweight EnvironmentManager singleton
*/
export function createMockEnvConfig(baseDir = "/tmp/hypertool-test") {
return {
mode: "test",
baseDir,
configRoot: join(baseDir, ".hypertool"),
registryPath: join(baseDir, ".hypertool/apps/registry.json"),
backupRoot: join(baseDir, ".hypertool/backups"),
cacheRoot: join(baseDir, ".hypertool/cache"),
setupScriptsRoot: join(baseDir, ".hypertool/setup"),
logsRoot: join(baseDir, ".hypertool/logs"),
};
}
/**
* Platform mock utilities
*/
export const platformMock = {
current: process.platform,
set: (platform) => {
Object.defineProperty(process, "platform", {
value: platform,
writable: true,
configurable: true,
});
},
reset: () => {
Object.defineProperty(process, "platform", {
value: platformMock.current,
writable: true,
configurable: true,
});
},
};
/**
* Async test wrapper with timeout
* Prevents hanging tests by enforcing timeouts
*/
export function withTimeout(fn, timeoutMs = 5000) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error(`Test timed out after ${timeoutMs}ms`));
}, timeoutMs);
fn()
.then((result) => {
clearTimeout(timer);
resolve(result);
})
.catch((error) => {
clearTimeout(timer);
reject(error);
});
});
}
export async function runScenario(scenario) {
await scenario.setup();
return {
cleanup: async () => {
if (scenario.teardown) {
await scenario.teardown();
}
vol.reset();
},
};
}
//# sourceMappingURL=lightweight.js.map