mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-09 12:00:26 +00:00
feat(cli): deprecate validate, inspect, layout in favor of check
One stderr notice per invocation and _meta.deprecated: true in JSON mode (shared helper next to withMeta; layout owns both inspect and layout via createInspectCommand). Help descriptions gain the pointer. No behavior change; removal ships separately once migration telemetry says usage has decayed. fix(producer): route info/debug logs to stderr — the compiler's 'Localized remote media' line was landing on stdout ahead of validate's --json payload, breaking every piped consumer. Diagnostics now share stderr with warn/error; render progress uses its own channel.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { CommandDef } from "citty";
|
||||
import { runCommand } from "citty";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
extractCompositionErrorsFromLint,
|
||||
navigationTimeoutHint,
|
||||
@@ -28,6 +30,29 @@ vi.mock("../utils/producer.js", () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
// U5 deprecation tests: resolveProject and lintProject are both reached via a
|
||||
// dynamic `await import(...)` inside validate.ts's run() / validateInBrowser(),
|
||||
// so vi.mock intercepts them the same way it would a static import. Mocking
|
||||
// resolveProject skips real filesystem project resolution; mocking lintProject
|
||||
// (the first await inside validateInBrowser) gives a fast, deterministic
|
||||
// failure well before any real browser or network work — exercising run()'s
|
||||
// outer catch (the JSON failure envelope) without needing headless Chrome.
|
||||
const FAKE_PROJECT = {
|
||||
dir: "/fake-project",
|
||||
name: "fake-project",
|
||||
indexPath: "/fake-project/index.html",
|
||||
};
|
||||
|
||||
vi.mock("../utils/project.js", () => ({
|
||||
resolveProject: vi.fn(() => FAKE_PROJECT),
|
||||
}));
|
||||
|
||||
vi.mock("../utils/lintProject.js", () => ({
|
||||
lintProject: vi.fn(async () => {
|
||||
throw new Error("lint failed (test double)");
|
||||
}),
|
||||
}));
|
||||
|
||||
// Regression for the validate audio-duration-probe timeout: a slow-loading
|
||||
// media element's duration was snapshotted once, at a fixed point in time,
|
||||
// and any element still mid-load was permanently misreported as unreadable.
|
||||
@@ -282,3 +307,62 @@ describe("navigationTimeoutHint", () => {
|
||||
expect(navigationTimeoutHint("some string failure", 10000)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
function metaDescription(command: CommandDef): string {
|
||||
const meta = command.meta;
|
||||
if (meta && typeof meta === "object" && "description" in meta) {
|
||||
return String(meta.description ?? "");
|
||||
}
|
||||
throw new Error("expected a synchronous meta object");
|
||||
}
|
||||
|
||||
describe("validate command deprecation (U5)", () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("marks the command description as deprecated", async () => {
|
||||
const { default: validateCommand } = await import("./validate.js");
|
||||
expect(metaDescription(validateCommand)).toContain("(deprecated, use check)");
|
||||
});
|
||||
|
||||
it("prints a one-line deprecation notice to stderr and never to stdout", async () => {
|
||||
const stderrWrites: string[] = [];
|
||||
const stdoutWrites: string[] = [];
|
||||
vi.spyOn(process.stderr, "write").mockImplementation((chunk: unknown) => {
|
||||
stderrWrites.push(String(chunk));
|
||||
return true;
|
||||
});
|
||||
vi.spyOn(process.stdout, "write").mockImplementation((chunk: unknown) => {
|
||||
stdoutWrites.push(String(chunk));
|
||||
return true;
|
||||
});
|
||||
vi.spyOn(process, "exit").mockImplementation(() => undefined as never);
|
||||
vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
|
||||
const { default: validateCommand } = await import("./validate.js");
|
||||
await runCommand(validateCommand, { rawArgs: ["--json"] });
|
||||
|
||||
const stderrText = stderrWrites.join("");
|
||||
expect(stderrText).toContain("hyperframes validate");
|
||||
expect(stderrText).toContain("hyperframes check");
|
||||
expect(stdoutWrites.join("")).toBe("");
|
||||
});
|
||||
|
||||
it("--json output is valid JSON with _meta.deprecated === true on failure", async () => {
|
||||
vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
||||
vi.spyOn(process, "exit").mockImplementation(() => undefined as never);
|
||||
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
|
||||
const { default: validateCommand } = await import("./validate.js");
|
||||
await runCommand(validateCommand, { rawArgs: ["--json"] });
|
||||
|
||||
const jsonCall = logSpy.mock.calls.find(
|
||||
([arg]) => typeof arg === "string" && arg.trim().startsWith("{"),
|
||||
);
|
||||
expect(jsonCall).toBeDefined();
|
||||
const parsed = JSON.parse(String(jsonCall?.[0]));
|
||||
expect(parsed.ok).toBe(false);
|
||||
expect(parsed._meta.deprecated).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user