Files
hyperframes/packages/cli/src/commands/previewLifecycleOutput.test.ts
T
Miguel Ángel 0e3c5f6bef feat(cli): give every preview lifecycle op one JSON document (#3309)
`--status`, `--stop`, `--list` and `--kill-all` emit a schema-versioned
envelope with an `ok` discriminant under `--json`, from one writer and one
failure-payload builder. Human output is unchanged; the JSON path is additive.

The value is in the failure paths. An agent that gets a bare error line on
stderr and an empty stdout cannot tell a crash from a "not running", so every
failure is a document too — including a missing project, which under `--json`
resolves through the throwing resolver rather than the human-shaped nudge.
2026-08-18 20:07:50 -04:00

84 lines
2.2 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import {
lifecycleFailurePayload,
lifecyclePayload,
writeLifecycleJson,
type PreviewLifecycleSession,
} from "./previewLifecycleOutput.js";
const session: PreviewLifecycleSession = {
state: "started",
mode: "background",
projectName: "demo",
projectDir: "/tmp/demo",
host: "127.0.0.1",
port: 3002,
pid: 42,
serverUrl: "http://127.0.0.1:3002",
studioUrl: "http://127.0.0.1:3002/#project/demo",
ready: true,
logPath: "/tmp/demo.log",
};
afterEach(() => {
vi.restoreAllMocks();
});
describe("preview lifecycle JSON", () => {
it("versions a managed start result", () => {
expect(lifecyclePayload("start", session)).toEqual({
schemaVersion: 1,
operation: "start",
ok: true,
result: session,
});
});
it.each([
["status", { state: "not-running", projectDir: "/tmp/demo" }],
["stop", { state: "stopped", projectDir: "/tmp/demo" }],
["list", { state: "listed", sessions: [session] }],
["kill-all", { state: "killed-all", stopped: 1 }],
] as const)("versions the %s result", (operation, result) => {
expect(lifecyclePayload(operation, result)).toMatchObject({
schemaVersion: 1,
operation,
ok: true,
result,
});
});
it("writes exactly one parseable JSON document", () => {
const log = vi.spyOn(console, "log").mockImplementation(() => {});
writeLifecycleJson(lifecyclePayload("start", { ...session, pid: null, state: "reused" }));
expect(log).toHaveBeenCalledOnce();
const [line] = log.mock.calls[0] as [string];
expect(JSON.parse(line)).toEqual({
schemaVersion: 1,
operation: "start",
ok: true,
result: { ...session, pid: null, state: "reused" },
});
});
it("versions lifecycle failures with a stable code", () => {
expect(
lifecycleFailurePayload(
"start",
"conflicting-lifecycle-flags",
"--background and --foreground cannot be used together",
),
).toEqual({
schemaVersion: 1,
operation: "start",
ok: false,
error: {
code: "conflicting-lifecycle-flags",
message: "--background and --foreground cannot be used together",
},
});
});
});