Files
rea/tests/acceptance/webSourceLocationCli.test.ts

358 lines
12 KiB
TypeScript

import { connectLocalToolsMcp } from "../fixtures/localToolsMcp.js";
import { parseMcpToolError } from "../fixtures/mcpToolError.js";
import { expect, onTestFinished } from "vitest";
import { Client } from "@modelcontextprotocol/client";
import {
StdioClientTransport,
getDefaultEnvironment,
} from "@modelcontextprotocol/client/stdio";
import { fileURLToPath } from "node:url";
import { createHash } from "node:crypto";
import { mkdir, symlink, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { webSourceLocationFixture } from "../fixtures/webSourceLocation.js";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
import { cliTest } from "../support/cli/cliFixture.js";
cliTest(
"accepts numeric UTF-16 coordinates and runs the actual owned source-map codec without a browser",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-source-map-cli-");
const fixture = webSourceLocationFixture();
await mkdir(join(root, "files", "modules"), { recursive: true });
await writeFile(join(root, "files", "modules", "main.js"), fixture.source);
let manifest = join(root, "manifest.json").replaceAll("\\", "/");
const map = join(root, "app.js.map");
await writeFile(manifest, JSON.stringify(fixture.manifest));
if (process.platform !== "win32") {
await mkdir(join(root, "lexical"));
await mkdir(join(root, "nested"));
await symlink(join(root, "nested"), join(root, "lexical", "link"));
manifest = `${root}/lexical/link/../manifest.json`;
}
await writeFile(map, fixture.sourceMap.text);
const response = await cli.run({
arguments: [
"trace-web-source-location",
manifest,
"0",
map,
fixture.sourceMap.url,
"1",
"0",
"--json",
],
environment: {
REA_LOG_LEVEL: "silent",
REA_BROWSER_EXECUTABLE: "relative-unconfigured-browser",
CLANG_MODULE_CACHE_PATH: map,
},
timeoutMs: 45000,
});
expect(response.exitCode, response.stdout + response.stderr).toBe(0);
expect(response.json).toMatchObject({
normalized_result: {
manifest: {
path: manifest,
reported_output_directory: fixture.manifest.output_directory,
},
source: {
script_index: 0,
path: join(root, "files", "modules", "main.js"),
},
source_map: { association: "caller-selected" },
generated_offset: 0,
execution: "unknown",
matches: [{ content: { text: "original" } }],
runtime: {
id: process.versions.bun === undefined ? "node-v8" : "bun",
},
},
});
const transport = new StdioClientTransport({
command: process.execPath,
args: [
fileURLToPath(new URL("../../scripts/rea.mjs", import.meta.url)),
"mcp",
],
env: {
...getDefaultEnvironment(),
REA_LOG_LEVEL: "silent",
CLANG_MODULE_CACHE_PATH: map,
},
stderr: "pipe",
});
const client = new Client({
name: "source-location-cli-parity",
version: "1",
});
onTestFinished(async () => {
try {
await client.close();
} finally {
await transport.close();
}
});
await client.connect(transport);
const mcpResponse = await client.callTool({
name: "trace_web_source_location",
arguments: {
manifest_path: manifest,
script_index: 0,
source_map: { path: map, url: fixture.sourceMap.url },
generated_position: { line: 1, column: 0 },
},
});
expect(mcpResponse.isError, JSON.stringify(mcpResponse)).not.toBe(true);
expect(mcpResponse.structuredContent).toEqual(response.json);
const invalid = await cli.run({
arguments: [
"trace-web-source-location",
manifest,
"0",
map,
fixture.sourceMap.url,
"2",
"0",
"--json",
],
environment: { REA_LOG_LEVEL: "silent" },
timeoutMs: 45000,
});
expect(invalid.exitCode).toBe(1);
expect(invalid.json).toMatchObject({
code: "invalid_request",
details: {
issues: [{ path: ["generated_position"] }],
partial_observation: {
kind: "web-trace-observation",
analysis: "incomplete",
manifest: { path: manifest },
source: { path: join(root, "files", "modules", "main.js") },
source_map: {
path: map,
sha256: createHash("sha256")
.update(fixture.sourceMap.text)
.digest("hex"),
},
},
},
});
},
// Allow cold CLI and MCP ownership preparation across the full parity sequence.
180_000,
);
cliTest(
"applies the shared version constraint to nested indexed maps through CLI and stdio MCP",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-indexed-map-version-");
const fixture = webSourceLocationFixture();
await mkdir(join(root, "files", "modules"), { recursive: true });
await writeFile(join(root, "files", "modules", "main.js"), fixture.source);
const manifest = join(root, "manifest.json").replaceAll("\\", "/");
await writeFile(manifest, JSON.stringify(fixture.manifest));
const { call } = await connectLocalToolsMcp({
REA_BROWSER_EXECUTABLE: "relative-unconfigured-browser",
});
const leaf: unknown = JSON.parse(fixture.sourceMap.text);
for (const [index, version] of [3, 2, null, undefined, "3"].entries()) {
const text = JSON.stringify({
version: 3,
sections: [
{
offset: { line: 0, column: 0 },
map: {
version,
sections: [{ offset: { line: 0, column: 0 }, map: leaf }],
},
},
],
});
const path = join(root, `nested-${index}.map`);
await writeFile(path, text);
const result = await cli.run({
arguments: [
"trace-web-source-location",
manifest,
"0",
path,
fixture.sourceMap.url,
"1",
"0",
"--json",
],
environment: {
REA_LOG_LEVEL: "silent",
REA_BROWSER_EXECUTABLE: "relative-unconfigured-browser",
},
timeoutMs: 45_000,
});
const response = await call("trace_web_source_location", {
manifest_path: manifest,
script_index: 0,
source_map: { path, url: fixture.sourceMap.url },
generated_position: { line: 1, column: 0 },
});
if (version === 3) {
expect(result.exitCode, result.stderr).toBe(0);
expect(result.json).toMatchObject({
normalized_result: {
matches: [
{
state: "mapped",
section_path: [0, 0],
content: { text: "original" },
},
],
},
});
expect(response.isError, JSON.stringify(response)).not.toBe(true);
expect(response.structuredContent).toEqual(result.json);
} else {
const failure = {
code: "invalid_request",
details: {
partial_observation: {
kind: "web-trace-observation",
analysis: "incomplete",
manifest: {
path: manifest,
sha256: createHash("sha256")
.update(JSON.stringify(fixture.manifest))
.digest("hex"),
},
source: {
path: join(root, "files", "modules", "main.js"),
sha256: createHash("sha256")
.update(fixture.source)
.digest("hex"),
},
source_map: {
path,
sha256: createHash("sha256").update(text).digest("hex"),
bytes: Buffer.byteLength(text),
},
},
issues: [
{
path: ["source_map", "path"],
reason: "invalid_format",
message: expect.stringContaining(
"not a version 3 map. Section path: [0].",
),
},
],
},
};
expect(result.exitCode).toBe(1);
expect(result.json).toMatchObject(failure);
expect(result.json).not.toHaveProperty("normalized_result");
expect(parseMcpToolError(response).error).toMatchObject(failure);
expect(response.structuredContent).toBeUndefined();
}
}
},
180_000,
);
cliTest(
"traces empty equal-offset sections while rejecting decreasing offsets and represented overlaps",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-empty-indexed-map-");
const fixture = webSourceLocationFixture();
await mkdir(join(root, "files", "modules"), { recursive: true });
await writeFile(join(root, "files", "modules", "main.js"), fixture.source);
const manifest = join(root, "manifest.json").replaceAll("\\", "/");
await writeFile(manifest, JSON.stringify(fixture.manifest));
const { call } = await connectLocalToolsMcp();
const leaf: unknown = JSON.parse(fixture.sourceMap.text);
const empty = { version: 3, sources: [], names: [], mappings: "" };
const nestedEmpty = {
version: 3,
sections: [{ offset: { line: 0, column: 0 }, map: empty }],
};
for (const [index, sample] of [
{ first: empty, firstColumn: 0, nextColumn: 0, succeeds: true },
{ first: nestedEmpty, firstColumn: 0, nextColumn: 0, succeeds: true },
{ first: empty, firstColumn: 0, nextColumn: 1, succeeds: true },
{ first: leaf, firstColumn: 0, nextColumn: 0, succeeds: false },
{ first: empty, firstColumn: 1, nextColumn: 0, succeeds: false },
].entries()) {
const path = join(root, `empty-${index}.map`);
await writeFile(
path,
JSON.stringify({
version: 3,
sections: [
{
offset: { line: 0, column: sample.firstColumn },
map: sample.first,
},
{ offset: { line: 0, column: sample.nextColumn }, map: leaf },
],
}),
);
const result = await cli.run({
arguments: [
"trace-web-source-location",
manifest,
"0",
path,
fixture.sourceMap.url,
"1",
String(sample.nextColumn),
"--json",
],
environment: { REA_LOG_LEVEL: "silent" },
timeoutMs: 45_000,
});
const response = await call("trace_web_source_location", {
manifest_path: manifest,
script_index: 0,
source_map: { path, url: fixture.sourceMap.url },
generated_position: { line: 1, column: sample.nextColumn },
});
if (sample.succeeds) {
expect(result.exitCode, result.stderr).toBe(0);
expect(result.json).toMatchObject({
normalized_result: {
lookup: {
matched_generated_position: {
line: 1,
column: sample.nextColumn,
},
},
matches: [
{
state: "mapped",
section_path: [1],
content: { text: "original" },
},
],
},
});
expect(response.isError, JSON.stringify(response)).not.toBe(true);
expect(response.structuredContent).toEqual(result.json);
} else {
const failure = {
code: "invalid_request",
details: {
issues: [
{
path: ["source_map", "path"],
reason: "invalid_format",
message: expect.stringMatching(/overlap|nondecreasing/u),
},
],
},
};
expect(result.exitCode).toBe(1);
expect(result.json).toMatchObject(failure);
expect(parseMcpToolError(response).error).toMatchObject(failure);
}
}
},
180_000,
);