160 lines
5.8 KiB
TypeScript
160 lines
5.8 KiB
TypeScript
import { writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
|
|
import { describe, expect } from "vitest";
|
|
|
|
import { parseCliJsonInput } from "../../../src/cliJsonInput.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
|
|
const JSON_COMMANDS = [
|
|
["trace-application-feature", "trace-application-feature"],
|
|
["trace-javascript-semantics", "trace-javascript-semantics"],
|
|
["compare-application-versions", "compare-application-versions"],
|
|
["compare-source-to-bundle", "compare-source-to-bundle"],
|
|
["compare-javascript-export-shapes", "compare-javascript-export-shapes"],
|
|
[
|
|
"build-reconstruction-obligation-ledger",
|
|
"build-reconstruction-obligation-ledger",
|
|
],
|
|
["evaluate-reconstruction-coverage", "evaluate-reconstruction-coverage"],
|
|
["import-managed-reconstruction", "import-managed-reconstruction"],
|
|
["verify-managed-native-boundaries", "verify-managed-native-boundaries"],
|
|
["project-managed-application-graph", "project-managed-application-graph"],
|
|
["capture-browser-scenario", "capture_browser_scenario"],
|
|
["capture-electron-scenario", "capture_electron_scenario"],
|
|
["reconcile-javascript-runtime", "reconcile_javascript_runtime"],
|
|
] as const;
|
|
|
|
describe("compiled CLI JSON input failure status", () => {
|
|
for (const [command, operation] of JSON_COMMANDS)
|
|
for (const kind of ["inline", "file", "missing"] as const)
|
|
cliTest(
|
|
`${command} rejects malformed or unreadable ${kind} input before dispatch`,
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-cli-json-status-");
|
|
const input = kind === "inline" ? "{" : join(root, "input.json");
|
|
if (kind === "file") await writeFile(input, "{");
|
|
const parsed = await parseCliJsonInput(input, operation);
|
|
if (parsed.ok)
|
|
throw new Error("Expected JSON input to fail before dispatch");
|
|
|
|
const result = await cli.run({
|
|
arguments: [command, input, "--json"],
|
|
environment: {
|
|
HOME: root,
|
|
XDG_CONFIG_HOME: root,
|
|
XDG_CACHE_HOME: root,
|
|
},
|
|
});
|
|
|
|
expect(result.stdout).toBe(
|
|
`${JSON.stringify(parsed.error, null, 2)}\n`,
|
|
);
|
|
expect(result.json).toMatchObject({
|
|
code: "invalid_request",
|
|
category: "invalid_input",
|
|
...(kind === "missing" ? {} : { details: { operation } }),
|
|
...(kind === "inline"
|
|
? {}
|
|
: {
|
|
input_path: input,
|
|
input_reason:
|
|
kind === "file" ? "invalid-json" : "read-failed",
|
|
}),
|
|
});
|
|
expect(result.stderr).toBe("");
|
|
expect(result.exitCode).toBe(1);
|
|
},
|
|
);
|
|
|
|
for (const [format, flags] of [
|
|
["JSON", ["--json"]],
|
|
["JSONL", ["--format", "jsonl"]],
|
|
["YAML", ["--format", "yaml"]],
|
|
["default", []],
|
|
] as const)
|
|
cliTest(
|
|
`keeps the failure status with ${format} output`,
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-cli-json-format-");
|
|
const input = join(root, "missing.json");
|
|
const result = await cli.run({
|
|
arguments: ["compare-javascript-export-shapes", input, ...flags],
|
|
environment: {
|
|
HOME: root,
|
|
XDG_CONFIG_HOME: root,
|
|
XDG_CACHE_HOME: root,
|
|
},
|
|
});
|
|
for (const diagnostic of [
|
|
"invalid_request",
|
|
"invalid_input",
|
|
input,
|
|
"read-failed",
|
|
])
|
|
expect(result.stdout).toContain(diagnostic);
|
|
expect(result.stderr).toBe("");
|
|
expect(result.exitCode).toBe(1);
|
|
},
|
|
);
|
|
|
|
cliTest(
|
|
"rejects an empty file path without losing its diagnostic",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-cli-json-empty-");
|
|
const result = await cli.run({
|
|
arguments: ["compare-javascript-export-shapes", "", "--json"],
|
|
environment: {
|
|
HOME: root,
|
|
XDG_CONFIG_HOME: root,
|
|
XDG_CACHE_HOME: root,
|
|
},
|
|
});
|
|
expect(result.json).toMatchObject({
|
|
code: "invalid_request",
|
|
input_path: "",
|
|
input_reason: "read-failed",
|
|
});
|
|
expect(result.exitCode).toBe(1);
|
|
},
|
|
);
|
|
});
|
|
|
|
describe("compiled JSON parser and logger success seam", () => {
|
|
for (const kind of ["inline", "file"] as const)
|
|
cliTest(
|
|
`preserves valid ${kind} data and a zero exit status without running a workflow`,
|
|
async ({ processes }) => {
|
|
const root = await createTestTempDirectory("rea-cli-json-success-");
|
|
const value = {
|
|
error: "source data",
|
|
code: "invalid_request",
|
|
values: [null, false, 0],
|
|
};
|
|
const json = JSON.stringify(value);
|
|
const input = kind === "inline" ? json : join(root, "input.json");
|
|
if (kind === "file") await writeFile(input, json);
|
|
const result = await processes.run(
|
|
process.execPath,
|
|
[
|
|
"--input-type=module",
|
|
"-e",
|
|
`import { parseCliJsonInput } from "./dist/cliJsonInput.js";
|
|
import { logCliCommand } from "./dist/cliLogging.js";
|
|
import { silentLogger } from "./dist/logger.js";
|
|
const parsed = await parseCliJsonInput(process.argv[1], "test-input");
|
|
const output = await logCliCommand(silentLogger, "test-input", async () =>
|
|
parsed.ok ? parsed.value : parsed.error);
|
|
console.log(JSON.stringify(output));`,
|
|
input,
|
|
],
|
|
{ env: { HOME: root, XDG_CONFIG_HOME: root, XDG_CACHE_HOME: root } },
|
|
);
|
|
expect(result.stdout).toBe(`${json}\n`);
|
|
expect(result.stderr).toBe("");
|
|
expect(result.exitCode).toBe(0);
|
|
},
|
|
);
|
|
});
|