Files
reverse-engineering-anything/tests/boundary/mcp/webModuleGrammarMcp.test.ts
T
morlutoandCopilot Autofix powered by AI 675d4076de test: strengthen regression oracles and cleanup ownership (#8152)
* test: strengthen suite oracles and cleanup ownership

* test: reuse setup across independent scenarios (#8153)

* Potential fix for pull request finding 'CodeQL / Improper code sanitization'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-10-31 00:22:16 +08:00

117 lines
4.1 KiB
TypeScript

import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it } from "vitest";
import { WebModuleTraceService } from "../../../src/application/WebModuleTraceService.js";
import { LocalWebModuleArtifacts } from "../../../src/browser/modules/WebModuleArtifacts.js";
import { parseEvidence } from "../../../src/domain/evidence.js";
import {
webModuleTraceResultSchema,
type WebModuleResolutionRequest,
} from "../../../src/domain/webModuleTrace.js";
import { createApplicationMcpHarness } from "../../fixtures/applicationMcpHarness.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import {
webModuleArtifactsFixture,
webModuleResolverFixture,
} from "../../fixtures/webModuleTrace.js";
it.each([
{
source: 'const order = left < import("./dep.js") > (right);',
expected: ["./dep.js"],
},
{
source:
'const fn = c ? x => import("./a.js") : y => import("./b.js"); import("./c.js");',
expected: ["./a.js", "./b.js", "./c.js"],
},
])(
"retains JavaScript imports and requests resolution through public MCP: $source",
async ({ source, expected }) => {
const root = await createTestTempDirectory("rea-module-grammar-");
const original = webModuleArtifactsFixture(source);
const manifest = {
...original.manifest,
output_directory: root,
scripts: original.manifest.scripts.map((script) => ({
...script,
url: "https://app.test/main.ts?build=1#entry",
})),
};
const sourcePath = join(root, "files", "modules", "main.js");
const manifestPath = join(root, "manifest.json");
await mkdir(join(root, "files", "modules"), { recursive: true });
await writeFile(sourcePath, source);
const manifestText = JSON.stringify(manifest);
await writeFile(manifestPath, manifestText);
const requests: WebModuleResolutionRequest[] = [];
const service = new WebModuleTraceService(new LocalWebModuleArtifacts(), {
resolve: async (request) => {
requests.push(request);
return webModuleResolverFixture.resolve(request);
},
});
const session = createTestBinarySession(() => {
throw new Error(
"Retained module tracing must not acquire a binary provider",
);
});
const { client } = await createApplicationMcpHarness({
session,
serverOptions: { webModuleTrace: service },
clientIdentity: { name: "module-grammar", version: "1" },
});
const response = await client.callTool({
name: "trace_web_module_imports",
arguments: { manifest_path: manifestPath, script_index: 0 },
});
expect(response.isError, JSON.stringify(response)).not.toBe(true);
const evidence = parseEvidence(response.structuredContent);
const result = webModuleTraceResultSchema.parse(evidence.normalized_result);
expect(requests).toEqual([
{
importerUrl: manifest.scripts[0]!.url,
importMap: null,
specifiers: expected,
},
]);
expect(result).toMatchObject({
source: {
path: sourcePath,
sha256: original.sourceFile.sha256,
bytes: original.sourceFile.bytes,
},
parser: { state: "parsed", diagnostics: [] },
engine: { id: "fixture", version: "1" },
});
expect(
result.imports.map(({ kind, specifier, resolution, execution }) => ({
kind,
specifier,
resolution,
execution,
})),
).toEqual(
expected.map((specifier) => ({
kind: "dynamic-import",
specifier,
resolution: {
state: "resolved",
url: new URL(specifier, manifest.scripts[0]!.url).href,
},
execution: "unknown",
})),
);
for (const reference of result.imports)
expect(source.slice(reference.start.offset, reference.end.offset)).toBe(
reference.expression,
);
expect(session.evidenceById(evidence.evidence_id)).toEqual(evidence);
expect(await readFile(sourcePath, "utf8")).toBe(source);
expect(await readFile(manifestPath, "utf8")).toBe(manifestText);
await client.ping();
},
);