test: switch integration project to folder-based manifest (#1314) (#1318)

* test: switch integration project to folder-based manifest (#1314)

Replace the `integrationTests` enumeration in vite.config.ts with a
folder glob (`src/test/integration/**/*.test.ts`). Files under that
folder run in the integration vitest project (node env, 30s timeouts);
everything else runs in the unit project (happy-dom).

This removes the silent misclassification trap from #1307: a new
integration-style test no longer falls into the unit project (and
happy-dom) just because someone forgot to add it to the array.

The 13 ported v1.5 tests + their helpers move under src/test/integration/
in a strict mirror of core/ source layout (mcp/, auth/, auth/node/,
storage/). Renames use git mv so history is preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test: address PR review on #1318 (glob extensions + AGENTS doc)

- vite.config.ts: widen integrationGlob from `*.test.ts` to
  `*.test.{ts,tsx}` so the integration folder fully owns its contents.
  Without this, a `.test.tsx` placed under src/test/integration/ would
  match the unit project's `{ts,tsx}` include, fail the unit `.ts`-only
  exclude, and silently land under happy-dom — the exact misclassification
  trap this PR set out to close.
- AGENTS.md: update the line describing where integration tests live;
  it still pointed at the old `src/test/core/` location and the removed
  `integrationTests` enumeration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cliff Hall 2026-05-18 11:54:49 -04:00 • committed by GitHub
commit 8bb389c8e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -0,0 +1,195 @@
import { describe, it, expect } from "vitest";
import { getServerType } from "@inspector/core/mcp/config.js";
import { createTransportNode } from "@inspector/core/mcp/node/transport.js";
import type {
MCPServerConfig,
FetchRequestEntryBase,
} from "@inspector/core/mcp/types.js";
import {
createTestServerHttp,
createEchoTool,
createTestServerInfo,
} from "@modelcontextprotocol/inspector-test-server";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
describe("Transport", () => {
describe("getServerType", () => {
it("should return stdio for stdio config", () => {
const config: MCPServerConfig = {
type: "stdio",
command: "echo",
args: ["hello"],
};
expect(getServerType(config)).toBe("stdio");
});
it("should return sse for sse config", () => {
const config: MCPServerConfig = {
type: "sse",
url: "http://localhost:3000/sse",
};
expect(getServerType(config)).toBe("sse");
});
it("should return streamable-http for streamable-http config", () => {
const config: MCPServerConfig = {
type: "streamable-http",
url: "http://localhost:3000/mcp",
};
expect(getServerType(config)).toBe("streamable-http");
});
it("should default to stdio when type is not present", () => {
const config: MCPServerConfig = {
command: "echo",
args: ["hello"],
};
expect(getServerType(config)).toBe("stdio");
});
it("should throw error for invalid type", () => {
const config = {
type: "invalid",
command: "echo",
} as unknown as MCPServerConfig;
expect(() => getServerType(config)).toThrow();
});
});
describe("createTransport", () => {
it("should create stdio transport", () => {
const config: MCPServerConfig = {
type: "stdio",
command: "echo",
args: ["hello"],
};
const result = createTransportNode(config);
expect(result.transport).toBeDefined();
});
it("should create SSE transport", () => {
const config: MCPServerConfig = {
type: "sse",
url: "http://localhost:3000/sse",
};
const result = createTransportNode(config);
expect(result.transport).toBeDefined();
});
it("should create streamable-http transport", () => {
const config: MCPServerConfig = {
type: "streamable-http",
url: "http://localhost:3000/mcp",
};
const result = createTransportNode(config);
expect(result.transport).toBeDefined();
});
it("should call onFetchRequest callback for SSE transport", async () => {
const server = createTestServerHttp({
serverInfo: createTestServerInfo(),
tools: [createEchoTool()],
serverType: "sse",
});
try {
await server.start();
const config: MCPServerConfig = {
type: "sse",
url: server.url,
};
const fetchRequests: FetchRequestEntryBase[] = [];
const result = createTransportNode(config, {
onFetchRequest: (entry) => {
fetchRequests.push(entry);
},
});
expect(result.transport).toBeDefined();
// Actually connect and make a request to verify fetch tracking works
const client = new Client(
{
name: "test-client",
version: "1.0.0",
},
{
capabilities: {},
},
);
await client.connect(result.transport);
await client.listTools();
await client.close();
// Verify fetch requests were tracked
expect(fetchRequests.length).toBeGreaterThan(0);
// SSE uses GET for the initial connection
const getRequest = fetchRequests.find((r) => r.method === "GET");
expect(getRequest).toBeDefined();
if (getRequest) {
expect(getRequest.url).toContain("/sse");
expect(getRequest.requestHeaders).toBeDefined();
}
} finally {
await server.stop();
}
});
it("should call onFetchRequest callback for streamable-http transport", async () => {
const server = createTestServerHttp({
serverInfo: createTestServerInfo(),
tools: [createEchoTool()],
serverType: "streamable-http",
});
try {
await server.start();
const config: MCPServerConfig = {
type: "streamable-http",
url: server.url,
};
const fetchRequests: FetchRequestEntryBase[] = [];
const result = createTransportNode(config, {
onFetchRequest: (entry) => {
fetchRequests.push(entry);
},
});
expect(result.transport).toBeDefined();
// Actually connect and make a request to verify fetch tracking works
const client = new Client(
{
name: "test-client",
version: "1.0.0",
},
{
capabilities: {},
},
);
await client.connect(result.transport);
await client.listTools();
await client.close();
// Verify fetch requests were tracked
expect(fetchRequests.length).toBeGreaterThan(0);
const request = fetchRequests[0];
expect(request).toBeDefined();
expect(request.url).toContain("/mcp");
expect(request.method).toBe("POST");
expect(request.requestHeaders).toBeDefined();
expect(request.responseStatus).toBeDefined();
expect(request.responseHeaders).toBeDefined();
expect(request.duration).toBeDefined();
} finally {
await server.stop();
}
});
});
});