test(perf): reduce repeated cli program setup overhead
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
configureCommand,
|
||||
ensureConfigReady,
|
||||
@@ -26,15 +26,20 @@ vi.mock("./config-cli.js", () => ({
|
||||
const { buildProgram } = await import("./program.js");
|
||||
|
||||
describe("cli program (smoke)", () => {
|
||||
let program = createProgram();
|
||||
|
||||
function createProgram() {
|
||||
return buildProgram();
|
||||
}
|
||||
|
||||
async function runProgram(argv: string[]) {
|
||||
const program = createProgram();
|
||||
await program.parseAsync(argv, { from: "user" });
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
program = createProgram();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
runTui.mockResolvedValue(undefined);
|
||||
@@ -42,7 +47,6 @@ describe("cli program (smoke)", () => {
|
||||
});
|
||||
|
||||
it("registers memory + status commands", () => {
|
||||
const program = createProgram();
|
||||
const names = program.commands.map((command) => command.name());
|
||||
expect(names).toContain("message");
|
||||
expect(names).toContain("memory");
|
||||
|
||||
@@ -73,6 +73,9 @@ afterEach(() => {
|
||||
|
||||
describe("registerPreActionHooks", () => {
|
||||
let program: Command;
|
||||
let preActionHook:
|
||||
| ((thisCommand: Command, actionCommand: Command) => Promise<void> | void)
|
||||
| null = null;
|
||||
|
||||
function buildProgram() {
|
||||
const program = new Command().name("openclaw");
|
||||
@@ -104,22 +107,32 @@ describe("registerPreActionHooks", () => {
|
||||
return program;
|
||||
}
|
||||
|
||||
async function runCommand(
|
||||
params: { parseArgv: string[]; processArgv?: string[] },
|
||||
program: Command,
|
||||
) {
|
||||
function resolveActionCommand(parseArgv: string[]): Command {
|
||||
let current = program;
|
||||
for (const segment of parseArgv) {
|
||||
const next = current.commands.find((command) => command.name() === segment);
|
||||
if (!next) {
|
||||
break;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
async function runPreAction(params: { parseArgv: string[]; processArgv?: string[] }) {
|
||||
process.argv = params.processArgv ?? [...params.parseArgv];
|
||||
await program.parseAsync(params.parseArgv, { from: "user" });
|
||||
const actionCommand = resolveActionCommand(params.parseArgv);
|
||||
if (!preActionHook) {
|
||||
throw new Error("missing preAction hook");
|
||||
}
|
||||
await preActionHook(program, actionCommand);
|
||||
}
|
||||
|
||||
it("emits banner, resolves config, and enables verbose from --debug", async () => {
|
||||
await runCommand(
|
||||
{
|
||||
parseArgv: ["status"],
|
||||
processArgv: ["node", "openclaw", "status", "--debug"],
|
||||
},
|
||||
program,
|
||||
);
|
||||
await runPreAction({
|
||||
parseArgv: ["status"],
|
||||
processArgv: ["node", "openclaw", "status", "--debug"],
|
||||
});
|
||||
|
||||
expect(emitCliBannerMock).toHaveBeenCalledWith("9.9.9-test");
|
||||
expect(setVerboseMock).toHaveBeenCalledWith(true);
|
||||
@@ -132,13 +145,10 @@ describe("registerPreActionHooks", () => {
|
||||
});
|
||||
|
||||
it("loads plugin registry for plugin-required commands", async () => {
|
||||
await runCommand(
|
||||
{
|
||||
parseArgv: ["message", "send"],
|
||||
processArgv: ["node", "openclaw", "message", "send"],
|
||||
},
|
||||
program,
|
||||
);
|
||||
await runPreAction({
|
||||
parseArgv: ["message", "send"],
|
||||
processArgv: ["node", "openclaw", "message", "send"],
|
||||
});
|
||||
|
||||
expect(setVerboseMock).toHaveBeenCalledWith(false);
|
||||
expect(process.env.NODE_NO_WARNINGS).toBe("1");
|
||||
@@ -150,37 +160,28 @@ describe("registerPreActionHooks", () => {
|
||||
});
|
||||
|
||||
it("loads plugin registry for configure command", async () => {
|
||||
await runCommand(
|
||||
{
|
||||
parseArgv: ["configure"],
|
||||
processArgv: ["node", "openclaw", "configure"],
|
||||
},
|
||||
program,
|
||||
);
|
||||
await runPreAction({
|
||||
parseArgv: ["configure"],
|
||||
processArgv: ["node", "openclaw", "configure"],
|
||||
});
|
||||
|
||||
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("skips config guard for doctor command", async () => {
|
||||
await runCommand(
|
||||
{
|
||||
parseArgv: ["doctor"],
|
||||
processArgv: ["node", "openclaw", "doctor"],
|
||||
},
|
||||
program,
|
||||
);
|
||||
await runPreAction({
|
||||
parseArgv: ["doctor"],
|
||||
processArgv: ["node", "openclaw", "doctor"],
|
||||
});
|
||||
|
||||
expect(ensureConfigReadyMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("skips preaction work when argv indicates help/version", async () => {
|
||||
await runCommand(
|
||||
{
|
||||
parseArgv: ["status"],
|
||||
processArgv: ["node", "openclaw", "--version"],
|
||||
},
|
||||
program,
|
||||
);
|
||||
await runPreAction({
|
||||
parseArgv: ["status"],
|
||||
processArgv: ["node", "openclaw", "--version"],
|
||||
});
|
||||
|
||||
expect(emitCliBannerMock).not.toHaveBeenCalled();
|
||||
expect(setVerboseMock).not.toHaveBeenCalled();
|
||||
@@ -189,43 +190,21 @@ describe("registerPreActionHooks", () => {
|
||||
|
||||
it("hides banner when OPENCLAW_HIDE_BANNER is truthy", async () => {
|
||||
process.env.OPENCLAW_HIDE_BANNER = "1";
|
||||
await runCommand(
|
||||
{
|
||||
parseArgv: ["status"],
|
||||
processArgv: ["node", "openclaw", "status"],
|
||||
},
|
||||
program,
|
||||
);
|
||||
await runPreAction({
|
||||
parseArgv: ["status"],
|
||||
processArgv: ["node", "openclaw", "status"],
|
||||
});
|
||||
|
||||
expect(emitCliBannerMock).not.toHaveBeenCalled();
|
||||
expect(ensureConfigReadyMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("suppresses doctor stdout for any --json output command", async () => {
|
||||
await runCommand(
|
||||
{
|
||||
parseArgv: ["message", "send", "--json"],
|
||||
processArgv: ["node", "openclaw", "message", "send", "--json"],
|
||||
},
|
||||
program,
|
||||
);
|
||||
|
||||
expect(ensureConfigReadyMock).toHaveBeenCalledWith({
|
||||
runtime: runtimeMock,
|
||||
commandPath: ["message", "send"],
|
||||
suppressDoctorStdout: true,
|
||||
it("suppresses doctor stdout for --json output command", async () => {
|
||||
await runPreAction({
|
||||
parseArgv: ["update", "status", "--json"],
|
||||
processArgv: ["node", "openclaw", "update", "status", "--json"],
|
||||
});
|
||||
|
||||
vi.clearAllMocks();
|
||||
|
||||
await runCommand(
|
||||
{
|
||||
parseArgv: ["update", "status", "--json"],
|
||||
processArgv: ["node", "openclaw", "update", "status", "--json"],
|
||||
},
|
||||
program,
|
||||
);
|
||||
|
||||
expect(ensureConfigReadyMock).toHaveBeenCalledWith({
|
||||
runtime: runtimeMock,
|
||||
commandPath: ["update", "status"],
|
||||
@@ -234,13 +213,10 @@ describe("registerPreActionHooks", () => {
|
||||
});
|
||||
|
||||
it("does not treat config set --json (strict-parse alias) as json output mode", async () => {
|
||||
await runCommand(
|
||||
{
|
||||
parseArgv: ["config", "set", "gateway.auth.mode", "{bad", "--json"],
|
||||
processArgv: ["node", "openclaw", "config", "set", "gateway.auth.mode", "{bad", "--json"],
|
||||
},
|
||||
program,
|
||||
);
|
||||
await runPreAction({
|
||||
parseArgv: ["config", "set", "gateway.auth.mode", "{bad", "--json"],
|
||||
processArgv: ["node", "openclaw", "config", "set", "gateway.auth.mode", "{bad", "--json"],
|
||||
});
|
||||
|
||||
expect(ensureConfigReadyMock).toHaveBeenCalledWith({
|
||||
runtime: runtimeMock,
|
||||
@@ -250,5 +226,13 @@ describe("registerPreActionHooks", () => {
|
||||
|
||||
beforeAll(() => {
|
||||
program = buildProgram();
|
||||
const hooks = (
|
||||
program as unknown as {
|
||||
_lifeCycleHooks?: {
|
||||
preAction?: Array<(thisCommand: Command, actionCommand: Command) => Promise<void> | void>;
|
||||
};
|
||||
}
|
||||
)._lifeCycleHooks?.preAction;
|
||||
preActionHook = hooks?.[0] ?? null;
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user