test(cli): add coverage for port scan fallback and c8 ignore for signal handlers

Adds test for stopDashboard finding an orphaned dashboard on a reassigned
port via the port-range scan fallback. Marks signal handler body with
c8 ignore since it only fires on process termination.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
adil 2026-04-12 10:51:16 +05:30
parent e620a182c9
commit 4958512d9e
2 changed files with 24 additions and 0 deletions

View File

@ -1059,6 +1059,7 @@ describe("stop command", () => {
mockConfigRef.current = makeConfig({ "my-app": makeProject() });
mockSessionManager.get.mockResolvedValue({ id: "app-orchestrator", status: "running" });
mockSessionManager.kill.mockResolvedValue(undefined);
mockExec.mockResolvedValue({ stdout: "12345", stderr: "" });
await program.parseAsync(["node", "test", "stop", "--purge-session"]);
@ -1066,6 +1067,27 @@ describe("stop command", () => {
purgeOpenCode: true,
});
});
it("finds orphaned dashboard on a reassigned port via port scan", async () => {
mockConfigRef.current = makeConfig({ "my-app": makeProject() });
mockSessionManager.get.mockResolvedValue({ id: "app-orchestrator", status: "running" });
mockSessionManager.kill.mockResolvedValue(undefined);
// Port 3000 has nothing, but port 3001 has the orphaned dashboard
mockExec.mockImplementation(async (cmd: string, args: string[] = []) => {
if (cmd === "kill") return { stdout: "", stderr: "" };
const portArg = args.find((a) => a.startsWith(":"));
if (portArg === ":3001") return { stdout: "99999", stderr: "" };
throw new Error("no process");
});
await program.parseAsync(["node", "test", "stop"]);
const output = vi
.mocked(console.log)
.mock.calls.map((c) => c.join(" "))
.join("\n");
expect(output).toContain("was on port 3001");
});
});
// ---------------------------------------------------------------------------

View File

@ -1155,6 +1155,7 @@ async function runStartup(
// Ensure the dashboard child is killed when the parent exits (e.g. Ctrl+C).
// Node.js does not guarantee signal propagation to child processes.
/* c8 ignore start -- signal handlers only fire on process termination */
const killDashboard = (): void => {
try {
dashboardProcess?.kill("SIGTERM");
@ -1162,6 +1163,7 @@ async function runStartup(
// already dead
}
};
/* c8 ignore stop */
process.on("SIGINT", killDashboard);
process.on("SIGTERM", killDashboard);
process.on("exit", killDashboard);