fix(electron): report rejected CLI arguments with issue details (#5036)

* fix(electron): report rejected CLI arguments with issue details

Pass schema validation issues and submitted input to inputError in list-electron-targets and inspect-electron-page commands, matching the structured diagnostics returned by browser commands.

Fixes #3865

* test(electron): assert exit code 1 on rejected CLI arguments
This commit is contained in:
KIEU TRONG KHANG
2026-10-22 03:08:52 +07:00
committed by GitHub
parent b0a554cc3a
commit 2aadcf7d04
2 changed files with 77 additions and 11 deletions
+18 -6
View File
@@ -217,10 +217,16 @@ const registerElectronTargetList = (
withCommandCancellation((signal) =>
logCliCommand(logger, "list-electron-targets", async () => {
const context = await electronObservationContext();
const parsed = listElectronTargetsInputSchema.safeParse({
const input = {
cdp_endpoint: args.endpoint,
});
if (!parsed.success) return inputError("list_electron_targets");
};
const parsed = listElectronTargetsInputSchema.safeParse(input);
if (!parsed.success)
return inputError(
"list_electron_targets",
parsed.error.issues,
input,
);
const { listElectronTargets } =
await import("../application/javascript/ElectronObservationService.js");
return await finishAnalysisCommand(
@@ -255,13 +261,19 @@ const registerElectronPageInspection = (
withCommandCancellation((signal) =>
logCliCommand(logger, "inspect-electron-page", async () => {
const context = await electronObservationContext();
const parsed = inspectElectronPageInputSchema.safeParse({
const input = {
cdp_endpoint: args.endpoint,
target_id: args.targetId,
observation_ms: options.observationMs,
include_script_sources: options.includeScriptSources,
});
if (!parsed.success) return inputError("inspect_electron_page");
};
const parsed = inspectElectronPageInputSchema.safeParse(input);
if (!parsed.success)
return inputError(
"inspect_electron_page",
parsed.error.issues,
input,
);
const { inspectElectronPage } =
await import("../application/javascript/ElectronObservationService.js");
return await finishAnalysisCommand(
+59 -5
View File
@@ -96,6 +96,53 @@ it(
INTEGRATION_TEST_TIMEOUT_MS,
);
it(
"reports rejected Electron CLI arguments with structured issue details",
async () => {
const invalidTargetList = await runCliResult(
["list-electron-targets", "not a url", "--json"],
process.env,
);
expect(invalidTargetList.exitCode).toBe(1);
expect(invalidTargetList.result).toMatchObject({
error: "Electron analysis failed",
code: "invalid_request",
category: "invalid_input",
details: {
operation: "list_electron_targets",
issues: [
{
path: ["cdp_endpoint"],
reason: "invalid_value",
},
],
},
});
const invalidPageInspect = await runCliResult(
["inspect-electron-page", "http://127.0.0.1:9222", "", "--json"],
process.env,
);
expect(invalidPageInspect.exitCode).toBe(1);
expect(invalidPageInspect.result).toMatchObject({
error: "Electron analysis failed",
code: "invalid_request",
category: "invalid_input",
details: {
operation: "inspect_electron_page",
issues: [
{
path: ["target_id"],
reason: "out_of_range",
minimum: 1,
},
],
},
});
},
INTEGRATION_TEST_TIMEOUT_MS,
);
// On Windows child.kill("SIGINT") terminates the process without a console signal.
it.skipIf(process.platform === "win32")(
"forwards SIGINT through Electron page inspection and completes target cleanup",
@@ -436,25 +483,32 @@ describe("Electron CLI runtime reconciliation", () => {
const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null && !Array.isArray(value);
const runCli = async (
const runCliResult = async (
arguments_: readonly string[],
environment: NodeJS.ProcessEnv,
): Promise<unknown> => {
): Promise<{ readonly exitCode: number; readonly result: unknown }> => {
try {
const { stdout } = await execute(
process.execPath,
["scripts/rea.mjs", ...arguments_],
{ cwd: process.cwd(), env: environment, maxBuffer: 16 * 1_024 * 1_024 },
);
return JSON.parse(stdout);
return { exitCode: 0, result: JSON.parse(stdout) };
} catch (cause: unknown) {
if (
typeof cause === "object" &&
cause !== null &&
"stdout" in cause &&
typeof cause.stdout === "string"
typeof cause.stdout === "string" &&
"code" in cause &&
typeof cause.code === "number"
)
return JSON.parse(cause.stdout);
return { exitCode: cause.code, result: JSON.parse(cause.stdout) };
throw cause;
}
};
const runCli = async (
arguments_: readonly string[],
environment: NodeJS.ProcessEnv,
): Promise<unknown> => (await runCliResult(arguments_, environment)).result;