49 lines
2.2 KiB
TypeScript
49 lines
2.2 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { spawn } from "node:child_process";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
test("stdio protocol mode writes only JSON-RPC messages to stdout", async () => {
|
|
const packageRoot = path.resolve(fileURLToPath(new URL("..", import.meta.url)));
|
|
const child = spawn(process.execPath, ["--import", "tsx", "test/stdioFixture.ts"], {
|
|
cwd: packageRoot,
|
|
shell: false,
|
|
windowsHide: true,
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
});
|
|
let stdout = "";
|
|
let stderr = "";
|
|
child.stdout.setEncoding("utf8").on("data", (chunk) => { stdout += String(chunk); });
|
|
child.stderr.setEncoding("utf8").on("data", (chunk) => { stderr += String(chunk); });
|
|
const messages = [
|
|
{ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2025-11-25", capabilities: {}, clientInfo: { name: "stdio-test", version: "1.0.0" } } },
|
|
{ jsonrpc: "2.0", method: "notifications/initialized" },
|
|
{ jsonrpc: "2.0", id: 2, method: "tools/list", params: { cursor: "next" } },
|
|
];
|
|
child.stdin.write(messages.map((message) => JSON.stringify(message)).join("\n") + "\n");
|
|
await waitFor(() => stdout.split(/\r?\n/).filter(Boolean).some((line) => {
|
|
try { return (JSON.parse(line) as { id?: number }).id === 2; } catch { return false; }
|
|
}), 3000);
|
|
child.stdin.end();
|
|
await new Promise<void>((resolve) => {
|
|
const timeout = setTimeout(() => { child.kill(); resolve(); }, 1000);
|
|
child.once("close", () => { clearTimeout(timeout); resolve(); });
|
|
});
|
|
const lines = stdout.split(/\r?\n/).filter(Boolean);
|
|
assert.ok(lines.length >= 2);
|
|
const parsed = lines.map((line) => JSON.parse(line) as { jsonrpc: string; id?: number; result?: unknown });
|
|
assert.ok(parsed.every((message) => message.jsonrpc === "2.0"));
|
|
assert.ok(parsed.some((message) => message.id === 1));
|
|
assert.ok(parsed.some((message) => message.id === 2));
|
|
assert.equal(stderr, "");
|
|
});
|
|
|
|
async function waitFor(predicate: () => boolean, timeoutMs: number): Promise<void> {
|
|
const started = Date.now();
|
|
while (!predicate()) {
|
|
if (Date.now() - started > timeoutMs) throw new Error("timed out waiting for stdio response");
|
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
}
|
|
}
|