mirror of https://github.com/openclaw/openclaw.git
test: speed up cli and command suites
This commit is contained in:
parent
6b6ddcd2a6
commit
3f1d6fe147
|
|
@ -1,36 +1,38 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { runRegisteredCli } from "../test-utils/command-runner.js";
|
||||
import { withTempSecretFiles } from "../test-utils/secret-file-fixture.js";
|
||||
import { registerAcpCli } from "./acp-cli.js";
|
||||
|
||||
const runAcpClientInteractive = vi.fn(async (_opts: unknown) => {});
|
||||
const serveAcpGateway = vi.fn(async (_opts: unknown) => {});
|
||||
const mocks = vi.hoisted(() => ({
|
||||
runAcpClientInteractive: vi.fn(async (_opts: unknown) => {}),
|
||||
serveAcpGateway: vi.fn(async (_opts: unknown) => {}),
|
||||
defaultRuntime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
writeStdout: vi.fn(),
|
||||
writeJson: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const defaultRuntime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
writeStdout: vi.fn(),
|
||||
writeJson: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
const { runAcpClientInteractive, serveAcpGateway, defaultRuntime } = mocks;
|
||||
|
||||
const passwordKey = () => ["pass", "word"].join("");
|
||||
|
||||
vi.mock("../acp/client.js", () => ({
|
||||
runAcpClientInteractive: (opts: unknown) => runAcpClientInteractive(opts),
|
||||
runAcpClientInteractive: (opts: unknown) => mocks.runAcpClientInteractive(opts),
|
||||
}));
|
||||
|
||||
vi.mock("../acp/server.js", () => ({
|
||||
serveAcpGateway: (opts: unknown) => serveAcpGateway(opts),
|
||||
serveAcpGateway: (opts: unknown) => mocks.serveAcpGateway(opts),
|
||||
}));
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
describe("acp cli option collisions", () => {
|
||||
let registerAcpCli: typeof import("./acp-cli.js").registerAcpCli;
|
||||
|
||||
function createAcpProgram() {
|
||||
const program = new Command();
|
||||
registerAcpCli(program);
|
||||
|
|
@ -48,10 +50,6 @@ describe("acp cli option collisions", () => {
|
|||
expect(defaultRuntime.exit).toHaveBeenCalledWith(1);
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerAcpCli } = await import("./acp-cli.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
runAcpClientInteractive.mockClear();
|
||||
serveAcpGateway.mockClear();
|
||||
|
|
|
|||
|
|
@ -1,17 +1,12 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { formatCliBannerLine } from "./banner.js";
|
||||
|
||||
const readCliBannerTaglineModeMock = vi.fn();
|
||||
const readCliBannerTaglineModeMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("./banner-config-lite.js", () => ({
|
||||
readCliBannerTaglineMode: readCliBannerTaglineModeMock,
|
||||
}));
|
||||
|
||||
let formatCliBannerLine: typeof import("./banner.js").formatCliBannerLine;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ formatCliBannerLine } = await import("./banner.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
readCliBannerTaglineModeMock.mockReset();
|
||||
readCliBannerTaglineModeMock.mockReturnValue(undefined);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { __testing, resolveCliChannelOptions } from "./channel-options.js";
|
||||
|
||||
const readFileSyncMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
|
|
@ -19,13 +20,6 @@ vi.mock("../channels/registry.js", () => ({
|
|||
CHAT_CHANNEL_ORDER: ["telegram", "discord"],
|
||||
}));
|
||||
|
||||
let resolveCliChannelOptions: typeof import("./channel-options.js").resolveCliChannelOptions;
|
||||
let __testing: typeof import("./channel-options.js").__testing;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ resolveCliChannelOptions, __testing } = await import("./channel-options.js"));
|
||||
});
|
||||
|
||||
describe("resolveCliChannelOptions", () => {
|
||||
afterEach(() => {
|
||||
__testing.resetPrecomputedChannelOptionsForTests();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import { Command } from "commander";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { registerDnsCli } from "./dns-cli.js";
|
||||
import { parseCanvasSnapshotPayload } from "./nodes-canvas.js";
|
||||
import { parseByteSize } from "./parse-bytes.js";
|
||||
import { parseDurationMs } from "./parse-duration.js";
|
||||
import { shouldSkipRespawnForArgv } from "./respawn-policy.js";
|
||||
import { waitForever } from "./wait.js";
|
||||
|
||||
const { registerDnsCli } = await import("./dns-cli.js");
|
||||
|
||||
describe("waitForever", () => {
|
||||
it("creates an unref'ed interval and returns a pending promise", () => {
|
||||
const setIntervalSpy = vi.spyOn(global, "setInterval");
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveCommandSecretRefsViaGateway } from "./command-secret-gateway.js";
|
||||
|
||||
const callGateway = vi.fn();
|
||||
const mocks = vi.hoisted(() => ({
|
||||
callGateway: vi.fn(),
|
||||
}));
|
||||
|
||||
const { callGateway } = mocks;
|
||||
|
||||
vi.mock("../gateway/call.js", () => ({
|
||||
callGateway,
|
||||
callGateway: mocks.callGateway,
|
||||
}));
|
||||
|
||||
vi.mock("../secrets/runtime-web-tools.js", () => ({
|
||||
|
|
@ -16,13 +21,6 @@ vi.mock("../utils/message-channel.js", () => ({
|
|||
GATEWAY_CLIENT_NAMES: { CLI: "cli" },
|
||||
}));
|
||||
|
||||
let resolveCommandSecretRefsViaGateway: typeof import("./command-secret-gateway.js").resolveCommandSecretRefsViaGateway;
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ resolveCommandSecretRefsViaGateway } = await import("./command-secret-gateway.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
callGateway.mockReset();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,9 +1,29 @@
|
|||
import { Command } from "commander";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { registerCronCli } from "./cron-cli.js";
|
||||
|
||||
const CRON_CLI_TEST_TIMEOUT_MS = 15_000;
|
||||
const { defaultRuntime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const mocks = vi.hoisted(() => {
|
||||
const defaultRuntime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
writeStdout: vi.fn((value: string) => {
|
||||
defaultRuntime.log(value.endsWith("\n") ? value.slice(0, -1) : value);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
defaultRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
}),
|
||||
};
|
||||
return {
|
||||
defaultRuntime,
|
||||
callGatewayFromCli: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const { defaultRuntime, callGatewayFromCli } = mocks;
|
||||
|
||||
const defaultGatewayMock = async (
|
||||
method: string,
|
||||
|
|
@ -16,23 +36,21 @@ const defaultGatewayMock = async (
|
|||
}
|
||||
return { ok: true, params };
|
||||
};
|
||||
const callGatewayFromCli = vi.fn(defaultGatewayMock);
|
||||
callGatewayFromCli.mockImplementation(defaultGatewayMock);
|
||||
|
||||
vi.mock("./gateway-rpc.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("./gateway-rpc.js")>("./gateway-rpc.js");
|
||||
return {
|
||||
...actual,
|
||||
callGatewayFromCli: (method: string, opts: unknown, params?: unknown, extra?: unknown) =>
|
||||
callGatewayFromCli(method, opts, params, extra as number | undefined),
|
||||
mocks.callGatewayFromCli(method, opts, params, extra as number | undefined),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
const { registerCronCli } = await import("./cron-cli.js");
|
||||
|
||||
type CronUpdatePatch = {
|
||||
patch?: {
|
||||
schedule?: { kind?: string; expr?: string; tz?: string; staggerMs?: number };
|
||||
|
|
@ -72,7 +90,11 @@ function buildProgram() {
|
|||
function resetGatewayMock() {
|
||||
callGatewayFromCli.mockClear();
|
||||
callGatewayFromCli.mockImplementation(defaultGatewayMock);
|
||||
resetRuntimeCapture();
|
||||
defaultRuntime.log.mockClear();
|
||||
defaultRuntime.error.mockClear();
|
||||
defaultRuntime.writeStdout.mockClear();
|
||||
defaultRuntime.writeJson.mockClear();
|
||||
defaultRuntime.exit.mockClear();
|
||||
}
|
||||
|
||||
async function runCronCommand(args: string[]): Promise<void> {
|
||||
|
|
@ -176,8 +198,7 @@ async function runCronRunAndCaptureExit(params: {
|
|||
},
|
||||
);
|
||||
|
||||
const runtimeModule = await import("../runtime.js");
|
||||
const runtime = runtimeModule.defaultRuntime as { exit: (code: number) => void };
|
||||
const runtime = defaultRuntime as { exit: (code: number) => void };
|
||||
const originalExit = runtime.exit;
|
||||
const exitSpy = vi.fn();
|
||||
runtime.exit = exitSpy;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Command } from "commander";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { registerDaemonCli } from "./daemon-cli.js";
|
||||
|
||||
const probeGatewayStatus = vi.fn(async (..._args: unknown[]) => ({ ok: true }));
|
||||
const resolveGatewayProgramArguments = vi.fn(async (_opts?: unknown) => ({
|
||||
|
|
@ -34,7 +34,28 @@ const buildGatewayInstallPlan = vi.fn(
|
|||
}),
|
||||
);
|
||||
|
||||
const { runtimeLogs, defaultRuntime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const mocks = vi.hoisted(() => {
|
||||
const runtimeLogs: string[] = [];
|
||||
const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" ");
|
||||
const defaultRuntime = {
|
||||
log: vi.fn((...args: unknown[]) => {
|
||||
runtimeLogs.push(stringifyArgs(args));
|
||||
}),
|
||||
error: vi.fn(),
|
||||
writeStdout: vi.fn((value: string) => {
|
||||
defaultRuntime.log(value.endsWith("\n") ? value.slice(0, -1) : value);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
defaultRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
}),
|
||||
};
|
||||
return { runtimeLogs, defaultRuntime };
|
||||
});
|
||||
|
||||
const { runtimeLogs } = mocks;
|
||||
|
||||
vi.mock("./daemon-cli/probe.js", () => ({
|
||||
probeGatewayStatus: (opts: unknown) => probeGatewayStatus(opts),
|
||||
|
|
@ -85,7 +106,7 @@ vi.mock("../infra/ports.js", () => ({
|
|||
|
||||
vi.mock("../runtime.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../runtime.js")>()),
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
vi.mock("../commands/daemon-install-helpers.js", () => ({
|
||||
|
|
@ -101,7 +122,6 @@ vi.mock("./progress.js", () => ({
|
|||
withProgress: async (_opts: unknown, fn: () => Promise<unknown>) => await fn(),
|
||||
}));
|
||||
|
||||
const { registerDaemonCli } = await import("./daemon-cli.js");
|
||||
let daemonProgram: Command;
|
||||
|
||||
function createDaemonProgram() {
|
||||
|
|
@ -145,7 +165,7 @@ describe("daemon-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("probes gateway status by default", async () => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
probeGatewayStatus.mockClear();
|
||||
|
||||
await runDaemonCommand(["daemon", "status"]);
|
||||
|
|
@ -159,7 +179,7 @@ describe("daemon-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("derives probe URL from service args + env (json)", async () => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
probeGatewayStatus.mockClear();
|
||||
inspectPortUsage.mockClear();
|
||||
|
||||
|
|
@ -208,7 +228,7 @@ describe("daemon-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("installs the daemon (json output)", async () => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
serviceIsLoaded.mockResolvedValueOnce(false);
|
||||
serviceInstall.mockClear();
|
||||
|
||||
|
|
@ -234,7 +254,7 @@ describe("daemon-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("starts and stops daemon (json output)", async () => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
serviceRestart.mockClear();
|
||||
serviceStop.mockClear();
|
||||
serviceIsLoaded.mockResolvedValue(true);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { probeGatewayStatus } from "./probe.js";
|
||||
|
||||
const callGatewayMock = vi.hoisted(() => vi.fn());
|
||||
const probeGatewayMock = vi.hoisted(() => vi.fn());
|
||||
|
|
@ -15,8 +16,6 @@ vi.mock("../progress.js", () => ({
|
|||
withProgress: async (_opts: unknown, fn: () => Promise<unknown>) => await fn(),
|
||||
}));
|
||||
|
||||
const { probeGatewayStatus } = await import("./probe.js");
|
||||
|
||||
describe("probeGatewayStatus", () => {
|
||||
it("uses lightweight token-only probing for daemon status", async () => {
|
||||
callGatewayMock.mockReset();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|||
import { createMockGatewayService } from "../../daemon/service.test-helpers.js";
|
||||
import { captureEnv } from "../../test-utils/env.js";
|
||||
import type { GatewayRestartSnapshot } from "./restart-health.js";
|
||||
import { gatherDaemonStatus } from "./status.gather.js";
|
||||
|
||||
const callGatewayStatusProbe = vi.fn<
|
||||
(opts?: unknown) => Promise<{ ok: boolean; url?: string; error?: string | null }>
|
||||
|
|
@ -136,8 +137,6 @@ vi.mock("./restart-health.js", () => ({
|
|||
inspectGatewayRestart: (opts: unknown) => inspectGatewayRestart(opts),
|
||||
}));
|
||||
|
||||
const { gatherDaemonStatus } = await import("./status.gather.js");
|
||||
|
||||
describe("gatherDaemonStatus", () => {
|
||||
let envSnapshot: ReturnType<typeof captureEnv>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { formatCliCommand } from "../command-format.js";
|
||||
import { printDaemonStatus } from "./status.print.js";
|
||||
|
||||
const runtime = vi.hoisted(() => ({
|
||||
log: vi.fn<(line: string) => void>(),
|
||||
|
|
@ -69,8 +70,6 @@ vi.mock("./status.gather.js", () => ({
|
|||
resolvePortListeningAddresses: () => ["127.0.0.1:18789"],
|
||||
}));
|
||||
|
||||
const { printDaemonStatus } = await import("./status.print.js");
|
||||
|
||||
describe("printDaemonStatus", () => {
|
||||
beforeEach(() => {
|
||||
runtime.log.mockReset();
|
||||
|
|
|
|||
|
|
@ -1,37 +1,53 @@
|
|||
import { Command } from "commander";
|
||||
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerDevicesCli } from "./devices-cli.js";
|
||||
|
||||
const { defaultRuntime: runtime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
runtime.exit.mockImplementation(() => {});
|
||||
const callGateway = vi.fn();
|
||||
const buildGatewayConnectionDetails = vi.fn(() => ({
|
||||
url: "ws://127.0.0.1:18789",
|
||||
urlSource: "local loopback",
|
||||
message: "",
|
||||
const mocks = vi.hoisted(() => ({
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
writeJson: vi.fn(),
|
||||
},
|
||||
callGateway: vi.fn(),
|
||||
buildGatewayConnectionDetails: vi.fn(() => ({
|
||||
url: "ws://127.0.0.1:18789",
|
||||
urlSource: "local loopback",
|
||||
message: "",
|
||||
})),
|
||||
listDevicePairing: vi.fn(),
|
||||
approveDevicePairing: vi.fn(),
|
||||
summarizeDeviceTokens: vi.fn(),
|
||||
withProgress: vi.fn(async (_opts: unknown, fn: () => Promise<unknown>) => await fn()),
|
||||
}));
|
||||
const listDevicePairing = vi.fn();
|
||||
const approveDevicePairing = vi.fn();
|
||||
const summarizeDeviceTokens = vi.fn();
|
||||
const withProgress = vi.fn(async (_opts: unknown, fn: () => Promise<unknown>) => await fn());
|
||||
vi.mock("../gateway/call.js", () => ({
|
||||
|
||||
const {
|
||||
runtime,
|
||||
callGateway,
|
||||
buildGatewayConnectionDetails,
|
||||
}));
|
||||
|
||||
vi.mock("./progress.js", () => ({
|
||||
withProgress,
|
||||
}));
|
||||
|
||||
vi.mock("../infra/device-pairing.js", () => ({
|
||||
listDevicePairing,
|
||||
approveDevicePairing,
|
||||
summarizeDeviceTokens,
|
||||
withProgress,
|
||||
} = mocks;
|
||||
|
||||
vi.mock("../gateway/call.js", () => ({
|
||||
callGateway: mocks.callGateway,
|
||||
buildGatewayConnectionDetails: mocks.buildGatewayConnectionDetails,
|
||||
}));
|
||||
|
||||
vi.mock("../runtime.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../runtime.js")>()),
|
||||
defaultRuntime: runtime,
|
||||
vi.mock("./progress.js", () => ({
|
||||
withProgress: mocks.withProgress,
|
||||
}));
|
||||
|
||||
vi.mock("../infra/device-pairing.js", () => ({
|
||||
listDevicePairing: mocks.listDevicePairing,
|
||||
approveDevicePairing: mocks.approveDevicePairing,
|
||||
summarizeDeviceTokens: mocks.summarizeDeviceTokens,
|
||||
}));
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime: mocks.runtime,
|
||||
writeRuntimeJson: (
|
||||
targetRuntime: { log: (...args: unknown[]) => void },
|
||||
value: unknown,
|
||||
|
|
@ -39,12 +55,6 @@ vi.mock("../runtime.js", async (importOriginal) => ({
|
|||
) => targetRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined)),
|
||||
}));
|
||||
|
||||
let registerDevicesCli: typeof import("./devices-cli.js").registerDevicesCli;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerDevicesCli } = await import("./devices-cli.js"));
|
||||
});
|
||||
|
||||
async function runDevicesApprove(argv: string[]) {
|
||||
await runDevicesCommand(["approve", ...argv]);
|
||||
}
|
||||
|
|
@ -321,9 +331,12 @@ describe("devices cli list", () => {
|
|||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
runtime.exit.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetRuntimeCapture();
|
||||
callGateway.mockClear();
|
||||
buildGatewayConnectionDetails.mockClear();
|
||||
buildGatewayConnectionDetails.mockReturnValue({
|
||||
url: "ws://127.0.0.1:18789",
|
||||
|
|
|
|||
|
|
@ -1,16 +1,30 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerDirectoryCli } from "./directory-cli.js";
|
||||
import type { CliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
|
||||
const runtimeState = vi.hoisted(() => ({ capture: null as CliRuntimeCapture | null }));
|
||||
|
||||
function getRuntimeCapture(): CliRuntimeCapture {
|
||||
if (!runtimeState.capture) {
|
||||
throw new Error("runtime capture not initialized");
|
||||
}
|
||||
return runtimeState.capture;
|
||||
}
|
||||
const runtimeState = vi.hoisted(() => {
|
||||
const runtimeLogs: string[] = [];
|
||||
const runtimeErrors: string[] = [];
|
||||
const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" ");
|
||||
const defaultRuntime = {
|
||||
log: vi.fn((...args: unknown[]) => {
|
||||
runtimeLogs.push(stringifyArgs(args));
|
||||
}),
|
||||
error: vi.fn((...args: unknown[]) => {
|
||||
runtimeErrors.push(stringifyArgs(args));
|
||||
}),
|
||||
writeStdout: vi.fn((value: string) => {
|
||||
defaultRuntime.log(value.endsWith("\n") ? value.slice(0, -1) : value);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
defaultRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
return { defaultRuntime, runtimeLogs, runtimeErrors };
|
||||
});
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
loadConfig: vi.fn(),
|
||||
|
|
@ -49,16 +63,15 @@ vi.mock("../channels/plugins/helpers.js", () => ({
|
|||
resolveChannelDefaultAccountId: mocks.resolveChannelDefaultAccountId,
|
||||
}));
|
||||
|
||||
vi.mock("../runtime.js", async () => {
|
||||
const { createCliRuntimeCapture } = await import("./test-runtime-capture.js");
|
||||
runtimeState.capture ??= createCliRuntimeCapture();
|
||||
return { defaultRuntime: runtimeState.capture.defaultRuntime };
|
||||
});
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime: runtimeState.defaultRuntime,
|
||||
}));
|
||||
|
||||
describe("registerDirectoryCli", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
getRuntimeCapture().resetRuntimeCapture();
|
||||
runtimeState.runtimeLogs.length = 0;
|
||||
runtimeState.runtimeErrors.length = 0;
|
||||
mocks.loadConfig.mockReturnValue({ channels: {} });
|
||||
mocks.readConfigFileSnapshot.mockResolvedValue({ hash: "config-1" });
|
||||
mocks.applyPluginAutoEnable.mockImplementation(({ config }) => ({ config, changes: [] }));
|
||||
|
|
@ -69,7 +82,12 @@ describe("registerDirectoryCli", () => {
|
|||
configured: ["demo-channel"],
|
||||
source: "explicit",
|
||||
});
|
||||
getRuntimeCapture().defaultRuntime.exit.mockImplementation((code: number) => {
|
||||
runtimeState.defaultRuntime.log.mockClear();
|
||||
runtimeState.defaultRuntime.error.mockClear();
|
||||
runtimeState.defaultRuntime.writeStdout.mockClear();
|
||||
runtimeState.defaultRuntime.writeJson.mockClear();
|
||||
runtimeState.defaultRuntime.exit.mockClear();
|
||||
runtimeState.defaultRuntime.exit.mockImplementation((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
});
|
||||
});
|
||||
|
|
@ -113,10 +131,10 @@ describe("registerDirectoryCli", () => {
|
|||
accountId: "default",
|
||||
}),
|
||||
);
|
||||
expect(getRuntimeCapture().defaultRuntime.log).toHaveBeenCalledWith(
|
||||
expect(runtimeState.defaultRuntime.log).toHaveBeenCalledWith(
|
||||
JSON.stringify({ id: "self-1", name: "Family Phone" }, null, 2),
|
||||
);
|
||||
expect(getRuntimeCapture().defaultRuntime.error).not.toHaveBeenCalled();
|
||||
expect(runtimeState.defaultRuntime.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uses the auto-enabled config snapshot for omitted channel selection", async () => {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,44 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import * as execApprovals from "../infra/exec-approvals.js";
|
||||
import { registerExecApprovalsCli } from "./exec-approvals-cli.js";
|
||||
|
||||
const callGatewayFromCli = vi.fn(async (method: string, _opts: unknown, params?: unknown) => {
|
||||
if (method.endsWith(".get")) {
|
||||
return {
|
||||
path: "/tmp/exec-approvals.json",
|
||||
exists: true,
|
||||
hash: "hash-1",
|
||||
file: { version: 1, agents: {} },
|
||||
};
|
||||
}
|
||||
return { method, params };
|
||||
const mocks = vi.hoisted(() => {
|
||||
const runtimeErrors: string[] = [];
|
||||
const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" ");
|
||||
const defaultRuntime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn((...args: unknown[]) => {
|
||||
runtimeErrors.push(stringifyArgs(args));
|
||||
}),
|
||||
writeStdout: vi.fn((value: string) => {
|
||||
defaultRuntime.log(value.endsWith("\n") ? value.slice(0, -1) : value);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
defaultRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
}),
|
||||
};
|
||||
return {
|
||||
callGatewayFromCli: vi.fn(async (method: string, _opts: unknown, params?: unknown) => {
|
||||
if (method.endsWith(".get")) {
|
||||
return {
|
||||
path: "/tmp/exec-approvals.json",
|
||||
exists: true,
|
||||
hash: "hash-1",
|
||||
file: { version: 1, agents: {} },
|
||||
};
|
||||
}
|
||||
return { method, params };
|
||||
}),
|
||||
defaultRuntime,
|
||||
runtimeErrors,
|
||||
};
|
||||
});
|
||||
|
||||
const { runtimeErrors, defaultRuntime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const { callGatewayFromCli, defaultRuntime, runtimeErrors } = mocks;
|
||||
|
||||
const localSnapshot = {
|
||||
path: "/tmp/local-exec-approvals.json",
|
||||
|
|
@ -30,7 +54,7 @@ function resetLocalSnapshot() {
|
|||
|
||||
vi.mock("./gateway-rpc.js", () => ({
|
||||
callGatewayFromCli: (method: string, opts: unknown, params?: unknown) =>
|
||||
callGatewayFromCli(method, opts, params),
|
||||
mocks.callGatewayFromCli(method, opts, params),
|
||||
}));
|
||||
|
||||
vi.mock("./nodes-cli/rpc.js", async () => {
|
||||
|
|
@ -42,7 +66,7 @@ vi.mock("./nodes-cli/rpc.js", async () => {
|
|||
});
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
vi.mock("../infra/exec-approvals.js", async () => {
|
||||
|
|
@ -56,9 +80,6 @@ vi.mock("../infra/exec-approvals.js", async () => {
|
|||
};
|
||||
});
|
||||
|
||||
const { registerExecApprovalsCli } = await import("./exec-approvals-cli.js");
|
||||
const execApprovals = await import("../infra/exec-approvals.js");
|
||||
|
||||
describe("exec approvals CLI", () => {
|
||||
const createProgram = () => {
|
||||
const program = new Command();
|
||||
|
|
@ -74,8 +95,13 @@ describe("exec approvals CLI", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
resetLocalSnapshot();
|
||||
resetRuntimeCapture();
|
||||
runtimeErrors.length = 0;
|
||||
callGatewayFromCli.mockClear();
|
||||
defaultRuntime.log.mockClear();
|
||||
defaultRuntime.error.mockClear();
|
||||
defaultRuntime.writeStdout.mockClear();
|
||||
defaultRuntime.writeJson.mockClear();
|
||||
defaultRuntime.exit.mockClear();
|
||||
});
|
||||
|
||||
it("routes get command to local, gateway, and node modes", async () => {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Command } from "commander";
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withEnvOverride } from "../config/test-helpers.js";
|
||||
import { GatewayLockError } from "../infra/gateway-lock.js";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { registerGatewayCli } from "./gateway-cli.js";
|
||||
|
||||
type DiscoveredBeacon = Awaited<
|
||||
ReturnType<typeof import("../infra/bonjour-discovery.js").discoverGatewayBeacons>
|
||||
|
|
@ -30,8 +30,31 @@ const gatewayStatusCommand = vi.fn<(opts: unknown) => Promise<void>>(async () =>
|
|||
const inspectPortUsage = vi.fn(async (_port: number) => ({ status: "free" as const }));
|
||||
const formatPortDiagnostics = vi.fn((_diagnostics: unknown) => [] as string[]);
|
||||
|
||||
const { runtimeLogs, runtimeErrors, defaultRuntime, resetRuntimeCapture } =
|
||||
createCliRuntimeCapture();
|
||||
const mocks = vi.hoisted(() => {
|
||||
const runtimeLogs: string[] = [];
|
||||
const runtimeErrors: string[] = [];
|
||||
const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" ");
|
||||
const defaultRuntime = {
|
||||
log: vi.fn((...args: unknown[]) => {
|
||||
runtimeLogs.push(stringifyArgs(args));
|
||||
}),
|
||||
error: vi.fn((...args: unknown[]) => {
|
||||
runtimeErrors.push(stringifyArgs(args));
|
||||
}),
|
||||
writeStdout: vi.fn((value: string) => {
|
||||
defaultRuntime.log(value.endsWith("\n") ? value.slice(0, -1) : value);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
defaultRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
}),
|
||||
};
|
||||
return { runtimeLogs, runtimeErrors, defaultRuntime };
|
||||
});
|
||||
|
||||
const { runtimeLogs, runtimeErrors, defaultRuntime } = mocks;
|
||||
|
||||
vi.mock(
|
||||
new URL("../../gateway/call.ts", new URL("./gateway-cli/call.ts", import.meta.url)).href,
|
||||
|
|
@ -53,7 +76,7 @@ vi.mock("../globals.js", () => ({
|
|||
|
||||
vi.mock("../runtime.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../runtime.js")>()),
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
vi.mock("./ports.js", () => ({
|
||||
|
|
@ -96,7 +119,6 @@ vi.mock("../infra/ports.js", () => ({
|
|||
formatPortDiagnostics: (diagnostics: unknown) => formatPortDiagnostics(diagnostics),
|
||||
}));
|
||||
|
||||
const { registerGatewayCli } = await import("./gateway-cli.js");
|
||||
let gatewayProgram: Command;
|
||||
|
||||
function createGatewayProgram() {
|
||||
|
|
@ -117,12 +139,18 @@ async function expectGatewayExit(args: string[]) {
|
|||
describe("gateway-cli coverage", () => {
|
||||
beforeEach(() => {
|
||||
gatewayProgram = createGatewayProgram();
|
||||
runtimeLogs.length = 0;
|
||||
runtimeErrors.length = 0;
|
||||
defaultRuntime.log.mockClear();
|
||||
defaultRuntime.error.mockClear();
|
||||
defaultRuntime.writeStdout.mockClear();
|
||||
defaultRuntime.writeJson.mockClear();
|
||||
defaultRuntime.exit.mockClear();
|
||||
inspectPortUsage.mockClear();
|
||||
formatPortDiagnostics.mockClear();
|
||||
});
|
||||
|
||||
it("registers call/health commands and routes to callGateway", async () => {
|
||||
resetRuntimeCapture();
|
||||
callGateway.mockClear();
|
||||
|
||||
await runGatewayCommand(["gateway", "call", "health", "--params", '{"x":1}', "--json"]);
|
||||
|
|
@ -132,7 +160,6 @@ describe("gateway-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("registers gateway probe and routes to gatewayStatusCommand", async () => {
|
||||
resetRuntimeCapture();
|
||||
gatewayStatusCommand.mockClear();
|
||||
|
||||
await runGatewayCommand(["gateway", "probe", "--json"]);
|
||||
|
|
@ -141,7 +168,6 @@ describe("gateway-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("registers gateway discover and prints json output", async () => {
|
||||
resetRuntimeCapture();
|
||||
discoverGatewayBeacons.mockClear();
|
||||
discoverGatewayBeacons.mockResolvedValueOnce([
|
||||
{
|
||||
|
|
@ -166,7 +192,6 @@ describe("gateway-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("validates gateway discover timeout", async () => {
|
||||
resetRuntimeCapture();
|
||||
discoverGatewayBeacons.mockClear();
|
||||
await expectGatewayExit(["gateway", "discover", "--timeout", "0"]);
|
||||
|
||||
|
|
@ -175,7 +200,6 @@ describe("gateway-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("fails gateway call on invalid params JSON", async () => {
|
||||
resetRuntimeCapture();
|
||||
callGateway.mockClear();
|
||||
await expectGatewayExit(["gateway", "call", "status", "--params", "not-json"]);
|
||||
|
||||
|
|
@ -184,8 +208,6 @@ describe("gateway-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("validates gateway ports and handles force/start errors", async () => {
|
||||
resetRuntimeCapture();
|
||||
|
||||
// Invalid port
|
||||
await expectGatewayExit(["gateway", "--port", "0", "--token", "test-token"]);
|
||||
|
||||
|
|
@ -243,7 +265,6 @@ describe("gateway-cli coverage", () => {
|
|||
OPENCLAW_SERVICE_KIND: undefined,
|
||||
},
|
||||
async () => {
|
||||
resetRuntimeCapture();
|
||||
serviceIsLoaded.mockResolvedValue(true);
|
||||
startGatewayServer.mockRejectedValueOnce(
|
||||
new GatewayLockError("another gateway instance is already listening"),
|
||||
|
|
@ -260,7 +281,8 @@ describe("gateway-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("keeps exit 1 for gateway bind failures wrapped as GatewayLockError", async () => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
runtimeErrors.length = 0;
|
||||
serviceIsLoaded.mockResolvedValue(true);
|
||||
startGatewayServer.mockRejectedValueOnce(
|
||||
new GatewayLockError("failed to bind gateway socket on ws://127.0.0.1:18789: Error: boom"),
|
||||
|
|
@ -272,7 +294,8 @@ describe("gateway-cli coverage", () => {
|
|||
});
|
||||
|
||||
it("keeps exit 1 for gateway lock acquisition failures", async () => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
runtimeErrors.length = 0;
|
||||
serviceIsLoaded.mockResolvedValue(true);
|
||||
startGatewayServer.mockRejectedValueOnce(
|
||||
new GatewayLockError("failed to acquire gateway lock at /tmp/openclaw/gateway.lock"),
|
||||
|
|
@ -285,7 +308,8 @@ describe("gateway-cli coverage", () => {
|
|||
|
||||
it("uses env/config port when --port is omitted", async () => {
|
||||
await withEnvOverride({ OPENCLAW_GATEWAY_PORT: "19001" }, async () => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
runtimeErrors.length = 0;
|
||||
startGatewayServer.mockClear();
|
||||
|
||||
startGatewayServer.mockRejectedValueOnce(new Error("nope"));
|
||||
|
|
|
|||
|
|
@ -1,13 +1,22 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "../test-runtime-capture.js";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerGatewayCli } from "./register.js";
|
||||
|
||||
const callGatewayCli = vi.fn(async (_method: string, _opts: unknown, _params?: unknown) => ({
|
||||
ok: true,
|
||||
const mocks = vi.hoisted(() => ({
|
||||
callGatewayCli: vi.fn(async (_method: string, _opts: unknown, _params?: unknown) => ({
|
||||
ok: true,
|
||||
})),
|
||||
gatewayStatusCommand: vi.fn(async (_opts: unknown, _runtime: unknown) => {}),
|
||||
defaultRuntime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
writeStdout: vi.fn(),
|
||||
writeJson: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
const gatewayStatusCommand = vi.fn(async (_opts: unknown, _runtime: unknown) => {});
|
||||
|
||||
const { defaultRuntime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const { callGatewayCli, gatewayStatusCommand, defaultRuntime } = mocks;
|
||||
|
||||
vi.mock("../cli-utils.js", () => ({
|
||||
runCommandWithRuntime: async (
|
||||
|
|
@ -25,11 +34,12 @@ vi.mock("../cli-utils.js", () => ({
|
|||
|
||||
vi.mock("../../runtime.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../../runtime.js")>()),
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/gateway-status.js", () => ({
|
||||
gatewayStatusCommand: (opts: unknown, runtime: unknown) => gatewayStatusCommand(opts, runtime),
|
||||
gatewayStatusCommand: (opts: unknown, runtime: unknown) =>
|
||||
mocks.gatewayStatusCommand(opts, runtime),
|
||||
}));
|
||||
|
||||
vi.mock("./call.js", () => ({
|
||||
|
|
@ -42,7 +52,7 @@ vi.mock("./call.js", () => ({
|
|||
.option("--expect-final", "Wait for final response (agent)", false)
|
||||
.option("--json", "Output JSON", false),
|
||||
callGatewayCli: (method: string, opts: unknown, params?: unknown) =>
|
||||
callGatewayCli(method, opts, params),
|
||||
mocks.callGatewayCli(method, opts, params),
|
||||
}));
|
||||
|
||||
vi.mock("./run.js", () => ({
|
||||
|
|
@ -113,20 +123,21 @@ vi.mock("./discover.js", () => ({
|
|||
}));
|
||||
|
||||
describe("gateway register option collisions", () => {
|
||||
let registerGatewayCli: typeof import("./register.js").registerGatewayCli;
|
||||
let sharedProgram: Command;
|
||||
let sharedProgram: Command = new Command();
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerGatewayCli } = await import("./register.js"));
|
||||
sharedProgram = new Command();
|
||||
if (sharedProgram.commands.length === 0) {
|
||||
sharedProgram.exitOverride();
|
||||
registerGatewayCli(sharedProgram);
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
resetRuntimeCapture();
|
||||
callGatewayCli.mockClear();
|
||||
gatewayStatusCommand.mockClear();
|
||||
defaultRuntime.log.mockClear();
|
||||
defaultRuntime.error.mockClear();
|
||||
defaultRuntime.writeStdout.mockClear();
|
||||
defaultRuntime.writeJson.mockClear();
|
||||
defaultRuntime.exit.mockClear();
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { runRegisteredCli } from "../test-utils/command-runner.js";
|
||||
import { formatLogTimestamp } from "./logs-cli.js";
|
||||
import { formatLogTimestamp, registerLogsCli } from "./logs-cli.js";
|
||||
|
||||
const callGatewayFromCli = vi.fn();
|
||||
|
||||
|
|
@ -12,12 +12,6 @@ vi.mock("./gateway-rpc.js", async () => {
|
|||
};
|
||||
});
|
||||
|
||||
let registerLogsCli: typeof import("./logs-cli.js").registerLogsCli;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerLogsCli } = await import("./logs-cli.js"));
|
||||
});
|
||||
|
||||
async function runLogsCli(argv: string[]) {
|
||||
await runRegisteredCli({
|
||||
register: registerLogsCli as (program: import("commander").Command) => void,
|
||||
|
|
|
|||
|
|
@ -2,21 +2,38 @@ import fs from "node:fs/promises";
|
|||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { Command } from "commander";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome } from "../config/home-env.test-harness.js";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { registerMcpCli } from "./mcp-cli.js";
|
||||
|
||||
const { defaultRuntime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const mocks = vi.hoisted(() => {
|
||||
const runtime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
runtime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
};
|
||||
return {
|
||||
runtime,
|
||||
serveOpenClawChannelMcp: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const defaultRuntime = mocks.runtime;
|
||||
const mockLog = defaultRuntime.log;
|
||||
const mockError = defaultRuntime.error;
|
||||
const serveOpenClawChannelMcp = vi.fn();
|
||||
const serveOpenClawChannelMcp = mocks.serveOpenClawChannelMcp;
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.runtime,
|
||||
}));
|
||||
|
||||
vi.mock("../mcp/channel-server.js", () => ({
|
||||
serveOpenClawChannelMcp,
|
||||
serveOpenClawChannelMcp: mocks.serveOpenClawChannelMcp,
|
||||
}));
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
|
@ -27,7 +44,6 @@ async function createWorkspace(): Promise<string> {
|
|||
return dir;
|
||||
}
|
||||
|
||||
let registerMcpCli: typeof import("./mcp-cli.js").registerMcpCli;
|
||||
let sharedProgram: Command;
|
||||
|
||||
async function runMcpCommand(args: string[]) {
|
||||
|
|
@ -35,16 +51,14 @@ async function runMcpCommand(args: string[]) {
|
|||
}
|
||||
|
||||
describe("mcp cli", () => {
|
||||
beforeAll(async () => {
|
||||
({ registerMcpCli } = await import("./mcp-cli.js"));
|
||||
if (!sharedProgram) {
|
||||
sharedProgram = new Command();
|
||||
sharedProgram.exitOverride();
|
||||
registerMcpCli(sharedProgram);
|
||||
}, 300_000);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
resetRuntimeCapture();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
|
|
|||
|
|
@ -1,45 +1,43 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { runRegisteredCli } from "../test-utils/command-runner.js";
|
||||
import { registerModelsCli } from "./models-cli.js";
|
||||
|
||||
const modelsStatusCommand = vi.fn().mockResolvedValue(undefined);
|
||||
const noopAsync = vi.fn(async () => undefined);
|
||||
const modelsAuthLoginCommand = vi.fn().mockResolvedValue(undefined);
|
||||
const mocks = vi.hoisted(() => ({
|
||||
modelsStatusCommand: vi.fn().mockResolvedValue(undefined),
|
||||
noopAsync: vi.fn(async () => undefined),
|
||||
modelsAuthLoginCommand: vi.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
const { modelsStatusCommand, modelsAuthLoginCommand } = mocks;
|
||||
|
||||
vi.mock("../commands/models.js", () => ({
|
||||
modelsStatusCommand,
|
||||
modelsAliasesAddCommand: noopAsync,
|
||||
modelsAliasesListCommand: noopAsync,
|
||||
modelsAliasesRemoveCommand: noopAsync,
|
||||
modelsAuthAddCommand: noopAsync,
|
||||
modelsAuthLoginCommand,
|
||||
modelsAuthOrderClearCommand: noopAsync,
|
||||
modelsAuthOrderGetCommand: noopAsync,
|
||||
modelsAuthOrderSetCommand: noopAsync,
|
||||
modelsAuthPasteTokenCommand: noopAsync,
|
||||
modelsAuthSetupTokenCommand: noopAsync,
|
||||
modelsFallbacksAddCommand: noopAsync,
|
||||
modelsFallbacksClearCommand: noopAsync,
|
||||
modelsFallbacksListCommand: noopAsync,
|
||||
modelsFallbacksRemoveCommand: noopAsync,
|
||||
modelsImageFallbacksAddCommand: noopAsync,
|
||||
modelsImageFallbacksClearCommand: noopAsync,
|
||||
modelsImageFallbacksListCommand: noopAsync,
|
||||
modelsImageFallbacksRemoveCommand: noopAsync,
|
||||
modelsListCommand: noopAsync,
|
||||
modelsScanCommand: noopAsync,
|
||||
modelsSetCommand: noopAsync,
|
||||
modelsSetImageCommand: noopAsync,
|
||||
modelsStatusCommand: mocks.modelsStatusCommand,
|
||||
modelsAliasesAddCommand: mocks.noopAsync,
|
||||
modelsAliasesListCommand: mocks.noopAsync,
|
||||
modelsAliasesRemoveCommand: mocks.noopAsync,
|
||||
modelsAuthAddCommand: mocks.noopAsync,
|
||||
modelsAuthLoginCommand: mocks.modelsAuthLoginCommand,
|
||||
modelsAuthOrderClearCommand: mocks.noopAsync,
|
||||
modelsAuthOrderGetCommand: mocks.noopAsync,
|
||||
modelsAuthOrderSetCommand: mocks.noopAsync,
|
||||
modelsAuthPasteTokenCommand: mocks.noopAsync,
|
||||
modelsAuthSetupTokenCommand: mocks.noopAsync,
|
||||
modelsFallbacksAddCommand: mocks.noopAsync,
|
||||
modelsFallbacksClearCommand: mocks.noopAsync,
|
||||
modelsFallbacksListCommand: mocks.noopAsync,
|
||||
modelsFallbacksRemoveCommand: mocks.noopAsync,
|
||||
modelsImageFallbacksAddCommand: mocks.noopAsync,
|
||||
modelsImageFallbacksClearCommand: mocks.noopAsync,
|
||||
modelsImageFallbacksListCommand: mocks.noopAsync,
|
||||
modelsImageFallbacksRemoveCommand: mocks.noopAsync,
|
||||
modelsListCommand: mocks.noopAsync,
|
||||
modelsScanCommand: mocks.noopAsync,
|
||||
modelsSetCommand: mocks.noopAsync,
|
||||
modelsSetImageCommand: mocks.noopAsync,
|
||||
}));
|
||||
|
||||
describe("models cli", () => {
|
||||
let registerModelsCli: (typeof import("./models-cli.js"))["registerModelsCli"];
|
||||
|
||||
beforeAll(async () => {
|
||||
// Load once; vi.mock above ensures command handlers are already mocked.
|
||||
({ registerModelsCli } = await import("./models-cli.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
modelsAuthLoginCommand.mockClear();
|
||||
modelsStatusCommand.mockClear();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as fs from "node:fs/promises";
|
||||
import * as path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
readFileUtf8AndCleanup,
|
||||
stubFetchResponse,
|
||||
|
|
@ -35,9 +35,7 @@ async function withCameraTempDir<T>(run: (dir: string) => Promise<T>): Promise<T
|
|||
}
|
||||
|
||||
describe("nodes camera helpers", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
beforeAll(async () => {
|
||||
({
|
||||
cameraTempPath,
|
||||
parseCameraClipPayload,
|
||||
|
|
@ -49,6 +47,10 @@ describe("nodes camera helpers", () => {
|
|||
({ parseScreenRecordPayload, screenRecordTempPath } = await import("./nodes-screen.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("parses camera.snap payload", () => {
|
||||
expect(
|
||||
parseCameraSnapPayload({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerNodesCli } from "./nodes-cli.js";
|
||||
|
||||
type NodeInvokeCall = {
|
||||
method?: string;
|
||||
|
|
@ -46,7 +46,31 @@ const callGateway = vi.fn(async (opts: NodeInvokeCall) => {
|
|||
|
||||
const randomIdempotencyKey = vi.fn(() => "rk_test");
|
||||
|
||||
const { runtimeErrors, defaultRuntime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const mocks = vi.hoisted(() => {
|
||||
const runtimeErrors: string[] = [];
|
||||
const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" ");
|
||||
const defaultRuntime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn((...args: unknown[]) => {
|
||||
runtimeErrors.push(stringifyArgs(args));
|
||||
}),
|
||||
writeStdout: vi.fn((value: string) => {
|
||||
defaultRuntime.log(value.endsWith("\n") ? value.slice(0, -1) : value);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
defaultRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
}),
|
||||
};
|
||||
return {
|
||||
runtimeErrors,
|
||||
defaultRuntime,
|
||||
};
|
||||
});
|
||||
|
||||
const { runtimeErrors, defaultRuntime } = mocks;
|
||||
|
||||
vi.mock("../gateway/call.js", () => ({
|
||||
callGateway: (opts: unknown) => callGateway(opts as NodeInvokeCall),
|
||||
|
|
@ -55,12 +79,11 @@ vi.mock("../gateway/call.js", () => ({
|
|||
|
||||
vi.mock("../runtime.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../runtime.js")>()),
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
describe("nodes-cli coverage", () => {
|
||||
let registerNodesCli: (program: Command) => void;
|
||||
let sharedProgram: Command;
|
||||
let sharedProgram: Command = new Command();
|
||||
|
||||
const getNodeInvokeCall = () => {
|
||||
const last = lastNodeInvokeCall;
|
||||
|
|
@ -75,17 +98,20 @@ describe("nodes-cli coverage", () => {
|
|||
return getNodeInvokeCall();
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerNodesCli } = await import("./nodes-cli.js"));
|
||||
sharedProgram = new Command();
|
||||
if (sharedProgram.commands.length === 0) {
|
||||
sharedProgram.exitOverride();
|
||||
registerNodesCli(sharedProgram);
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
resetRuntimeCapture();
|
||||
runtimeErrors.length = 0;
|
||||
callGateway.mockClear();
|
||||
randomIdempotencyKey.mockClear();
|
||||
defaultRuntime.log.mockClear();
|
||||
defaultRuntime.error.mockClear();
|
||||
defaultRuntime.writeStdout.mockClear();
|
||||
defaultRuntime.writeJson.mockClear();
|
||||
defaultRuntime.exit.mockClear();
|
||||
lastNodeInvokeCall = null;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { DEFAULT_EXEC_APPROVAL_TIMEOUT_MS } from "../../infra/exec-approvals.js";
|
||||
import { parseTimeoutMs } from "../parse-timeout.js";
|
||||
import { callGatewayCli } from "./rpc.js";
|
||||
|
||||
/**
|
||||
* Regression test for #12098:
|
||||
|
|
@ -18,9 +19,11 @@ import { parseTimeoutMs } from "../parse-timeout.js";
|
|||
* least approvalTimeoutMs + 10_000.
|
||||
*/
|
||||
|
||||
const callGatewaySpy = vi.fn<
|
||||
(opts: Record<string, unknown>) => Promise<{ decision: "allow-once" }>
|
||||
>(async () => ({ decision: "allow-once" }));
|
||||
const { callGatewaySpy } = vi.hoisted(() => ({
|
||||
callGatewaySpy: vi.fn<(opts: Record<string, unknown>) => Promise<{ decision: "allow-once" }>>(
|
||||
async () => ({ decision: "allow-once" }),
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock("../../gateway/call.js", () => ({
|
||||
callGateway: callGatewaySpy,
|
||||
|
|
@ -32,13 +35,8 @@ vi.mock("../progress.js", () => ({
|
|||
}));
|
||||
|
||||
describe("exec approval transport timeout (#12098)", () => {
|
||||
let callGatewayCli: typeof import("./rpc.js").callGatewayCli;
|
||||
const approvalTransportFloorMs = DEFAULT_EXEC_APPROVAL_TIMEOUT_MS + 10_000;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ callGatewayCli } = await import("./rpc.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
callGatewaySpy.mockClear();
|
||||
callGatewaySpy.mockResolvedValue({ decision: "allow-once" });
|
||||
|
|
|
|||
|
|
@ -1,43 +1,56 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerPairingCli } from "./pairing-cli.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
listChannelPairingRequests: vi.fn(),
|
||||
approveChannelPairingCode: vi.fn(),
|
||||
notifyPairingApproved: vi.fn(),
|
||||
normalizeChannelId: vi.fn((raw: string) => {
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
if (raw === "imsg") {
|
||||
return "imessage";
|
||||
}
|
||||
if (["telegram", "discord", "imessage"].includes(raw)) {
|
||||
return raw;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
getPairingAdapter: vi.fn((channel: string) => ({
|
||||
idLabel: pairingIdLabels[channel] ?? "userId",
|
||||
})),
|
||||
listPairingChannels: vi.fn(() => ["telegram", "discord", "imessage"]),
|
||||
}));
|
||||
|
||||
const {
|
||||
listChannelPairingRequests,
|
||||
approveChannelPairingCode,
|
||||
notifyPairingApproved,
|
||||
normalizeChannelId,
|
||||
getPairingAdapter,
|
||||
listPairingChannels,
|
||||
} = mocks;
|
||||
|
||||
const listChannelPairingRequests = vi.fn();
|
||||
const approveChannelPairingCode = vi.fn();
|
||||
const notifyPairingApproved = vi.fn();
|
||||
const pairingIdLabels: Record<string, string> = {
|
||||
telegram: "telegramUserId",
|
||||
discord: "discordUserId",
|
||||
};
|
||||
const normalizeChannelId = vi.fn((raw: string) => {
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
if (raw === "imsg") {
|
||||
return "imessage";
|
||||
}
|
||||
if (["telegram", "discord", "imessage"].includes(raw)) {
|
||||
return raw;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
const getPairingAdapter = vi.fn((channel: string) => ({
|
||||
idLabel: pairingIdLabels[channel] ?? "userId",
|
||||
}));
|
||||
const listPairingChannels = vi.fn(() => ["telegram", "discord", "imessage"]);
|
||||
|
||||
vi.mock("../pairing/pairing-store.js", () => ({
|
||||
listChannelPairingRequests,
|
||||
approveChannelPairingCode,
|
||||
listChannelPairingRequests: mocks.listChannelPairingRequests,
|
||||
approveChannelPairingCode: mocks.approveChannelPairingCode,
|
||||
}));
|
||||
|
||||
vi.mock("../channels/plugins/pairing.js", () => ({
|
||||
listPairingChannels,
|
||||
notifyPairingApproved,
|
||||
getPairingAdapter,
|
||||
listPairingChannels: mocks.listPairingChannels,
|
||||
notifyPairingApproved: mocks.notifyPairingApproved,
|
||||
getPairingAdapter: mocks.getPairingAdapter,
|
||||
}));
|
||||
|
||||
vi.mock("../channels/plugins/index.js", () => ({
|
||||
normalizeChannelId,
|
||||
normalizeChannelId: mocks.normalizeChannelId,
|
||||
}));
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
|
|
@ -45,13 +58,6 @@ vi.mock("../config/config.js", () => ({
|
|||
}));
|
||||
|
||||
describe("pairing cli", () => {
|
||||
let registerPairingCli: typeof import("./pairing-cli.js").registerPairingCli;
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ registerPairingCli } = await import("./pairing-cli.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
listChannelPairingRequests.mockClear();
|
||||
listChannelPairingRequests.mockResolvedValue([]);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { __testing, ensurePluginRegistryLoaded } from "./plugin-registry.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
applyPluginAutoEnable: vi.fn(),
|
||||
|
|
@ -37,8 +38,8 @@ vi.mock("../plugins/runtime.js", () => ({
|
|||
|
||||
describe("ensurePluginRegistryLoaded", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
__testing.resetPluginRegistryLoadedForTests();
|
||||
mocks.getActivePluginRegistry.mockReturnValue({
|
||||
plugins: [],
|
||||
channels: [],
|
||||
|
|
@ -73,8 +74,6 @@ describe("ensurePluginRegistryLoaded", () => {
|
|||
diagnostics: [],
|
||||
});
|
||||
|
||||
const { ensurePluginRegistryLoaded } = await import("./plugin-registry.js");
|
||||
|
||||
ensurePluginRegistryLoaded({ scope: "configured-channels" });
|
||||
|
||||
expect(mocks.applyPluginAutoEnable).toHaveBeenCalledWith({
|
||||
|
|
@ -127,8 +126,6 @@ describe("ensurePluginRegistryLoaded", () => {
|
|||
tools: [],
|
||||
});
|
||||
|
||||
const { ensurePluginRegistryLoaded } = await import("./plugin-registry.js");
|
||||
|
||||
ensurePluginRegistryLoaded({ scope: "configured-channels" });
|
||||
ensurePluginRegistryLoaded({ scope: "channels" });
|
||||
|
||||
|
|
@ -160,8 +157,6 @@ describe("ensurePluginRegistryLoaded", () => {
|
|||
tools: [],
|
||||
});
|
||||
|
||||
const { ensurePluginRegistryLoaded } = await import("./plugin-registry.js");
|
||||
|
||||
ensurePluginRegistryLoaded({ scope: "all" });
|
||||
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -188,8 +183,6 @@ describe("ensurePluginRegistryLoaded", () => {
|
|||
tools: [{ pluginId: "demo-tool" }],
|
||||
});
|
||||
|
||||
const { ensurePluginRegistryLoaded } = await import("./plugin-registry.js");
|
||||
|
||||
ensurePluginRegistryLoaded({ scope: "configured-channels" });
|
||||
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenCalledTimes(1);
|
||||
|
|
|
|||
|
|
@ -107,3 +107,9 @@ export function ensurePluginRegistryLoaded(options?: { scope?: PluginRegistrySco
|
|||
});
|
||||
pluginRegistryLoaded = scope;
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
resetPluginRegistryLoadedForTests(): void {
|
||||
pluginRegistryLoaded = "none";
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,10 +2,17 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
|||
import { bundledPluginRootAt, repoInstallSpec } from "../../test/helpers/bundled-plugin-paths.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { ConfigFileSnapshot } from "../config/types.openclaw.js";
|
||||
import { loadConfigForInstall } from "./plugins-install-command.js";
|
||||
|
||||
const loadConfigMock = vi.fn<() => OpenClawConfig>();
|
||||
const readConfigFileSnapshotMock = vi.fn<() => Promise<ConfigFileSnapshot>>();
|
||||
const cleanStaleMatrixPluginConfigMock = vi.fn();
|
||||
const hoisted = vi.hoisted(() => ({
|
||||
loadConfigMock: vi.fn<() => OpenClawConfig>(),
|
||||
readConfigFileSnapshotMock: vi.fn<() => Promise<ConfigFileSnapshot>>(),
|
||||
cleanStaleMatrixPluginConfigMock: vi.fn(),
|
||||
}));
|
||||
|
||||
const loadConfigMock = hoisted.loadConfigMock;
|
||||
const readConfigFileSnapshotMock = hoisted.readConfigFileSnapshotMock;
|
||||
const cleanStaleMatrixPluginConfigMock = hoisted.cleanStaleMatrixPluginConfigMock;
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
loadConfig: () => loadConfigMock(),
|
||||
|
|
@ -16,7 +23,6 @@ vi.mock("../commands/doctor/providers/matrix.js", () => ({
|
|||
cleanStaleMatrixPluginConfig: (cfg: OpenClawConfig) => cleanStaleMatrixPluginConfigMock(cfg),
|
||||
}));
|
||||
|
||||
const { loadConfigForInstall } = await import("./plugins-install-command.js");
|
||||
const MATRIX_REPO_INSTALL_SPEC = repoInstallSpec("matrix");
|
||||
|
||||
function makeSnapshot(overrides: Partial<ConfigFileSnapshot> = {}): ConfigFileSnapshot {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerNodesCli } from "./nodes-cli.js";
|
||||
import { createIosNodeListResponse } from "./program.nodes-test-helpers.js";
|
||||
import { callGateway, installBaseProgramMocks, runtime } from "./program.test-mocks.js";
|
||||
|
||||
installBaseProgramMocks();
|
||||
let registerNodesCli: (program: Command) => void;
|
||||
|
||||
function formatRuntimeLogCallArg(value: unknown): string {
|
||||
if (typeof value === "string") {
|
||||
|
|
@ -26,12 +26,12 @@ function formatRuntimeLogCallArg(value: unknown): string {
|
|||
describe("cli program (nodes basics)", () => {
|
||||
let program: Command;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerNodesCli } = await import("./nodes-cli.js"));
|
||||
program = new Command();
|
||||
program.exitOverride();
|
||||
registerNodesCli(program);
|
||||
});
|
||||
function createProgram() {
|
||||
const next = new Command();
|
||||
next.exitOverride();
|
||||
registerNodesCli(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
async function runProgram(argv: string[]) {
|
||||
runtime.log.mockClear();
|
||||
|
|
@ -57,6 +57,7 @@ describe("cli program (nodes basics)", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
program = createProgram();
|
||||
});
|
||||
|
||||
it("runs nodes list --connected and filters to connected nodes", async () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { buildProgram } from "./program.js";
|
||||
import {
|
||||
configureCommand,
|
||||
ensureConfigReady,
|
||||
|
|
@ -23,8 +24,6 @@ vi.mock("./config-cli.js", () => ({
|
|||
runConfigUnset: vi.fn(),
|
||||
}));
|
||||
|
||||
const { buildProgram } = await import("./program.js");
|
||||
|
||||
describe("cli program (smoke)", () => {
|
||||
let program = createProgram();
|
||||
|
||||
|
|
@ -36,11 +35,8 @@ describe("cli program (smoke)", () => {
|
|||
await program.parseAsync(argv, { from: "user" });
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
program = createProgram();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
program = createProgram();
|
||||
vi.clearAllMocks();
|
||||
runTui.mockResolvedValue(undefined);
|
||||
ensureConfigReady.mockResolvedValue(undefined);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { reparseProgramFromActionArgs } from "./action-reparse.js";
|
||||
|
||||
const buildParseArgvMock = vi.fn();
|
||||
const resolveActionArgsMock = vi.fn();
|
||||
const buildParseArgvMock = vi.hoisted(() => vi.fn());
|
||||
const resolveActionArgsMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../argv.js", () => ({
|
||||
buildParseArgv: buildParseArgvMock,
|
||||
|
|
@ -12,8 +13,6 @@ vi.mock("./helpers.js", () => ({
|
|||
resolveActionArgs: resolveActionArgsMock,
|
||||
}));
|
||||
|
||||
const { reparseProgramFromActionArgs } = await import("./action-reparse.js");
|
||||
|
||||
describe("reparseProgramFromActionArgs", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import process from "node:process";
|
||||
import { Command } from "commander";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { buildProgram } from "./build-program.js";
|
||||
import type { ProgramContext } from "./context.js";
|
||||
|
||||
const registerProgramCommandsMock = vi.fn();
|
||||
const createProgramContextMock = vi.fn();
|
||||
const configureProgramHelpMock = vi.fn();
|
||||
const registerPreActionHooksMock = vi.fn();
|
||||
const setProgramContextMock = vi.fn();
|
||||
const registerProgramCommandsMock = vi.hoisted(() => vi.fn());
|
||||
const createProgramContextMock = vi.hoisted(() => vi.fn());
|
||||
const configureProgramHelpMock = vi.hoisted(() => vi.fn());
|
||||
const registerPreActionHooksMock = vi.hoisted(() => vi.fn());
|
||||
const setProgramContextMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("./command-registry.js", () => ({
|
||||
registerProgramCommands: registerProgramCommandsMock,
|
||||
|
|
@ -29,8 +30,6 @@ vi.mock("./program-context.js", () => ({
|
|||
setProgramContext: setProgramContextMock,
|
||||
}));
|
||||
|
||||
const { buildProgram } = await import("./build-program.js");
|
||||
|
||||
describe("buildProgram", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import process from "node:process";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { buildProgram } = await import("./build-program.js");
|
||||
import { buildProgram } from "./build-program.js";
|
||||
|
||||
describe("buildProgram version alias handling", () => {
|
||||
let originalArgv: string[];
|
||||
|
|
|
|||
|
|
@ -27,13 +27,6 @@ vi.mock("./register.maintenance.js", () => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const {
|
||||
getCoreCliCommandNames,
|
||||
getCoreCliCommandsWithSubcommands,
|
||||
registerCoreCliByName,
|
||||
registerCoreCliCommands,
|
||||
} = await import("./command-registry.js");
|
||||
|
||||
vi.mock("./register.status-health-sessions.js", () => ({
|
||||
registerStatusHealthSessionsCommands: (program: Command) => {
|
||||
program.command("status");
|
||||
|
|
@ -44,6 +37,13 @@ vi.mock("./register.status-health-sessions.js", () => ({
|
|||
},
|
||||
}));
|
||||
|
||||
import {
|
||||
getCoreCliCommandNames,
|
||||
getCoreCliCommandsWithSubcommands,
|
||||
registerCoreCliByName,
|
||||
registerCoreCliCommands,
|
||||
} from "./command-registry.js";
|
||||
|
||||
const testProgramContext: ProgramContext = {
|
||||
programVersion: "0.0.0-test",
|
||||
channelOptions: [],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { RuntimeEnv } from "../../runtime.js";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { ensureConfigReady, __test__ } from "./config-guard.js";
|
||||
|
||||
const loadAndMaybeMigrateDoctorConfigMock = vi.hoisted(() => vi.fn());
|
||||
const readConfigFileSnapshotMock = vi.hoisted(() => vi.fn());
|
||||
|
|
@ -12,8 +12,6 @@ vi.mock("../../config/config.js", () => ({
|
|||
readConfigFileSnapshot: readConfigFileSnapshotMock,
|
||||
}));
|
||||
|
||||
const mockedModuleIds = ["../../commands/doctor-config-preflight.js", "../../config/config.js"];
|
||||
|
||||
function makeSnapshot() {
|
||||
return {
|
||||
exists: false,
|
||||
|
|
@ -46,13 +44,7 @@ async function withCapturedStdout(run: () => Promise<void>): Promise<string> {
|
|||
}
|
||||
|
||||
describe("ensureConfigReady", () => {
|
||||
let ensureConfigReady: (params: {
|
||||
runtime: RuntimeEnv;
|
||||
commandPath?: string[];
|
||||
suppressDoctorStdout?: boolean;
|
||||
allowInvalid?: boolean;
|
||||
}) => Promise<void>;
|
||||
let resetConfigGuardStateForTests: () => void;
|
||||
const resetConfigGuardStateForTests = __test__.resetConfigGuardStateForTests;
|
||||
|
||||
async function runEnsureConfigReady(commandPath: string[], suppressDoctorStdout = false) {
|
||||
const runtime = makeRuntime();
|
||||
|
|
@ -75,20 +67,6 @@ describe("ensureConfigReady", () => {
|
|||
});
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
({
|
||||
ensureConfigReady,
|
||||
__test__: { resetConfigGuardStateForTests },
|
||||
} = await import("./config-guard.js"));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
resetConfigGuardStateForTests();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createProgramContext } from "./context.js";
|
||||
|
||||
const resolveCliChannelOptionsMock = vi.fn(() => ["telegram", "whatsapp"]);
|
||||
const resolveCliChannelOptionsMock = vi.hoisted(() => vi.fn(() => ["telegram", "whatsapp"]));
|
||||
|
||||
vi.mock("../../version.js", () => ({
|
||||
VERSION: "9.9.9-test",
|
||||
|
|
@ -10,8 +11,6 @@ vi.mock("../channel-options.js", () => ({
|
|||
resolveCliChannelOptions: resolveCliChannelOptionsMock,
|
||||
}));
|
||||
|
||||
const { createProgramContext } = await import("./context.js");
|
||||
|
||||
describe("createProgramContext", () => {
|
||||
it("builds program context from version and resolved channel options", () => {
|
||||
resolveCliChannelOptionsMock.mockClear().mockReturnValue(["telegram", "whatsapp"]);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
import { Command } from "commander";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ProgramContext } from "./context.js";
|
||||
import { configureProgramHelp } from "./help.js";
|
||||
|
||||
const hasEmittedCliBannerMock = vi.fn(() => false);
|
||||
const formatCliBannerLineMock = vi.fn(() => "BANNER-LINE");
|
||||
const formatDocsLinkMock = vi.fn((_path: string, full: string) => `https://${full}`);
|
||||
const resolveCommitHashMock = vi.fn<() => string | null>(() => "abc1234");
|
||||
const hasEmittedCliBannerMock = vi.hoisted(() => vi.fn(() => false));
|
||||
const formatCliBannerLineMock = vi.hoisted(() => vi.fn(() => "BANNER-LINE"));
|
||||
const formatDocsLinkMock = vi.hoisted(() =>
|
||||
vi.fn((_path: string, full: string) => `https://${full}`),
|
||||
);
|
||||
const resolveCommitHashMock = vi.hoisted(() => vi.fn<() => string | null>(() => "abc1234"));
|
||||
|
||||
vi.mock("../../terminal/links.js", () => ({
|
||||
formatDocsLink: formatDocsLinkMock,
|
||||
|
|
@ -44,8 +47,6 @@ vi.mock("./register.subclis.js", () => ({
|
|||
getSubCliCommandsWithSubcommands: () => ["gateway"],
|
||||
}));
|
||||
|
||||
const { configureProgramHelp } = await import("./help.js");
|
||||
|
||||
const testProgramContext: ProgramContext = {
|
||||
programVersion: "9.9.9-test",
|
||||
channelOptions: ["telegram"],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Command } from "commander";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { repoInstallSpec } from "../../../test/helpers/bundled-plugin-paths.js";
|
||||
import { loggingState } from "../../logging/state.js";
|
||||
import { setCommandJsonMode } from "./json-mode.js";
|
||||
|
|
@ -48,15 +48,6 @@ vi.mock("../plugin-registry.js", () => ({
|
|||
ensurePluginRegistryLoaded: ensurePluginRegistryLoadedMock,
|
||||
}));
|
||||
|
||||
const mockedModuleIds = [
|
||||
"../../globals.js",
|
||||
"../../runtime.js",
|
||||
"../banner.js",
|
||||
"../cli-name.js",
|
||||
"./config-guard.js",
|
||||
"../plugin-registry.js",
|
||||
];
|
||||
|
||||
let registerPreActionHooks: typeof import("./preaction.js").registerPreActionHooks;
|
||||
let originalProcessArgv: string[];
|
||||
let originalProcessTitle: string;
|
||||
|
|
@ -70,13 +61,6 @@ beforeAll(async () => {
|
|||
({ registerPreActionHooks } = await import("./preaction.js"));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
originalProcessArgv = [...process.argv];
|
||||
|
|
|
|||
|
|
@ -1,67 +1,63 @@
|
|||
import { Command } from "commander";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "../test-runtime-capture.js";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerAgentCommands } from "./register.agent.js";
|
||||
|
||||
const agentCliCommandMock = vi.fn();
|
||||
const agentsAddCommandMock = vi.fn();
|
||||
const agentsBindingsCommandMock = vi.fn();
|
||||
const agentsBindCommandMock = vi.fn();
|
||||
const agentsDeleteCommandMock = vi.fn();
|
||||
const agentsListCommandMock = vi.fn();
|
||||
const agentsSetIdentityCommandMock = vi.fn();
|
||||
const agentsUnbindCommandMock = vi.fn();
|
||||
const setVerboseMock = vi.fn();
|
||||
const createDefaultDepsMock = vi.fn(() => ({ deps: true }));
|
||||
const mocks = vi.hoisted(() => ({
|
||||
agentCliCommandMock: vi.fn(),
|
||||
agentsAddCommandMock: vi.fn(),
|
||||
agentsBindingsCommandMock: vi.fn(),
|
||||
agentsBindCommandMock: vi.fn(),
|
||||
agentsDeleteCommandMock: vi.fn(),
|
||||
agentsListCommandMock: vi.fn(),
|
||||
agentsSetIdentityCommandMock: vi.fn(),
|
||||
agentsUnbindCommandMock: vi.fn(),
|
||||
setVerboseMock: vi.fn(),
|
||||
createDefaultDepsMock: vi.fn(() => ({ deps: true })),
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const { defaultRuntime: runtime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const agentCliCommandMock = mocks.agentCliCommandMock;
|
||||
const agentsAddCommandMock = mocks.agentsAddCommandMock;
|
||||
const agentsBindingsCommandMock = mocks.agentsBindingsCommandMock;
|
||||
const agentsBindCommandMock = mocks.agentsBindCommandMock;
|
||||
const agentsDeleteCommandMock = mocks.agentsDeleteCommandMock;
|
||||
const agentsListCommandMock = mocks.agentsListCommandMock;
|
||||
const agentsSetIdentityCommandMock = mocks.agentsSetIdentityCommandMock;
|
||||
const agentsUnbindCommandMock = mocks.agentsUnbindCommandMock;
|
||||
const setVerboseMock = mocks.setVerboseMock;
|
||||
const createDefaultDepsMock = mocks.createDefaultDepsMock;
|
||||
const runtime = mocks.runtime;
|
||||
|
||||
vi.mock("../../commands/agent-via-gateway.js", () => ({
|
||||
agentCliCommand: agentCliCommandMock,
|
||||
agentCliCommand: mocks.agentCliCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/agents.js", () => ({
|
||||
agentsAddCommand: agentsAddCommandMock,
|
||||
agentsBindingsCommand: agentsBindingsCommandMock,
|
||||
agentsBindCommand: agentsBindCommandMock,
|
||||
agentsDeleteCommand: agentsDeleteCommandMock,
|
||||
agentsListCommand: agentsListCommandMock,
|
||||
agentsSetIdentityCommand: agentsSetIdentityCommandMock,
|
||||
agentsUnbindCommand: agentsUnbindCommandMock,
|
||||
agentsAddCommand: mocks.agentsAddCommandMock,
|
||||
agentsBindingsCommand: mocks.agentsBindingsCommandMock,
|
||||
agentsBindCommand: mocks.agentsBindCommandMock,
|
||||
agentsDeleteCommand: mocks.agentsDeleteCommandMock,
|
||||
agentsListCommand: mocks.agentsListCommandMock,
|
||||
agentsSetIdentityCommand: mocks.agentsSetIdentityCommandMock,
|
||||
agentsUnbindCommand: mocks.agentsUnbindCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../globals.js", () => ({
|
||||
setVerbose: setVerboseMock,
|
||||
setVerbose: mocks.setVerboseMock,
|
||||
}));
|
||||
|
||||
vi.mock("../deps.js", () => ({
|
||||
createDefaultDeps: createDefaultDepsMock,
|
||||
createDefaultDeps: mocks.createDefaultDepsMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime: runtime,
|
||||
defaultRuntime: mocks.runtime,
|
||||
}));
|
||||
|
||||
const mockedModuleIds = [
|
||||
"../../commands/agent-via-gateway.js",
|
||||
"../../commands/agents.js",
|
||||
"../../globals.js",
|
||||
"../deps.js",
|
||||
"../../runtime.js",
|
||||
];
|
||||
|
||||
let registerAgentCommands: typeof import("./register.agent.js").registerAgentCommands;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerAgentCommands } = await import("./register.agent.js"));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
describe("registerAgentCommands", () => {
|
||||
async function runCli(args: string[]) {
|
||||
const program = new Command();
|
||||
|
|
@ -71,7 +67,6 @@ describe("registerAgentCommands", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
resetRuntimeCapture();
|
||||
runtime.exit.mockImplementation(() => {});
|
||||
agentCliCommandMock.mockResolvedValue(undefined);
|
||||
agentsAddCommandMock.mockResolvedValue(undefined);
|
||||
|
|
|
|||
|
|
@ -1,43 +1,33 @@
|
|||
import { Command } from "commander";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "../test-runtime-capture.js";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerBackupCommand } from "./register.backup.js";
|
||||
|
||||
const backupCreateCommand = vi.fn();
|
||||
const backupVerifyCommand = vi.fn();
|
||||
const mocks = vi.hoisted(() => ({
|
||||
backupCreateCommand: vi.fn(),
|
||||
backupVerifyCommand: vi.fn(),
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const { defaultRuntime: runtime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const backupCreateCommand = mocks.backupCreateCommand;
|
||||
const backupVerifyCommand = mocks.backupVerifyCommand;
|
||||
const runtime = mocks.runtime;
|
||||
|
||||
vi.mock("../../commands/backup.js", () => ({
|
||||
backupCreateCommand,
|
||||
backupCreateCommand: mocks.backupCreateCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/backup-verify.js", () => ({
|
||||
backupVerifyCommand,
|
||||
backupVerifyCommand: mocks.backupVerifyCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime: runtime,
|
||||
defaultRuntime: mocks.runtime,
|
||||
}));
|
||||
|
||||
const mockedModuleIds = [
|
||||
"../../commands/backup.js",
|
||||
"../../commands/backup-verify.js",
|
||||
"../../runtime.js",
|
||||
];
|
||||
|
||||
let registerBackupCommand: typeof import("./register.backup.js").registerBackupCommand;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerBackupCommand } = await import("./register.backup.js"));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
describe("registerBackupCommand", () => {
|
||||
async function runCli(args: string[]) {
|
||||
const program = new Command();
|
||||
|
|
@ -47,7 +37,6 @@ describe("registerBackupCommand", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
resetRuntimeCapture();
|
||||
backupCreateCommand.mockResolvedValue(undefined);
|
||||
backupVerifyCommand.mockResolvedValue(undefined);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,37 +1,27 @@
|
|||
import { Command } from "commander";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerConfigureCommand } from "./register.configure.js";
|
||||
|
||||
const configureCommandFromSectionsArgMock = vi.fn();
|
||||
const runtime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
const mocks = vi.hoisted(() => ({
|
||||
configureCommandFromSectionsArgMock: vi.fn(),
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const { configureCommandFromSectionsArgMock, runtime } = mocks;
|
||||
|
||||
vi.mock("../../commands/configure.js", () => ({
|
||||
CONFIGURE_WIZARD_SECTIONS: ["auth", "channels", "gateway", "agent"],
|
||||
configureCommandFromSectionsArg: configureCommandFromSectionsArgMock,
|
||||
configureCommandFromSectionsArg: mocks.configureCommandFromSectionsArgMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime: runtime,
|
||||
defaultRuntime: mocks.runtime,
|
||||
}));
|
||||
|
||||
const mockedModuleIds = ["../../commands/configure.js", "../../runtime.js"];
|
||||
|
||||
let registerConfigureCommand: typeof import("./register.configure.js").registerConfigureCommand;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerConfigureCommand } = await import("./register.configure.js"));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
describe("registerConfigureCommand", () => {
|
||||
async function runCli(args: string[]) {
|
||||
const program = new Command();
|
||||
|
|
|
|||
|
|
@ -1,58 +1,41 @@
|
|||
import { Command } from "commander";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerMaintenanceCommands } from "./register.maintenance.js";
|
||||
|
||||
const doctorCommand = vi.fn();
|
||||
const dashboardCommand = vi.fn();
|
||||
const resetCommand = vi.fn();
|
||||
const uninstallCommand = vi.fn();
|
||||
const mocks = vi.hoisted(() => ({
|
||||
doctorCommand: vi.fn(),
|
||||
dashboardCommand: vi.fn(),
|
||||
resetCommand: vi.fn(),
|
||||
uninstallCommand: vi.fn(),
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const runtime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
const { doctorCommand, dashboardCommand, resetCommand, uninstallCommand, runtime } = mocks;
|
||||
|
||||
vi.mock("../../commands/doctor.js", () => ({
|
||||
doctorCommand,
|
||||
doctorCommand: mocks.doctorCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/dashboard.js", () => ({
|
||||
dashboardCommand,
|
||||
dashboardCommand: mocks.dashboardCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/reset.js", () => ({
|
||||
resetCommand,
|
||||
resetCommand: mocks.resetCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/uninstall.js", () => ({
|
||||
uninstallCommand,
|
||||
uninstallCommand: mocks.uninstallCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime: runtime,
|
||||
defaultRuntime: mocks.runtime,
|
||||
}));
|
||||
|
||||
const mockedModuleIds = [
|
||||
"../../commands/doctor.js",
|
||||
"../../commands/dashboard.js",
|
||||
"../../commands/reset.js",
|
||||
"../../commands/uninstall.js",
|
||||
"../../runtime.js",
|
||||
];
|
||||
|
||||
let registerMaintenanceCommands: typeof import("./register.maintenance.js").registerMaintenanceCommands;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerMaintenanceCommands } = await import("./register.maintenance.js"));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
describe("registerMaintenanceCommands doctor action", () => {
|
||||
async function runMaintenanceCli(args: string[]) {
|
||||
const program = new Command();
|
||||
|
|
|
|||
|
|
@ -1,94 +1,84 @@
|
|||
import { Command } from "commander";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ProgramContext } from "./context.js";
|
||||
import { registerMessageCommands } from "./register.message.js";
|
||||
|
||||
const createMessageCliHelpersMock = vi.fn(() => ({ helper: true }));
|
||||
const registerMessageSendCommandMock = vi.fn();
|
||||
const registerMessageBroadcastCommandMock = vi.fn();
|
||||
const registerMessagePollCommandMock = vi.fn();
|
||||
const registerMessageReactionsCommandsMock = vi.fn();
|
||||
const registerMessageReadEditDeleteCommandsMock = vi.fn();
|
||||
const registerMessagePinCommandsMock = vi.fn();
|
||||
const registerMessagePermissionsCommandMock = vi.fn();
|
||||
const registerMessageSearchCommandMock = vi.fn();
|
||||
const registerMessageThreadCommandsMock = vi.fn();
|
||||
const registerMessageEmojiCommandsMock = vi.fn();
|
||||
const registerMessageStickerCommandsMock = vi.fn();
|
||||
const registerMessageDiscordAdminCommandsMock = vi.fn();
|
||||
const mocks = vi.hoisted(() => ({
|
||||
createMessageCliHelpersMock: vi.fn(() => ({ helper: true })),
|
||||
registerMessageSendCommandMock: vi.fn(),
|
||||
registerMessageBroadcastCommandMock: vi.fn(),
|
||||
registerMessagePollCommandMock: vi.fn(),
|
||||
registerMessageReactionsCommandsMock: vi.fn(),
|
||||
registerMessageReadEditDeleteCommandsMock: vi.fn(),
|
||||
registerMessagePinCommandsMock: vi.fn(),
|
||||
registerMessagePermissionsCommandMock: vi.fn(),
|
||||
registerMessageSearchCommandMock: vi.fn(),
|
||||
registerMessageThreadCommandsMock: vi.fn(),
|
||||
registerMessageEmojiCommandsMock: vi.fn(),
|
||||
registerMessageStickerCommandsMock: vi.fn(),
|
||||
registerMessageDiscordAdminCommandsMock: vi.fn(),
|
||||
}));
|
||||
|
||||
const createMessageCliHelpersMock = mocks.createMessageCliHelpersMock;
|
||||
const registerMessageSendCommandMock = mocks.registerMessageSendCommandMock;
|
||||
const registerMessageBroadcastCommandMock = mocks.registerMessageBroadcastCommandMock;
|
||||
const registerMessagePollCommandMock = mocks.registerMessagePollCommandMock;
|
||||
const registerMessageReactionsCommandsMock = mocks.registerMessageReactionsCommandsMock;
|
||||
const registerMessageReadEditDeleteCommandsMock = mocks.registerMessageReadEditDeleteCommandsMock;
|
||||
const registerMessagePinCommandsMock = mocks.registerMessagePinCommandsMock;
|
||||
const registerMessagePermissionsCommandMock = mocks.registerMessagePermissionsCommandMock;
|
||||
const registerMessageSearchCommandMock = mocks.registerMessageSearchCommandMock;
|
||||
const registerMessageThreadCommandsMock = mocks.registerMessageThreadCommandsMock;
|
||||
const registerMessageEmojiCommandsMock = mocks.registerMessageEmojiCommandsMock;
|
||||
const registerMessageStickerCommandsMock = mocks.registerMessageStickerCommandsMock;
|
||||
const registerMessageDiscordAdminCommandsMock = mocks.registerMessageDiscordAdminCommandsMock;
|
||||
|
||||
vi.mock("./message/helpers.js", () => ({
|
||||
createMessageCliHelpers: createMessageCliHelpersMock,
|
||||
createMessageCliHelpers: mocks.createMessageCliHelpersMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.send.js", () => ({
|
||||
registerMessageSendCommand: registerMessageSendCommandMock,
|
||||
registerMessageSendCommand: mocks.registerMessageSendCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.broadcast.js", () => ({
|
||||
registerMessageBroadcastCommand: registerMessageBroadcastCommandMock,
|
||||
registerMessageBroadcastCommand: mocks.registerMessageBroadcastCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.poll.js", () => ({
|
||||
registerMessagePollCommand: registerMessagePollCommandMock,
|
||||
registerMessagePollCommand: mocks.registerMessagePollCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.reactions.js", () => ({
|
||||
registerMessageReactionsCommands: registerMessageReactionsCommandsMock,
|
||||
registerMessageReactionsCommands: mocks.registerMessageReactionsCommandsMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.read-edit-delete.js", () => ({
|
||||
registerMessageReadEditDeleteCommands: registerMessageReadEditDeleteCommandsMock,
|
||||
registerMessageReadEditDeleteCommands: mocks.registerMessageReadEditDeleteCommandsMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.pins.js", () => ({
|
||||
registerMessagePinCommands: registerMessagePinCommandsMock,
|
||||
registerMessagePinCommands: mocks.registerMessagePinCommandsMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.permissions-search.js", () => ({
|
||||
registerMessagePermissionsCommand: registerMessagePermissionsCommandMock,
|
||||
registerMessageSearchCommand: registerMessageSearchCommandMock,
|
||||
registerMessagePermissionsCommand: mocks.registerMessagePermissionsCommandMock,
|
||||
registerMessageSearchCommand: mocks.registerMessageSearchCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.thread.js", () => ({
|
||||
registerMessageThreadCommands: registerMessageThreadCommandsMock,
|
||||
registerMessageThreadCommands: mocks.registerMessageThreadCommandsMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.emoji-sticker.js", () => ({
|
||||
registerMessageEmojiCommands: registerMessageEmojiCommandsMock,
|
||||
registerMessageStickerCommands: registerMessageStickerCommandsMock,
|
||||
registerMessageEmojiCommands: mocks.registerMessageEmojiCommandsMock,
|
||||
registerMessageStickerCommands: mocks.registerMessageStickerCommandsMock,
|
||||
}));
|
||||
|
||||
vi.mock("./message/register.discord-admin.js", () => ({
|
||||
registerMessageDiscordAdminCommands: registerMessageDiscordAdminCommandsMock,
|
||||
registerMessageDiscordAdminCommands: mocks.registerMessageDiscordAdminCommandsMock,
|
||||
}));
|
||||
|
||||
const mockedModuleIds = [
|
||||
"./message/helpers.js",
|
||||
"./message/register.send.js",
|
||||
"./message/register.broadcast.js",
|
||||
"./message/register.poll.js",
|
||||
"./message/register.reactions.js",
|
||||
"./message/register.read-edit-delete.js",
|
||||
"./message/register.pins.js",
|
||||
"./message/register.permissions-search.js",
|
||||
"./message/register.thread.js",
|
||||
"./message/register.emoji-sticker.js",
|
||||
"./message/register.discord-admin.js",
|
||||
];
|
||||
|
||||
let registerMessageCommands: typeof import("./register.message.js").registerMessageCommands;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerMessageCommands } = await import("./register.message.js"));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
describe("registerMessageCommands", () => {
|
||||
const ctx: ProgramContext = {
|
||||
programVersion: "9.9.9-test",
|
||||
|
|
|
|||
|
|
@ -1,13 +1,18 @@
|
|||
import { Command } from "commander";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerOnboardCommand } from "./register.onboard.js";
|
||||
|
||||
const setupWizardCommandMock = vi.fn();
|
||||
const mocks = vi.hoisted(() => ({
|
||||
setupWizardCommandMock: vi.fn(),
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const runtime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
const setupWizardCommandMock = mocks.setupWizardCommandMock;
|
||||
const runtime = mocks.runtime;
|
||||
|
||||
vi.mock("../../commands/auth-choice-options.static.js", () => ({
|
||||
formatStaticAuthChoiceChoicesForCli: () => "token|oauth",
|
||||
|
|
@ -38,35 +43,13 @@ vi.mock("../../plugins/provider-auth-choices.js", () => ({
|
|||
}));
|
||||
|
||||
vi.mock("../../commands/onboard.js", () => ({
|
||||
setupWizardCommand: setupWizardCommandMock,
|
||||
setupWizardCommand: mocks.setupWizardCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime: runtime,
|
||||
defaultRuntime: mocks.runtime,
|
||||
}));
|
||||
|
||||
const mockedModuleIds = [
|
||||
"../../commands/auth-choice-options.static.js",
|
||||
"../../commands/auth-choice-options.js",
|
||||
"../../commands/onboard-core-auth-flags.js",
|
||||
"../../plugins/provider-auth-choices.js",
|
||||
"../../commands/onboard.js",
|
||||
"../../runtime.js",
|
||||
];
|
||||
|
||||
let registerOnboardCommand: typeof import("./register.onboard.js").registerOnboardCommand;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerOnboardCommand } = await import("./register.onboard.js"));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
describe("registerOnboardCommand", () => {
|
||||
async function runCli(args: string[]) {
|
||||
const program = new Command();
|
||||
|
|
|
|||
|
|
@ -1,45 +1,33 @@
|
|||
import { Command } from "commander";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerSetupCommand } from "./register.setup.js";
|
||||
|
||||
const setupCommandMock = vi.fn();
|
||||
const setupWizardCommandMock = vi.fn();
|
||||
const runtime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
const mocks = vi.hoisted(() => ({
|
||||
setupCommandMock: vi.fn(),
|
||||
setupWizardCommandMock: vi.fn(),
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const setupCommandMock = mocks.setupCommandMock;
|
||||
const setupWizardCommandMock = mocks.setupWizardCommandMock;
|
||||
const runtime = mocks.runtime;
|
||||
|
||||
vi.mock("../../commands/setup.js", () => ({
|
||||
setupCommand: setupCommandMock,
|
||||
setupCommand: mocks.setupCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/onboard.js", () => ({
|
||||
setupWizardCommand: setupWizardCommandMock,
|
||||
setupWizardCommand: mocks.setupWizardCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime: runtime,
|
||||
defaultRuntime: mocks.runtime,
|
||||
}));
|
||||
|
||||
const mockedModuleIds = [
|
||||
"../../commands/setup.js",
|
||||
"../../commands/onboard.js",
|
||||
"../../runtime.js",
|
||||
];
|
||||
|
||||
let registerSetupCommand: typeof import("./register.setup.js").registerSetupCommand;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerSetupCommand } = await import("./register.setup.js"));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
describe("registerSetupCommand", () => {
|
||||
async function runCli(args: string[]) {
|
||||
const program = new Command();
|
||||
|
|
|
|||
|
|
@ -1,60 +1,72 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "../test-runtime-capture.js";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerStatusHealthSessionsCommands } from "./register.status-health-sessions.js";
|
||||
|
||||
const statusCommand = vi.fn();
|
||||
const healthCommand = vi.fn();
|
||||
const sessionsCommand = vi.fn();
|
||||
const sessionsCleanupCommand = vi.fn();
|
||||
const tasksListCommand = vi.fn();
|
||||
const tasksAuditCommand = vi.fn();
|
||||
const tasksMaintenanceCommand = vi.fn();
|
||||
const tasksShowCommand = vi.fn();
|
||||
const tasksNotifyCommand = vi.fn();
|
||||
const tasksCancelCommand = vi.fn();
|
||||
const setVerbose = vi.fn();
|
||||
const mocks = vi.hoisted(() => ({
|
||||
statusCommand: vi.fn(),
|
||||
healthCommand: vi.fn(),
|
||||
sessionsCommand: vi.fn(),
|
||||
sessionsCleanupCommand: vi.fn(),
|
||||
tasksListCommand: vi.fn(),
|
||||
tasksAuditCommand: vi.fn(),
|
||||
tasksMaintenanceCommand: vi.fn(),
|
||||
tasksShowCommand: vi.fn(),
|
||||
tasksNotifyCommand: vi.fn(),
|
||||
tasksCancelCommand: vi.fn(),
|
||||
setVerbose: vi.fn(),
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const { defaultRuntime: runtime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const statusCommand = mocks.statusCommand;
|
||||
const healthCommand = mocks.healthCommand;
|
||||
const sessionsCommand = mocks.sessionsCommand;
|
||||
const sessionsCleanupCommand = mocks.sessionsCleanupCommand;
|
||||
const tasksListCommand = mocks.tasksListCommand;
|
||||
const tasksAuditCommand = mocks.tasksAuditCommand;
|
||||
const tasksMaintenanceCommand = mocks.tasksMaintenanceCommand;
|
||||
const tasksShowCommand = mocks.tasksShowCommand;
|
||||
const tasksNotifyCommand = mocks.tasksNotifyCommand;
|
||||
const tasksCancelCommand = mocks.tasksCancelCommand;
|
||||
const setVerbose = mocks.setVerbose;
|
||||
const runtime = mocks.runtime;
|
||||
|
||||
vi.mock("../../commands/status.js", () => ({
|
||||
statusCommand,
|
||||
statusCommand: mocks.statusCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/health.js", () => ({
|
||||
healthCommand,
|
||||
healthCommand: mocks.healthCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/sessions.js", () => ({
|
||||
sessionsCommand,
|
||||
sessionsCommand: mocks.sessionsCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/sessions-cleanup.js", () => ({
|
||||
sessionsCleanupCommand,
|
||||
sessionsCleanupCommand: mocks.sessionsCleanupCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/tasks.js", () => ({
|
||||
tasksListCommand,
|
||||
tasksAuditCommand,
|
||||
tasksMaintenanceCommand,
|
||||
tasksShowCommand,
|
||||
tasksNotifyCommand,
|
||||
tasksCancelCommand,
|
||||
tasksListCommand: mocks.tasksListCommand,
|
||||
tasksAuditCommand: mocks.tasksAuditCommand,
|
||||
tasksMaintenanceCommand: mocks.tasksMaintenanceCommand,
|
||||
tasksShowCommand: mocks.tasksShowCommand,
|
||||
tasksNotifyCommand: mocks.tasksNotifyCommand,
|
||||
tasksCancelCommand: mocks.tasksCancelCommand,
|
||||
}));
|
||||
|
||||
vi.mock("../../globals.js", () => ({
|
||||
setVerbose,
|
||||
setVerbose: mocks.setVerbose,
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime: runtime,
|
||||
defaultRuntime: mocks.runtime,
|
||||
}));
|
||||
|
||||
let registerStatusHealthSessionsCommands: typeof import("./register.status-health-sessions.js").registerStatusHealthSessionsCommands;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerStatusHealthSessionsCommands } = await import("./register.status-health-sessions.js"));
|
||||
});
|
||||
|
||||
describe("registerStatusHealthSessionsCommands", () => {
|
||||
async function runCli(args: string[]) {
|
||||
const program = new Command();
|
||||
|
|
@ -64,7 +76,6 @@ describe("registerStatusHealthSessionsCommands", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
resetRuntimeCapture();
|
||||
runtime.exit.mockImplementation(() => {});
|
||||
statusCommand.mockResolvedValue(undefined);
|
||||
healthCommand.mockResolvedValue(undefined);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { Command } from "commander";
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
loadValidatedConfigForPluginRegistration,
|
||||
registerSubCliByName,
|
||||
registerSubCliCommands,
|
||||
} from "./register.subclis.js";
|
||||
|
||||
const { acpAction, registerAcpCli } = vi.hoisted(() => {
|
||||
const action = vi.fn();
|
||||
|
|
@ -27,18 +32,6 @@ vi.mock("../acp-cli.js", () => ({ registerAcpCli }));
|
|||
vi.mock("../nodes-cli.js", () => ({ registerNodesCli }));
|
||||
vi.mock("../../config/config.js", () => configModule);
|
||||
|
||||
const mockedModuleIds = ["../acp-cli.js", "../nodes-cli.js", "../../config/config.js"];
|
||||
|
||||
const { loadValidatedConfigForPluginRegistration, registerSubCliByName, registerSubCliCommands } =
|
||||
await import("./register.subclis.js");
|
||||
|
||||
afterAll(() => {
|
||||
for (const id of mockedModuleIds) {
|
||||
vi.doUnmock(id);
|
||||
}
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
describe("registerSubCliCommands", () => {
|
||||
const originalArgv = process.argv;
|
||||
const originalDisableLazySubcommands = process.env.OPENCLAW_DISABLE_LAZY_SUBCOMMANDS;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { renderRootHelpText } from "./root-help.js";
|
||||
|
||||
vi.mock("./core-command-descriptors.js", () => ({
|
||||
getCoreCliCommandDescriptors: () => [
|
||||
|
|
@ -32,8 +33,6 @@ vi.mock("../../plugins/cli.js", () => ({
|
|||
],
|
||||
}));
|
||||
|
||||
const { renderRootHelpText } = await import("./root-help.js");
|
||||
|
||||
describe("root help", () => {
|
||||
it("includes plugin CLI descriptors alongside core and sub-CLI commands", async () => {
|
||||
const text = await renderRootHelpText();
|
||||
|
|
|
|||
|
|
@ -1,34 +1,26 @@
|
|||
import readline from "node:readline/promises";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { isYes, setVerbose, setYes } from "../globals.js";
|
||||
import { promptYesNo } from "./prompt.js";
|
||||
|
||||
type ReadlineMock = {
|
||||
default: {
|
||||
createInterface: () => {
|
||||
question: ReturnType<typeof vi.fn>;
|
||||
close: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
};
|
||||
};
|
||||
const readlineState = vi.hoisted(() => {
|
||||
const question = vi.fn(async () => "");
|
||||
const close = vi.fn();
|
||||
const createInterface = vi.fn(() => ({ question, close }));
|
||||
return { question, close, createInterface };
|
||||
});
|
||||
|
||||
type PromptModule = typeof import("./prompt.js");
|
||||
type GlobalsModule = typeof import("../globals.js");
|
||||
vi.mock("node:readline/promises", () => ({
|
||||
default: { createInterface: readlineState.createInterface },
|
||||
}));
|
||||
|
||||
let promptYesNo: PromptModule["promptYesNo"];
|
||||
let readline: ReadlineMock;
|
||||
let isYes: GlobalsModule["isYes"];
|
||||
let setVerbose: GlobalsModule["setVerbose"];
|
||||
let setYes: GlobalsModule["setYes"];
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
vi.doMock("node:readline/promises", () => {
|
||||
const question = vi.fn(async () => "");
|
||||
const close = vi.fn();
|
||||
const createInterface = vi.fn(() => ({ question, close }));
|
||||
return { default: { createInterface } };
|
||||
});
|
||||
({ promptYesNo } = await import("./prompt.js"));
|
||||
({ isYes, setVerbose, setYes } = await import("../globals.js"));
|
||||
readline = (await import("node:readline/promises")) as unknown as ReadlineMock;
|
||||
beforeEach(() => {
|
||||
setYes(false);
|
||||
setVerbose(false);
|
||||
readlineState.question.mockReset();
|
||||
readlineState.question.mockResolvedValue("");
|
||||
readlineState.close.mockClear();
|
||||
readlineState.createInterface.mockClear();
|
||||
});
|
||||
|
||||
describe("promptYesNo", () => {
|
||||
|
|
@ -43,16 +35,16 @@ describe("promptYesNo", () => {
|
|||
it("asks the question and respects default", async () => {
|
||||
setYes(false);
|
||||
setVerbose(false);
|
||||
const { question: questionMock } = readline.default.createInterface();
|
||||
questionMock.mockResolvedValueOnce("");
|
||||
expect(readline).toBeTruthy();
|
||||
readlineState.question.mockResolvedValueOnce("");
|
||||
const resultDefaultYes = await promptYesNo("Continue?", true);
|
||||
expect(resultDefaultYes).toBe(true);
|
||||
|
||||
questionMock.mockResolvedValueOnce("n");
|
||||
readlineState.question.mockResolvedValueOnce("n");
|
||||
const resultNo = await promptYesNo("Continue?", true);
|
||||
expect(resultNo).toBe(false);
|
||||
|
||||
questionMock.mockResolvedValueOnce("y");
|
||||
readlineState.question.mockResolvedValueOnce("y");
|
||||
const resultYes = await promptYesNo("Continue?", false);
|
||||
expect(resultYes).toBe(true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import process from "node:process";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { runCli } from "./run-main.js";
|
||||
|
||||
const tryRouteCliMock = vi.hoisted(() => vi.fn());
|
||||
const loadDotEnvMock = vi.hoisted(() => vi.fn());
|
||||
|
|
@ -67,8 +68,6 @@ vi.mock("./program.js", () => ({
|
|||
buildProgram: buildProgramMock,
|
||||
}));
|
||||
|
||||
const { runCli } = await import("./run-main.js");
|
||||
|
||||
describe("runCli exit behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
|
|
|||
|
|
@ -3,48 +3,83 @@ import os from "node:os";
|
|||
import path from "node:path";
|
||||
import { Command } from "commander";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { registerSecretsCli } from "./secrets-cli.js";
|
||||
|
||||
const callGatewayFromCli = vi.fn();
|
||||
const runSecretsAudit = vi.fn();
|
||||
const resolveSecretsAuditExitCode = vi.fn();
|
||||
const runSecretsConfigureInteractive = vi.fn();
|
||||
const runSecretsApply = vi.fn();
|
||||
const confirm = vi.fn();
|
||||
const mocks = vi.hoisted(() => {
|
||||
const runtimeLogs: string[] = [];
|
||||
const runtimeErrors: string[] = [];
|
||||
const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" ");
|
||||
const defaultRuntime = {
|
||||
log: vi.fn((...args: unknown[]) => {
|
||||
runtimeLogs.push(stringifyArgs(args));
|
||||
}),
|
||||
error: vi.fn((...args: unknown[]) => {
|
||||
runtimeErrors.push(stringifyArgs(args));
|
||||
}),
|
||||
writeStdout: vi.fn((value: string) => {
|
||||
defaultRuntime.log(value.endsWith("\n") ? value.slice(0, -1) : value);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
defaultRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
}),
|
||||
};
|
||||
return {
|
||||
callGatewayFromCli: vi.fn(),
|
||||
runSecretsAudit: vi.fn(),
|
||||
resolveSecretsAuditExitCode: vi.fn(),
|
||||
runSecretsConfigureInteractive: vi.fn(),
|
||||
runSecretsApply: vi.fn(),
|
||||
confirm: vi.fn(),
|
||||
defaultRuntime,
|
||||
runtimeLogs,
|
||||
runtimeErrors,
|
||||
};
|
||||
});
|
||||
|
||||
const { defaultRuntime, runtimeLogs, runtimeErrors, resetRuntimeCapture } =
|
||||
createCliRuntimeCapture();
|
||||
const {
|
||||
callGatewayFromCli,
|
||||
runSecretsAudit,
|
||||
resolveSecretsAuditExitCode,
|
||||
runSecretsConfigureInteractive,
|
||||
runSecretsApply,
|
||||
confirm,
|
||||
defaultRuntime,
|
||||
runtimeLogs,
|
||||
runtimeErrors,
|
||||
} = mocks;
|
||||
|
||||
vi.mock("./gateway-rpc.js", () => ({
|
||||
addGatewayClientOptions: (cmd: Command) => cmd,
|
||||
callGatewayFromCli: (method: string, opts: unknown, params?: unknown, extra?: unknown) =>
|
||||
callGatewayFromCli(method, opts, params, extra),
|
||||
mocks.callGatewayFromCli(method, opts, params, extra),
|
||||
}));
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
vi.mock("../secrets/audit.js", () => ({
|
||||
runSecretsAudit: (options: unknown) => runSecretsAudit(options),
|
||||
runSecretsAudit: (options: unknown) => mocks.runSecretsAudit(options),
|
||||
resolveSecretsAuditExitCode: (report: unknown, check: boolean) =>
|
||||
resolveSecretsAuditExitCode(report, check),
|
||||
mocks.resolveSecretsAuditExitCode(report, check),
|
||||
}));
|
||||
|
||||
vi.mock("../secrets/configure.js", () => ({
|
||||
runSecretsConfigureInteractive: (options: unknown) => runSecretsConfigureInteractive(options),
|
||||
runSecretsConfigureInteractive: (options: unknown) =>
|
||||
mocks.runSecretsConfigureInteractive(options),
|
||||
}));
|
||||
|
||||
vi.mock("../secrets/apply.js", () => ({
|
||||
runSecretsApply: (options: unknown) => runSecretsApply(options),
|
||||
runSecretsApply: (options: unknown) => mocks.runSecretsApply(options),
|
||||
}));
|
||||
|
||||
vi.mock("@clack/prompts", () => ({
|
||||
confirm: (options: unknown) => confirm(options),
|
||||
confirm: (options: unknown) => mocks.confirm(options),
|
||||
}));
|
||||
|
||||
const { registerSecretsCli } = await import("./secrets-cli.js");
|
||||
|
||||
function createManualSecretsPlan() {
|
||||
return {
|
||||
version: 1,
|
||||
|
|
@ -126,13 +161,19 @@ describe("secrets CLI", () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
runtimeErrors.length = 0;
|
||||
callGatewayFromCli.mockReset();
|
||||
runSecretsAudit.mockReset();
|
||||
resolveSecretsAuditExitCode.mockReset();
|
||||
runSecretsConfigureInteractive.mockReset();
|
||||
runSecretsApply.mockReset();
|
||||
confirm.mockReset();
|
||||
defaultRuntime.log.mockClear();
|
||||
defaultRuntime.error.mockClear();
|
||||
defaultRuntime.writeStdout.mockClear();
|
||||
defaultRuntime.writeJson.mockClear();
|
||||
defaultRuntime.exit.mockClear();
|
||||
});
|
||||
|
||||
it("calls secrets.reload and prints human output", async () => {
|
||||
|
|
|
|||
|
|
@ -1,43 +1,72 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { registerSecurityCli } from "./security-cli.js";
|
||||
|
||||
const loadConfig = vi.fn();
|
||||
const runSecurityAudit = vi.fn();
|
||||
const fixSecurityFootguns = vi.fn();
|
||||
const resolveCommandSecretRefsViaGateway = vi.fn();
|
||||
const getSecurityAuditCommandSecretTargetIds = vi.fn(
|
||||
() => new Set(["gateway.auth.token", "gateway.auth.password"]),
|
||||
);
|
||||
const mocks = vi.hoisted(() => {
|
||||
const runtimeLogs: string[] = [];
|
||||
const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" ");
|
||||
const defaultRuntime = {
|
||||
log: vi.fn((...args: unknown[]) => {
|
||||
runtimeLogs.push(stringifyArgs(args));
|
||||
}),
|
||||
error: vi.fn(),
|
||||
writeStdout: vi.fn((value: string) => {
|
||||
defaultRuntime.log(value.endsWith("\n") ? value.slice(0, -1) : value);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
defaultRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
}),
|
||||
};
|
||||
return {
|
||||
loadConfig: vi.fn(),
|
||||
runSecurityAudit: vi.fn(),
|
||||
fixSecurityFootguns: vi.fn(),
|
||||
resolveCommandSecretRefsViaGateway: vi.fn(),
|
||||
getSecurityAuditCommandSecretTargetIds: vi.fn(
|
||||
() => new Set(["gateway.auth.token", "gateway.auth.password"]),
|
||||
),
|
||||
defaultRuntime,
|
||||
runtimeLogs,
|
||||
};
|
||||
});
|
||||
|
||||
const { defaultRuntime, runtimeLogs, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const {
|
||||
loadConfig,
|
||||
runSecurityAudit,
|
||||
fixSecurityFootguns,
|
||||
resolveCommandSecretRefsViaGateway,
|
||||
getSecurityAuditCommandSecretTargetIds,
|
||||
runtimeLogs,
|
||||
} = mocks;
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
loadConfig: () => loadConfig(),
|
||||
loadConfig: () => mocks.loadConfig(),
|
||||
}));
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
vi.mock("../security/audit.js", () => ({
|
||||
runSecurityAudit: (opts: unknown) => runSecurityAudit(opts),
|
||||
runSecurityAudit: (opts: unknown) => mocks.runSecurityAudit(opts),
|
||||
}));
|
||||
|
||||
vi.mock("../security/fix.js", () => ({
|
||||
fixSecurityFootguns: () => fixSecurityFootguns(),
|
||||
fixSecurityFootguns: () => mocks.fixSecurityFootguns(),
|
||||
}));
|
||||
|
||||
vi.mock("./command-secret-gateway.js", () => ({
|
||||
resolveCommandSecretRefsViaGateway: (opts: unknown) => resolveCommandSecretRefsViaGateway(opts),
|
||||
resolveCommandSecretRefsViaGateway: (opts: unknown) =>
|
||||
mocks.resolveCommandSecretRefsViaGateway(opts),
|
||||
}));
|
||||
|
||||
vi.mock("./command-secret-targets.js", () => ({
|
||||
getSecurityAuditCommandSecretTargetIds: () => getSecurityAuditCommandSecretTargetIds(),
|
||||
getSecurityAuditCommandSecretTargetIds: () => mocks.getSecurityAuditCommandSecretTargetIds(),
|
||||
}));
|
||||
|
||||
const { registerSecurityCli } = await import("./security-cli.js");
|
||||
|
||||
function createProgram() {
|
||||
const program = new Command();
|
||||
program.exitOverride();
|
||||
|
|
@ -63,7 +92,7 @@ function primeDeepAuditConfig(sourceConfig = { gateway: { mode: "local" } }) {
|
|||
|
||||
describe("security CLI", () => {
|
||||
beforeEach(() => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
loadConfig.mockReset();
|
||||
runSecurityAudit.mockReset();
|
||||
fixSecurityFootguns.mockReset();
|
||||
|
|
|
|||
|
|
@ -1,40 +1,76 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { registerSkillsCli } from "./skills-cli.js";
|
||||
|
||||
const loadConfigMock = vi.fn(() => ({}));
|
||||
const resolveDefaultAgentIdMock = vi.fn(() => "main");
|
||||
const resolveAgentWorkspaceDirMock = vi.fn(() => "/tmp/workspace");
|
||||
const searchSkillsFromClawHubMock = vi.fn();
|
||||
const installSkillFromClawHubMock = vi.fn();
|
||||
const updateSkillsFromClawHubMock = vi.fn();
|
||||
const readTrackedClawHubSkillSlugsMock = vi.fn();
|
||||
const mocks = vi.hoisted(() => {
|
||||
const runtimeLogs: string[] = [];
|
||||
const runtimeErrors: string[] = [];
|
||||
const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" ");
|
||||
const defaultRuntime = {
|
||||
log: vi.fn((...args: unknown[]) => {
|
||||
runtimeLogs.push(stringifyArgs(args));
|
||||
}),
|
||||
error: vi.fn((...args: unknown[]) => {
|
||||
runtimeErrors.push(stringifyArgs(args));
|
||||
}),
|
||||
writeStdout: vi.fn((value: string) => {
|
||||
defaultRuntime.log(value.endsWith("\n") ? value.slice(0, -1) : value);
|
||||
}),
|
||||
writeJson: vi.fn((value: unknown, space = 2) => {
|
||||
defaultRuntime.log(JSON.stringify(value, null, space > 0 ? space : undefined));
|
||||
}),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
}),
|
||||
};
|
||||
return {
|
||||
loadConfigMock: vi.fn(() => ({})),
|
||||
resolveDefaultAgentIdMock: vi.fn(() => "main"),
|
||||
resolveAgentWorkspaceDirMock: vi.fn(() => "/tmp/workspace"),
|
||||
searchSkillsFromClawHubMock: vi.fn(),
|
||||
installSkillFromClawHubMock: vi.fn(),
|
||||
updateSkillsFromClawHubMock: vi.fn(),
|
||||
readTrackedClawHubSkillSlugsMock: vi.fn(),
|
||||
defaultRuntime,
|
||||
runtimeLogs,
|
||||
runtimeErrors,
|
||||
};
|
||||
});
|
||||
|
||||
const { defaultRuntime, runtimeLogs, runtimeErrors, resetRuntimeCapture } =
|
||||
createCliRuntimeCapture();
|
||||
const {
|
||||
loadConfigMock,
|
||||
resolveDefaultAgentIdMock,
|
||||
resolveAgentWorkspaceDirMock,
|
||||
searchSkillsFromClawHubMock,
|
||||
installSkillFromClawHubMock,
|
||||
updateSkillsFromClawHubMock,
|
||||
readTrackedClawHubSkillSlugsMock,
|
||||
defaultRuntime,
|
||||
runtimeLogs,
|
||||
runtimeErrors,
|
||||
} = mocks;
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
loadConfig: () => loadConfigMock(),
|
||||
loadConfig: () => mocks.loadConfigMock(),
|
||||
}));
|
||||
|
||||
vi.mock("../agents/agent-scope.js", () => ({
|
||||
resolveDefaultAgentId: () => resolveDefaultAgentIdMock(),
|
||||
resolveAgentWorkspaceDir: () => resolveAgentWorkspaceDirMock(),
|
||||
resolveDefaultAgentId: () => mocks.resolveDefaultAgentIdMock(),
|
||||
resolveAgentWorkspaceDir: () => mocks.resolveAgentWorkspaceDirMock(),
|
||||
}));
|
||||
|
||||
vi.mock("../agents/skills-clawhub.js", () => ({
|
||||
searchSkillsFromClawHub: (...args: unknown[]) => searchSkillsFromClawHubMock(...args),
|
||||
installSkillFromClawHub: (...args: unknown[]) => installSkillFromClawHubMock(...args),
|
||||
updateSkillsFromClawHub: (...args: unknown[]) => updateSkillsFromClawHubMock(...args),
|
||||
readTrackedClawHubSkillSlugs: (...args: unknown[]) => readTrackedClawHubSkillSlugsMock(...args),
|
||||
searchSkillsFromClawHub: (...args: unknown[]) => mocks.searchSkillsFromClawHubMock(...args),
|
||||
installSkillFromClawHub: (...args: unknown[]) => mocks.installSkillFromClawHubMock(...args),
|
||||
updateSkillsFromClawHub: (...args: unknown[]) => mocks.updateSkillsFromClawHubMock(...args),
|
||||
readTrackedClawHubSkillSlugs: (...args: unknown[]) =>
|
||||
mocks.readTrackedClawHubSkillSlugsMock(...args),
|
||||
}));
|
||||
|
||||
const { registerSkillsCli } = await import("./skills-cli.js");
|
||||
|
||||
describe("skills cli commands", () => {
|
||||
const createProgram = () => {
|
||||
const program = new Command();
|
||||
|
|
@ -46,7 +82,8 @@ describe("skills cli commands", () => {
|
|||
const runCommand = (argv: string[]) => createProgram().parseAsync(argv, { from: "user" });
|
||||
|
||||
beforeEach(() => {
|
||||
resetRuntimeCapture();
|
||||
runtimeLogs.length = 0;
|
||||
runtimeErrors.length = 0;
|
||||
loadConfigMock.mockReset();
|
||||
resolveDefaultAgentIdMock.mockReset();
|
||||
resolveAgentWorkspaceDirMock.mockReset();
|
||||
|
|
@ -65,6 +102,11 @@ describe("skills cli commands", () => {
|
|||
});
|
||||
updateSkillsFromClawHubMock.mockResolvedValue([]);
|
||||
readTrackedClawHubSkillSlugsMock.mockResolvedValue([]);
|
||||
defaultRuntime.log.mockClear();
|
||||
defaultRuntime.error.mockClear();
|
||||
defaultRuntime.writeStdout.mockClear();
|
||||
defaultRuntime.writeJson.mockClear();
|
||||
defaultRuntime.exit.mockClear();
|
||||
});
|
||||
|
||||
it("searches ClawHub skills from the native CLI", async () => {
|
||||
|
|
|
|||
|
|
@ -1,42 +1,44 @@
|
|||
import { Command } from "commander";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { runRegisteredCli } from "../test-utils/command-runner.js";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
import { registerUpdateCli } from "./update-cli.js";
|
||||
|
||||
const updateCommand = vi.fn(async (_opts: unknown) => {});
|
||||
const updateStatusCommand = vi.fn(async (_opts: unknown) => {});
|
||||
const updateWizardCommand = vi.fn(async (_opts: unknown) => {});
|
||||
const mocks = vi.hoisted(() => ({
|
||||
updateCommand: vi.fn(async (_opts: unknown) => {}),
|
||||
updateStatusCommand: vi.fn(async (_opts: unknown) => {}),
|
||||
updateWizardCommand: vi.fn(async (_opts: unknown) => {}),
|
||||
defaultRuntime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
writeStdout: vi.fn(),
|
||||
writeJson: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const { defaultRuntime, resetRuntimeCapture } = createCliRuntimeCapture();
|
||||
const { updateCommand, updateStatusCommand, updateWizardCommand, defaultRuntime } = mocks;
|
||||
|
||||
vi.mock("./update-cli/update-command.js", () => ({
|
||||
updateCommand: (opts: unknown) => updateCommand(opts),
|
||||
updateCommand: (opts: unknown) => mocks.updateCommand(opts),
|
||||
}));
|
||||
|
||||
vi.mock("./update-cli/status.js", () => ({
|
||||
updateStatusCommand: (opts: unknown) => updateStatusCommand(opts),
|
||||
updateStatusCommand: (opts: unknown) => mocks.updateStatusCommand(opts),
|
||||
}));
|
||||
|
||||
vi.mock("./update-cli/wizard.js", () => ({
|
||||
updateWizardCommand: (opts: unknown) => updateWizardCommand(opts),
|
||||
updateWizardCommand: (opts: unknown) => mocks.updateWizardCommand(opts),
|
||||
}));
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: mocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
describe("update cli option collisions", () => {
|
||||
let registerUpdateCli: typeof import("./update-cli.js").registerUpdateCli;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ registerUpdateCli } = await import("./update-cli.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
updateCommand.mockClear();
|
||||
updateStatusCommand.mockClear();
|
||||
updateWizardCommand.mockClear();
|
||||
resetRuntimeCapture();
|
||||
defaultRuntime.log.mockClear();
|
||||
defaultRuntime.error.mockClear();
|
||||
defaultRuntime.writeStdout.mockClear();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createGlobalCommandRunner } from "./shared.js";
|
||||
|
||||
const runCommandWithTimeout = vi.fn();
|
||||
const runCommandWithTimeout = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../../process/exec.js", () => ({
|
||||
runCommandWithTimeout,
|
||||
}));
|
||||
|
||||
const { createGlobalCommandRunner } = await import("./shared.js");
|
||||
|
||||
describe("createGlobalCommandRunner", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ReplyPayload } from "../auto-reply/types.js";
|
||||
import type { CliDeps } from "../cli/deps.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { SessionEntry } from "../config/sessions.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { deliverAgentCommandResult } from "./agent/delivery.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
deliverOutboundPayloads: vi.fn(async () => []),
|
||||
|
|
@ -30,14 +31,7 @@ vi.mock("../infra/outbound/targets.js", async () => {
|
|||
};
|
||||
});
|
||||
|
||||
let deliverAgentCommandResult: typeof import("./agent/delivery.js").deliverAgentCommandResult;
|
||||
|
||||
describe("deliverAgentCommandResult", () => {
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ deliverAgentCommandResult } = await import("./agent/delivery.js"));
|
||||
});
|
||||
|
||||
function createRuntime(): RuntimeEnv {
|
||||
return {
|
||||
log: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { resolveSessionKeyForRequest } from "./session.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
loadSessionStore: vi.fn(),
|
||||
|
|
@ -22,8 +23,6 @@ vi.mock("../../agents/agent-scope.js", () => ({
|
|||
listAgentIds: mocks.listAgentIds,
|
||||
}));
|
||||
|
||||
let resolveSessionKeyForRequest: typeof import("./session.js").resolveSessionKeyForRequest;
|
||||
|
||||
describe("resolveSessionKeyForRequest", () => {
|
||||
const MAIN_STORE_PATH = "/tmp/main-store.json";
|
||||
const MYBOT_STORE_PATH = "/tmp/mybot-store.json";
|
||||
|
|
@ -46,11 +45,6 @@ describe("resolveSessionKeyForRequest", () => {
|
|||
mocks.loadSessionStore.mockImplementation((storePath: string) => stores[storePath] ?? {});
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ resolveSessionKeyForRequest } = await import("./session.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mocks.listAgentIds.mockReturnValue(["main"]);
|
||||
|
|
|
|||
|
|
@ -34,9 +34,11 @@ vi.mock("../config/config.js", async (importOriginal) => {
|
|||
|
||||
export const runtime = createTestRuntime();
|
||||
|
||||
let agentsCommandModulePromise: Promise<typeof import("./agents.js")> | undefined;
|
||||
|
||||
export async function loadFreshAgentsCommandModuleForTest() {
|
||||
vi.resetModules();
|
||||
return await import("./agents.js");
|
||||
agentsCommandModulePromise ??= import("./agents.js");
|
||||
return await agentsCommandModulePromise;
|
||||
}
|
||||
|
||||
export function resetAgentsBindTestHarness(): void {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import os from "node:os";
|
|||
import path from "node:path";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";
|
||||
import { backupCreateCommand } from "./backup.js";
|
||||
|
||||
const tarCreateMock = vi.hoisted(() => vi.fn());
|
||||
const backupVerifyCommandMock = vi.hoisted(() => vi.fn());
|
||||
|
|
@ -15,8 +16,6 @@ vi.mock("./backup-verify.js", () => ({
|
|||
backupVerifyCommand: backupVerifyCommandMock,
|
||||
}));
|
||||
|
||||
const { backupCreateCommand } = await import("./backup.js");
|
||||
|
||||
describe("backupCreateCommand atomic archive write", () => {
|
||||
let tempHome: TempHomeEnv;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ChannelPluginCatalogEntry } from "../channels/plugins/catalog.js";
|
||||
import type { ChannelPlugin } from "../channels/plugins/types.js";
|
||||
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
|
|
@ -8,6 +8,7 @@ import {
|
|||
ensureChannelSetupPluginInstalled,
|
||||
loadChannelSetupPluginRegistrySnapshotForChannel,
|
||||
} from "./channel-setup/plugin-install.js";
|
||||
import { channelsAddCommand } from "./channels.js";
|
||||
import { configMocks, offsetMocks } from "./channels.mock-harness.js";
|
||||
import {
|
||||
createMSTeamsCatalogEntry,
|
||||
|
|
@ -47,7 +48,6 @@ vi.mock("./channel-setup/plugin-install.js", async (importOriginal) => {
|
|||
});
|
||||
|
||||
const runtime = createTestRuntime();
|
||||
let channelsAddCommand: typeof import("./channels.js").channelsAddCommand;
|
||||
|
||||
function listConfiguredAccountIds(
|
||||
channelConfig: { accounts?: Record<string, unknown>; botToken?: string } | undefined,
|
||||
|
|
@ -219,10 +219,6 @@ async function runSignalAddCommand(afterAccountConfigWritten: SignalAfterAccount
|
|||
}
|
||||
|
||||
describe("channelsAddCommand", () => {
|
||||
beforeAll(async () => {
|
||||
({ channelsAddCommand } = await import("./channels.js"));
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
configMocks.readConfigFileSnapshot.mockClear();
|
||||
configMocks.writeConfigFile.mockClear();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ChannelPluginCatalogEntry } from "../channels/plugins/catalog.js";
|
||||
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import { createTestRegistry } from "../test-utils/channel-plugins.js";
|
||||
|
|
@ -6,6 +6,7 @@ import {
|
|||
ensureChannelSetupPluginInstalled,
|
||||
loadChannelSetupPluginRegistrySnapshotForChannel,
|
||||
} from "./channel-setup/plugin-install.js";
|
||||
import { channelsRemoveCommand } from "./channels.js";
|
||||
import { configMocks } from "./channels.mock-harness.js";
|
||||
import {
|
||||
createMSTeamsCatalogEntry,
|
||||
|
|
@ -33,13 +34,8 @@ vi.mock("./channel-setup/plugin-install.js", async (importOriginal) => {
|
|||
});
|
||||
|
||||
const runtime = createTestRuntime();
|
||||
let channelsRemoveCommand: typeof import("./channels.js").channelsRemoveCommand;
|
||||
|
||||
describe("channelsRemoveCommand", () => {
|
||||
beforeAll(async () => {
|
||||
({ channelsRemoveCommand } = await import("./channels.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
configMocks.readConfigFileSnapshot.mockClear();
|
||||
configMocks.writeConfigFile.mockClear();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { channelsResolveCommand } from "./channels/resolve.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
resolveCommandSecretRefsViaGateway: vi.fn(),
|
||||
|
|
@ -42,8 +43,6 @@ vi.mock("../channels/plugins/index.js", () => ({
|
|||
getChannelPlugin: mocks.getChannelPlugin,
|
||||
}));
|
||||
|
||||
const { channelsResolveCommand } = await import("./channels/resolve.js");
|
||||
|
||||
describe("channelsResolveCommand", () => {
|
||||
const runtime = {
|
||||
log: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js";
|
||||
import { channelsStatusCommand } from "./channels/status.js";
|
||||
|
||||
const resolveDefaultAccountId = () => DEFAULT_ACCOUNT_ID;
|
||||
|
||||
|
|
@ -39,8 +40,6 @@ vi.mock("../cli/progress.js", () => ({
|
|||
withProgress: (opts: unknown, run: () => Promise<unknown>) => withProgress(opts, run),
|
||||
}));
|
||||
|
||||
const { channelsStatusCommand } = await import("./channels/status.js");
|
||||
|
||||
function createTokenOnlyPlugin() {
|
||||
return {
|
||||
id: "discord",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { PluginCompatibilityNotice } from "../plugins/status.js";
|
||||
import { createCompatibilityNotice } from "../plugins/status.test-helpers.js";
|
||||
import { requireValidConfigSnapshot } from "./config-validation.js";
|
||||
|
||||
const readConfigFileSnapshot = vi.fn();
|
||||
const buildPluginCompatibilityNotices = vi.fn<(_params?: unknown) => PluginCompatibilityNotice[]>(
|
||||
() => [],
|
||||
);
|
||||
const { readConfigFileSnapshot, buildPluginCompatibilityNotices } = vi.hoisted(() => ({
|
||||
readConfigFileSnapshot: vi.fn(),
|
||||
buildPluginCompatibilityNotices: vi.fn<(_params?: unknown) => PluginCompatibilityNotice[]>(
|
||||
() => [],
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
readConfigFileSnapshot,
|
||||
|
|
@ -46,7 +49,6 @@ describe("requireValidConfigSnapshot", () => {
|
|||
createValidSnapshot();
|
||||
const runtime = createRuntime();
|
||||
|
||||
const { requireValidConfigSnapshot } = await import("./config-validation.js");
|
||||
const config = await requireValidConfigSnapshot(runtime);
|
||||
|
||||
expect(config).toEqual({ plugins: {} });
|
||||
|
|
@ -60,7 +62,6 @@ describe("requireValidConfigSnapshot", () => {
|
|||
createValidSnapshot();
|
||||
const runtime = createRuntime();
|
||||
|
||||
const { requireValidConfigSnapshot } = await import("./config-validation.js");
|
||||
const config = await requireValidConfigSnapshot(runtime, {
|
||||
includeCompatibilityAdvisory: true,
|
||||
});
|
||||
|
|
@ -83,7 +84,6 @@ describe("requireValidConfigSnapshot", () => {
|
|||
});
|
||||
const runtime = createRuntime();
|
||||
|
||||
const { requireValidConfigSnapshot } = await import("./config-validation.js");
|
||||
const config = await requireValidConfigSnapshot(runtime, {
|
||||
includeCompatibilityAdvisory: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { maybeInstallDaemon } from "./configure.daemon.js";
|
||||
|
||||
const progressSetLabel = vi.hoisted(() => vi.fn());
|
||||
const withProgress = vi.hoisted(() =>
|
||||
|
|
@ -69,8 +70,6 @@ vi.mock("./systemd-linger.js", () => ({
|
|||
ensureSystemdUserLingerInteractive,
|
||||
}));
|
||||
|
||||
const { maybeInstallDaemon } = await import("./configure.daemon.js");
|
||||
|
||||
describe("maybeInstallDaemon", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { dashboardCommand } from "./dashboard.js";
|
||||
|
||||
const readConfigFileSnapshotMock = vi.hoisted(() => vi.fn());
|
||||
const resolveGatewayPortMock = vi.hoisted(() => vi.fn());
|
||||
|
|
@ -29,8 +30,6 @@ vi.mock("../secrets/resolve.js", () => ({
|
|||
resolveSecretRefValues: resolveSecretRefValuesMock,
|
||||
}));
|
||||
|
||||
let dashboardCommand: typeof import("./dashboard.js").dashboardCommand;
|
||||
|
||||
const runtime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
|
|
@ -63,9 +62,7 @@ function mockSnapshot(token: unknown = "abc") {
|
|||
}
|
||||
|
||||
describe("dashboardCommand", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ dashboardCommand } = await import("./dashboard.js"));
|
||||
beforeEach(() => {
|
||||
resetRuntime();
|
||||
readConfigFileSnapshotMock.mockClear();
|
||||
resolveGatewayPortMock.mockClear();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { GatewayBindMode } from "../config/types.gateway.js";
|
||||
import { dashboardCommand } from "./dashboard.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
readConfigFileSnapshot: vi.fn(),
|
||||
|
|
@ -29,7 +30,6 @@ const runtime = {
|
|||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
let dashboardCommand: typeof import("./dashboard.js").dashboardCommand;
|
||||
|
||||
function mockSnapshot(params?: {
|
||||
token?: string;
|
||||
|
|
@ -62,9 +62,7 @@ function mockSnapshot(params?: {
|
|||
}
|
||||
|
||||
describe("dashboardCommand bind selection", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ dashboardCommand } = await import("./dashboard.js"));
|
||||
beforeEach(() => {
|
||||
mocks.readConfigFileSnapshot.mockClear();
|
||||
mocks.resolveGatewayPort.mockClear();
|
||||
mocks.resolveControlUiLinks.mockClear();
|
||||
|
|
|
|||
|
|
@ -5,45 +5,47 @@ import {
|
|||
createTypedHook,
|
||||
} from "../plugins/status.test-helpers.js";
|
||||
import * as noteModule from "../terminal/note.js";
|
||||
import { noteWorkspaceStatus } from "./doctor-workspace-status.js";
|
||||
|
||||
const resolveAgentWorkspaceDirMock = vi.fn();
|
||||
const resolveDefaultAgentIdMock = vi.fn();
|
||||
const buildWorkspaceSkillStatusMock = vi.fn();
|
||||
const buildPluginStatusReportMock = vi.fn();
|
||||
const buildPluginCompatibilityWarningsMock = vi.fn();
|
||||
const mocks = vi.hoisted(() => ({
|
||||
resolveAgentWorkspaceDir: vi.fn(),
|
||||
resolveDefaultAgentId: vi.fn(),
|
||||
buildWorkspaceSkillStatus: vi.fn(),
|
||||
buildPluginStatusReport: vi.fn(),
|
||||
buildPluginCompatibilityWarnings: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../agents/agent-scope.js", () => ({
|
||||
resolveAgentWorkspaceDir: (...args: unknown[]) => resolveAgentWorkspaceDirMock(...args),
|
||||
resolveDefaultAgentId: (...args: unknown[]) => resolveDefaultAgentIdMock(...args),
|
||||
resolveAgentWorkspaceDir: (...args: unknown[]) => mocks.resolveAgentWorkspaceDir(...args),
|
||||
resolveDefaultAgentId: (...args: unknown[]) => mocks.resolveDefaultAgentId(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../agents/skills-status.js", () => ({
|
||||
buildWorkspaceSkillStatus: (...args: unknown[]) => buildWorkspaceSkillStatusMock(...args),
|
||||
buildWorkspaceSkillStatus: (...args: unknown[]) => mocks.buildWorkspaceSkillStatus(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/status.js", () => ({
|
||||
buildPluginStatusReport: (...args: unknown[]) => buildPluginStatusReportMock(...args),
|
||||
buildPluginStatusReport: (...args: unknown[]) => mocks.buildPluginStatusReport(...args),
|
||||
buildPluginCompatibilityWarnings: (...args: unknown[]) =>
|
||||
buildPluginCompatibilityWarningsMock(...args),
|
||||
mocks.buildPluginCompatibilityWarnings(...args),
|
||||
}));
|
||||
|
||||
async function runNoteWorkspaceStatusForTest(
|
||||
loadResult: ReturnType<typeof createPluginLoadResult>,
|
||||
compatibilityWarnings: string[] = [],
|
||||
) {
|
||||
resolveDefaultAgentIdMock.mockReturnValue("default");
|
||||
resolveAgentWorkspaceDirMock.mockReturnValue("/workspace");
|
||||
buildWorkspaceSkillStatusMock.mockReturnValue({
|
||||
mocks.resolveDefaultAgentId.mockReturnValue("default");
|
||||
mocks.resolveAgentWorkspaceDir.mockReturnValue("/workspace");
|
||||
mocks.buildWorkspaceSkillStatus.mockReturnValue({
|
||||
skills: [],
|
||||
});
|
||||
buildPluginStatusReportMock.mockReturnValue({
|
||||
mocks.buildPluginStatusReport.mockReturnValue({
|
||||
workspaceDir: "/workspace",
|
||||
...loadResult,
|
||||
});
|
||||
buildPluginCompatibilityWarningsMock.mockReturnValue(compatibilityWarnings);
|
||||
mocks.buildPluginCompatibilityWarnings.mockReturnValue(compatibilityWarnings);
|
||||
|
||||
const noteSpy = vi.spyOn(noteModule, "note").mockImplementation(() => {});
|
||||
const { noteWorkspaceStatus } = await import("./doctor-workspace-status.js");
|
||||
noteWorkspaceStatus({});
|
||||
return noteSpy;
|
||||
}
|
||||
|
|
@ -65,7 +67,7 @@ describe("noteWorkspaceStatus", () => {
|
|||
}),
|
||||
);
|
||||
try {
|
||||
expect(buildPluginStatusReportMock).toHaveBeenCalledWith({
|
||||
expect(mocks.buildPluginStatusReport).toHaveBeenCalledWith({
|
||||
config: {},
|
||||
workspaceDir: "/workspace",
|
||||
});
|
||||
|
|
@ -138,7 +140,7 @@ describe("noteWorkspaceStatus", () => {
|
|||
"legacy-plugin still uses legacy before_agent_start",
|
||||
]);
|
||||
try {
|
||||
expect(buildPluginCompatibilityWarningsMock).toHaveBeenCalledWith({
|
||||
expect(mocks.buildPluginCompatibilityWarnings).toHaveBeenCalledWith({
|
||||
config: {},
|
||||
workspaceDir: "/workspace",
|
||||
report: {
|
||||
|
|
|
|||
|
|
@ -1,23 +1,19 @@
|
|||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
createDoctorRuntime,
|
||||
mockDoctorConfigSnapshot,
|
||||
runStartupMatrixMigration,
|
||||
} from "./doctor.e2e-harness.js";
|
||||
import "./doctor.fast-path-mocks.js";
|
||||
import { doctorCommand } from "./doctor.js";
|
||||
|
||||
vi.mock("../plugins/providers.runtime.js", () => ({
|
||||
resolvePluginProviders: vi.fn(() => []),
|
||||
}));
|
||||
|
||||
const DOCTOR_MIGRATION_TIMEOUT_MS = process.platform === "win32" ? 60_000 : 45_000;
|
||||
let doctorCommand: typeof import("./doctor.js").doctorCommand;
|
||||
|
||||
describe("doctor command", () => {
|
||||
beforeAll(async () => {
|
||||
({ doctorCommand } = await import("./doctor.js"));
|
||||
});
|
||||
|
||||
it(
|
||||
"runs Matrix startup migration during repair flows",
|
||||
{ timeout: DOCTOR_MIGRATION_TIMEOUT_MS },
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { maybeRepairAllowlistPolicyAllowFrom } from "./allowlist-policy-repair.js";
|
||||
|
||||
const { readChannelAllowFromStoreMock } = vi.hoisted(() => ({
|
||||
readChannelAllowFromStoreMock: vi.fn(),
|
||||
|
|
@ -8,12 +9,8 @@ vi.mock("../../../pairing/pairing-store.js", () => ({
|
|||
readChannelAllowFromStore: readChannelAllowFromStoreMock,
|
||||
}));
|
||||
|
||||
let maybeRepairAllowlistPolicyAllowFrom: typeof import("./allowlist-policy-repair.js").maybeRepairAllowlistPolicyAllowFrom;
|
||||
|
||||
describe("doctor allowlist-policy repair", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ maybeRepairAllowlistPolicyAllowFrom } = await import("./allowlist-policy-repair.js"));
|
||||
beforeEach(() => {
|
||||
readChannelAllowFromStoreMock.mockReset();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveGatewayInstallToken } from "./gateway-install-token.js";
|
||||
|
||||
const readConfigFileSnapshotMock = vi.hoisted(() => vi.fn());
|
||||
const replaceConfigFileMock = vi.hoisted(() => vi.fn());
|
||||
|
|
@ -57,8 +58,6 @@ vi.mock("./onboard-helpers.js", () => ({
|
|||
randomToken: randomTokenMock,
|
||||
}));
|
||||
|
||||
const { resolveGatewayInstallToken } = await import("./gateway-install-token.js");
|
||||
|
||||
describe("resolveGatewayInstallToken", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
|
|
|||
|
|
@ -3,147 +3,161 @@ import type { GatewayProbeResult } from "../gateway/probe.js";
|
|||
import type { GatewayBonjourBeacon } from "../infra/bonjour-discovery.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { withEnvAsync } from "../test-utils/env.js";
|
||||
import { gatewayStatusCommand } from "./gateway-status.js";
|
||||
|
||||
const readBestEffortConfig = vi.fn(async () => ({
|
||||
gateway: {
|
||||
mode: "remote",
|
||||
remote: { url: "wss://remote.example:18789", token: "rtok" },
|
||||
auth: { token: "ltok" },
|
||||
},
|
||||
}));
|
||||
const resolveGatewayPort = vi.fn((_cfg?: unknown) => 18789);
|
||||
const discoverGatewayBeacons = vi.fn(
|
||||
async (_opts?: unknown): Promise<GatewayBonjourBeacon[]> => [],
|
||||
);
|
||||
const pickPrimaryTailnetIPv4 = vi.fn(() => "100.64.0.10");
|
||||
const sshStop = vi.fn(async () => {});
|
||||
const resolveSshConfig = vi.fn(
|
||||
async (
|
||||
_opts?: unknown,
|
||||
): Promise<{
|
||||
user: string;
|
||||
host: string;
|
||||
port: number;
|
||||
identityFiles: string[];
|
||||
} | null> => null,
|
||||
);
|
||||
const startSshPortForward = vi.fn(async (_opts?: unknown) => ({
|
||||
parsedTarget: { user: "me", host: "studio", port: 22 },
|
||||
localPort: 18789,
|
||||
remotePort: 18789,
|
||||
pid: 123,
|
||||
stderr: [],
|
||||
stop: sshStop,
|
||||
}));
|
||||
const probeGateway = vi.fn(async (opts: { url: string }): Promise<GatewayProbeResult> => {
|
||||
const { url } = opts;
|
||||
if (url.includes("127.0.0.1")) {
|
||||
return {
|
||||
ok: true,
|
||||
url,
|
||||
connectLatencyMs: 12,
|
||||
error: null,
|
||||
close: null,
|
||||
health: { ok: true },
|
||||
status: {
|
||||
linkChannel: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
linked: false,
|
||||
authAgeMs: null,
|
||||
},
|
||||
sessions: { count: 0 },
|
||||
},
|
||||
presence: [
|
||||
{
|
||||
mode: "gateway",
|
||||
reason: "self",
|
||||
host: "local",
|
||||
ip: "127.0.0.1",
|
||||
text: "Gateway: local (127.0.0.1) · app test · mode gateway · reason self",
|
||||
ts: Date.now(),
|
||||
},
|
||||
],
|
||||
configSnapshot: {
|
||||
path: "/tmp/cfg.json",
|
||||
exists: true,
|
||||
valid: true,
|
||||
config: {
|
||||
gateway: { mode: "local" },
|
||||
},
|
||||
issues: [],
|
||||
legacyIssues: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
const mocks = vi.hoisted(() => {
|
||||
const sshStop = vi.fn(async () => {});
|
||||
return {
|
||||
ok: true,
|
||||
url,
|
||||
connectLatencyMs: 34,
|
||||
error: null,
|
||||
close: null,
|
||||
health: { ok: true },
|
||||
status: {
|
||||
linkChannel: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
linked: true,
|
||||
authAgeMs: 5_000,
|
||||
readBestEffortConfig: vi.fn(async () => ({
|
||||
gateway: {
|
||||
mode: "remote",
|
||||
remote: { url: "wss://remote.example:18789", token: "rtok" },
|
||||
auth: { token: "ltok" },
|
||||
},
|
||||
sessions: { count: 2 },
|
||||
},
|
||||
presence: [
|
||||
{
|
||||
mode: "gateway",
|
||||
reason: "self",
|
||||
host: "remote",
|
||||
ip: "100.64.0.2",
|
||||
text: "Gateway: remote (100.64.0.2) · app test · mode gateway · reason self",
|
||||
ts: Date.now(),
|
||||
},
|
||||
],
|
||||
configSnapshot: {
|
||||
path: "/tmp/remote.json",
|
||||
exists: true,
|
||||
valid: true,
|
||||
config: { gateway: { mode: "remote" } },
|
||||
issues: [],
|
||||
legacyIssues: [],
|
||||
},
|
||||
})),
|
||||
resolveGatewayPort: vi.fn((_cfg?: unknown) => 18789),
|
||||
discoverGatewayBeacons: vi.fn(async (_opts?: unknown): Promise<GatewayBonjourBeacon[]> => []),
|
||||
pickPrimaryTailnetIPv4: vi.fn(() => "100.64.0.10"),
|
||||
sshStop,
|
||||
resolveSshConfig: vi.fn(
|
||||
async (
|
||||
_opts?: unknown,
|
||||
): Promise<{
|
||||
user: string;
|
||||
host: string;
|
||||
port: number;
|
||||
identityFiles: string[];
|
||||
} | null> => null,
|
||||
),
|
||||
startSshPortForward: vi.fn(async (_opts?: unknown) => ({
|
||||
parsedTarget: { user: "me", host: "studio", port: 22 },
|
||||
localPort: 18789,
|
||||
remotePort: 18789,
|
||||
pid: 123,
|
||||
stderr: [],
|
||||
stop: sshStop,
|
||||
})),
|
||||
probeGateway: vi.fn(async (opts: { url: string }): Promise<GatewayProbeResult> => {
|
||||
const { url } = opts;
|
||||
if (url.includes("127.0.0.1")) {
|
||||
return {
|
||||
ok: true,
|
||||
url,
|
||||
connectLatencyMs: 12,
|
||||
error: null,
|
||||
close: null,
|
||||
health: { ok: true },
|
||||
status: {
|
||||
linkChannel: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
linked: false,
|
||||
authAgeMs: null,
|
||||
},
|
||||
sessions: { count: 0 },
|
||||
},
|
||||
presence: [
|
||||
{
|
||||
mode: "gateway",
|
||||
reason: "self",
|
||||
host: "local",
|
||||
ip: "127.0.0.1",
|
||||
text: "Gateway: local (127.0.0.1) · app test · mode gateway · reason self",
|
||||
ts: Date.now(),
|
||||
},
|
||||
],
|
||||
configSnapshot: {
|
||||
path: "/tmp/cfg.json",
|
||||
exists: true,
|
||||
valid: true,
|
||||
config: {
|
||||
gateway: { mode: "local" },
|
||||
},
|
||||
issues: [],
|
||||
legacyIssues: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
url,
|
||||
connectLatencyMs: 34,
|
||||
error: null,
|
||||
close: null,
|
||||
health: { ok: true },
|
||||
status: {
|
||||
linkChannel: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
linked: true,
|
||||
authAgeMs: 5_000,
|
||||
},
|
||||
sessions: { count: 2 },
|
||||
},
|
||||
presence: [
|
||||
{
|
||||
mode: "gateway",
|
||||
reason: "self",
|
||||
host: "remote",
|
||||
ip: "100.64.0.2",
|
||||
text: "Gateway: remote (100.64.0.2) · app test · mode gateway · reason self",
|
||||
ts: Date.now(),
|
||||
},
|
||||
],
|
||||
configSnapshot: {
|
||||
path: "/tmp/remote.json",
|
||||
exists: true,
|
||||
valid: true,
|
||||
config: { gateway: { mode: "remote" } },
|
||||
issues: [],
|
||||
legacyIssues: [],
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
const {
|
||||
readBestEffortConfig,
|
||||
resolveGatewayPort,
|
||||
discoverGatewayBeacons,
|
||||
pickPrimaryTailnetIPv4,
|
||||
sshStop,
|
||||
resolveSshConfig,
|
||||
startSshPortForward,
|
||||
probeGateway,
|
||||
} = mocks;
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
readBestEffortConfig: mocks.readBestEffortConfig,
|
||||
resolveGatewayPort: mocks.resolveGatewayPort,
|
||||
}));
|
||||
|
||||
vi.mock("../infra/bonjour-discovery.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../infra/bonjour-discovery.js")>();
|
||||
return {
|
||||
...actual,
|
||||
discoverGatewayBeacons,
|
||||
discoverGatewayBeacons: mocks.discoverGatewayBeacons,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../infra/tailnet.js", () => ({
|
||||
pickPrimaryTailnetIPv4,
|
||||
pickPrimaryTailnetIPv4: mocks.pickPrimaryTailnetIPv4,
|
||||
}));
|
||||
|
||||
vi.mock("../infra/ssh-tunnel.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../infra/ssh-tunnel.js")>();
|
||||
return {
|
||||
...actual,
|
||||
startSshPortForward,
|
||||
startSshPortForward: mocks.startSshPortForward,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../infra/ssh-config.js", () => ({
|
||||
resolveSshConfig,
|
||||
resolveSshConfig: mocks.resolveSshConfig,
|
||||
}));
|
||||
|
||||
vi.mock("../gateway/probe.js", () => ({
|
||||
probeGateway,
|
||||
probeGateway: mocks.probeGateway,
|
||||
}));
|
||||
|
||||
function createRuntimeCapture() {
|
||||
|
|
@ -194,7 +208,6 @@ async function runGatewayStatus(
|
|||
runtime: ReturnType<typeof createRuntimeCapture>["runtime"],
|
||||
opts: { timeout: string; json?: boolean; ssh?: string; sshAuto?: boolean; sshIdentity?: string },
|
||||
) {
|
||||
const { gatewayStatusCommand } = await import("./gateway-status.js");
|
||||
await gatewayStatusCommand(opts, asRuntimeEnv(runtime));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ type TelegramHealthAccount = {
|
|||
};
|
||||
|
||||
async function loadFreshHealthModulesForTest() {
|
||||
vi.resetModules();
|
||||
vi.doMock("../config/config.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { CliDeps } from "../cli/outbound-send-deps.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { messageCommand } from "./message.js";
|
||||
|
||||
let testConfig: Record<string, unknown> = {};
|
||||
|
||||
|
|
@ -57,9 +58,6 @@ describe("messageCommand agent routing", () => {
|
|||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
|
||||
const { messageCommand } = await import("./message.js");
|
||||
|
||||
await messageCommand(
|
||||
{
|
||||
action: "send",
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ let envSnapshot: ReturnType<typeof captureEnv>;
|
|||
const EMPTY_TEST_REGISTRY = createTestRegistry([]);
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ messageCommand } = await import("./message.js"));
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,6 @@ function installModelsListCommandForwardCompatMocks() {
|
|||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
installModelsListCommandForwardCompatMocks();
|
||||
({ modelsListCommand } = await import("./list.list-command.js"));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { loadValidConfigOrThrow, updateConfig } from "./shared.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
readConfigFileSnapshot: vi.fn(),
|
||||
|
|
@ -11,15 +12,10 @@ vi.mock("../../config/config.js", () => ({
|
|||
replaceConfigFile: (...args: unknown[]) => mocks.replaceConfigFile(...args),
|
||||
}));
|
||||
|
||||
let loadValidConfigOrThrow: typeof import("./shared.js").loadValidConfigOrThrow;
|
||||
let updateConfig: typeof import("./shared.js").updateConfig;
|
||||
|
||||
describe("models/shared", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
beforeEach(() => {
|
||||
mocks.readConfigFileSnapshot.mockClear();
|
||||
mocks.replaceConfigFile.mockClear();
|
||||
({ loadValidConfigOrThrow, updateConfig } = await import("./shared.js"));
|
||||
});
|
||||
|
||||
it("returns config when snapshot is valid", async () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import { installGatewayDaemonNonInteractive } from "./daemon-install.js";
|
||||
|
||||
const buildGatewayInstallPlan = vi.hoisted(() => vi.fn());
|
||||
const gatewayInstallErrorHint = vi.hoisted(() => vi.fn(() => "hint"));
|
||||
|
|
@ -36,8 +37,6 @@ vi.mock("../../systemd-linger.js", () => ({
|
|||
ensureSystemdUserLingerNonInteractive,
|
||||
}));
|
||||
|
||||
const { installGatewayDaemonNonInteractive } = await import("./daemon-install.js");
|
||||
|
||||
describe("installGatewayDaemonNonInteractive", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import type { OpenClawConfig } from "../config/config.js";
|
|||
import type { GatewayBonjourBeacon } from "../infra/bonjour-discovery.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||
import { promptRemoteGatewayConfig } from "./onboard-remote.js";
|
||||
import { createWizardPrompter } from "./test-wizard-helpers.js";
|
||||
|
||||
const discoverGatewayBeacons = vi.hoisted(() => vi.fn<() => Promise<GatewayBonjourBeacon[]>>());
|
||||
|
|
@ -25,8 +26,6 @@ vi.mock("./onboard-helpers.js", () => ({
|
|||
detectBinary,
|
||||
}));
|
||||
|
||||
const { promptRemoteGatewayConfig } = await import("./onboard-remote.js");
|
||||
|
||||
function createPrompter(overrides: Partial<WizardPrompter>): WizardPrompter {
|
||||
return createWizardPrompter(overrides, { defaultSelect: "" });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ describe("onboard-search provider resolution", () => {
|
|||
let mod: typeof import("./onboard-search.js");
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
mod = await import("./onboard-search.js");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { onboardCommand, setupWizardCommand } from "./onboard.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
runInteractiveSetup: vi.fn(async () => {}),
|
||||
|
|
@ -26,8 +27,6 @@ vi.mock("./onboard-helpers.js", () => ({
|
|||
handleReset: mocks.handleReset,
|
||||
}));
|
||||
|
||||
const { onboardCommand, setupWizardCommand } = await import("./onboard.js");
|
||||
|
||||
function makeRuntime(): RuntimeEnv {
|
||||
return {
|
||||
log: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createNonExitingRuntime } from "../runtime.js";
|
||||
|
||||
const resolveCleanupPlanFromDisk = vi.fn();
|
||||
const removePath = vi.fn();
|
||||
const listAgentSessionDirs = vi.fn();
|
||||
|
|
@ -22,10 +21,13 @@ vi.mock("./cleanup-utils.js", () => ({
|
|||
removeWorkspaceDirs,
|
||||
}));
|
||||
|
||||
const { resetCommand } = await import("./reset.js");
|
||||
|
||||
describe("resetCommand", () => {
|
||||
const runtime = createNonExitingRuntime();
|
||||
let resetCommand: typeof import("./reset.js").resetCommand;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ resetCommand } = await import("./reset.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { sandboxExplainCommand } from "./sandbox-explain.js";
|
||||
|
||||
const SANDBOX_EXPLAIN_TEST_TIMEOUT_MS = process.platform === "win32" ? 45_000 : 30_000;
|
||||
|
||||
|
|
@ -12,8 +13,6 @@ vi.mock("../config/config.js", async (importOriginal) => {
|
|||
};
|
||||
});
|
||||
|
||||
const { sandboxExplainCommand } = await import("./sandbox-explain.js");
|
||||
|
||||
describe("sandbox explain command", () => {
|
||||
it("prints JSON shape + fix-it keys", { timeout: SANDBOX_EXPLAIN_TEST_TIMEOUT_MS }, async () => {
|
||||
mockCfg = {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { statusJsonCommand } from "./status-json.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
scanStatusJsonFast: vi.fn(),
|
||||
|
|
@ -41,8 +42,6 @@ vi.mock("../infra/update-channels.js", () => ({
|
|||
resolveUpdateChannelDisplay: mocks.resolveUpdateChannelDisplay,
|
||||
}));
|
||||
|
||||
const { statusJsonCommand } = await import("./status-json.js");
|
||||
|
||||
function createRuntimeCapture() {
|
||||
const logs: string[] = [];
|
||||
const runtime: RuntimeEnv = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("../channels/config-presence.js", () => ({
|
||||
hasPotentialConfiguredChannels: vi.fn(() => true),
|
||||
|
|
@ -113,21 +113,20 @@ vi.mock("./status.link-channel.js", () => ({
|
|||
const { hasPotentialConfiguredChannels } = await import("../channels/config-presence.js");
|
||||
const { buildChannelSummary } = await import("../infra/channel-summary.js");
|
||||
const { resolveLinkChannelContext } = await import("./status.link-channel.js");
|
||||
|
||||
async function loadStatusSummaryForTest() {
|
||||
vi.resetModules();
|
||||
const { getStatusSummary } = await import("./status.summary.js");
|
||||
const { statusSummaryRuntime } = await import("./status.summary.runtime.js");
|
||||
return { getStatusSummary, statusSummaryRuntime };
|
||||
}
|
||||
let getStatusSummary: typeof import("./status.summary.js").getStatusSummary;
|
||||
let statusSummaryRuntime: typeof import("./status.summary.runtime.js").statusSummaryRuntime;
|
||||
|
||||
describe("getStatusSummary", () => {
|
||||
beforeAll(async () => {
|
||||
({ getStatusSummary } = await import("./status.summary.js"));
|
||||
({ statusSummaryRuntime } = await import("./status.summary.runtime.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("includes runtimeVersion in the status payload", async () => {
|
||||
const { getStatusSummary } = await loadStatusSummaryForTest();
|
||||
const summary = await getStatusSummary();
|
||||
|
||||
expect(summary.runtimeVersion).toBe("2026.3.8");
|
||||
|
|
@ -138,7 +137,6 @@ describe("getStatusSummary", () => {
|
|||
});
|
||||
|
||||
it("skips channel summary imports when no channels are configured", async () => {
|
||||
const { getStatusSummary } = await loadStatusSummaryForTest();
|
||||
vi.mocked(hasPotentialConfiguredChannels).mockReturnValue(false);
|
||||
|
||||
const summary = await getStatusSummary();
|
||||
|
|
@ -150,7 +148,6 @@ describe("getStatusSummary", () => {
|
|||
});
|
||||
|
||||
it("does not trigger async context warmup while building status summaries", async () => {
|
||||
const { getStatusSummary, statusSummaryRuntime } = await loadStatusSummaryForTest();
|
||||
await getStatusSummary();
|
||||
|
||||
expect(vi.mocked(statusSummaryRuntime.resolveContextTokensForModel)).toHaveBeenCalledWith(
|
||||
|
|
|
|||
|
|
@ -1,18 +1,41 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "../cli/test-runtime-capture.js";
|
||||
import {
|
||||
tasksAuditCommand,
|
||||
tasksCancelCommand,
|
||||
tasksListCommand,
|
||||
tasksMaintenanceCommand,
|
||||
tasksNotifyCommand,
|
||||
tasksShowCommand,
|
||||
} from "./tasks.js";
|
||||
|
||||
const reconcileInspectableTasksMock = vi.fn();
|
||||
const reconcileTaskLookupTokenMock = vi.fn();
|
||||
const listTaskAuditFindingsMock = vi.fn();
|
||||
const summarizeTaskAuditFindingsMock = vi.fn();
|
||||
const previewTaskRegistryMaintenanceMock = vi.fn();
|
||||
const runTaskRegistryMaintenanceMock = vi.fn();
|
||||
const getInspectableTaskRegistrySummaryMock = vi.fn();
|
||||
const getInspectableTaskAuditSummaryMock = vi.fn();
|
||||
const updateTaskNotifyPolicyByIdMock = vi.fn();
|
||||
const cancelTaskByIdMock = vi.fn();
|
||||
const getTaskByIdMock = vi.fn();
|
||||
const loadConfigMock = vi.fn(() => ({ loaded: true }));
|
||||
const mocks = vi.hoisted(() => ({
|
||||
reconcileInspectableTasksMock: vi.fn(),
|
||||
reconcileTaskLookupTokenMock: vi.fn(),
|
||||
listTaskAuditFindingsMock: vi.fn(),
|
||||
summarizeTaskAuditFindingsMock: vi.fn(),
|
||||
previewTaskRegistryMaintenanceMock: vi.fn(),
|
||||
runTaskRegistryMaintenanceMock: vi.fn(),
|
||||
getInspectableTaskRegistrySummaryMock: vi.fn(),
|
||||
getInspectableTaskAuditSummaryMock: vi.fn(),
|
||||
updateTaskNotifyPolicyByIdMock: vi.fn(),
|
||||
cancelTaskByIdMock: vi.fn(),
|
||||
getTaskByIdMock: vi.fn(),
|
||||
loadConfigMock: vi.fn(() => ({ loaded: true })),
|
||||
}));
|
||||
|
||||
const reconcileInspectableTasksMock = mocks.reconcileInspectableTasksMock;
|
||||
const reconcileTaskLookupTokenMock = mocks.reconcileTaskLookupTokenMock;
|
||||
const listTaskAuditFindingsMock = mocks.listTaskAuditFindingsMock;
|
||||
const summarizeTaskAuditFindingsMock = mocks.summarizeTaskAuditFindingsMock;
|
||||
const previewTaskRegistryMaintenanceMock = mocks.previewTaskRegistryMaintenanceMock;
|
||||
const runTaskRegistryMaintenanceMock = mocks.runTaskRegistryMaintenanceMock;
|
||||
const getInspectableTaskRegistrySummaryMock = mocks.getInspectableTaskRegistrySummaryMock;
|
||||
const getInspectableTaskAuditSummaryMock = mocks.getInspectableTaskAuditSummaryMock;
|
||||
const updateTaskNotifyPolicyByIdMock = mocks.updateTaskNotifyPolicyByIdMock;
|
||||
const cancelTaskByIdMock = mocks.cancelTaskByIdMock;
|
||||
const getTaskByIdMock = mocks.getTaskByIdMock;
|
||||
const loadConfigMock = mocks.loadConfigMock;
|
||||
|
||||
vi.mock("../tasks/task-registry.reconcile.js", () => ({
|
||||
reconcileInspectableTasks: (...args: unknown[]) => reconcileInspectableTasksMock(...args),
|
||||
|
|
@ -51,13 +74,6 @@ const {
|
|||
resetRuntimeCapture,
|
||||
} = createCliRuntimeCapture();
|
||||
|
||||
let tasksListCommand: typeof import("./tasks.js").tasksListCommand;
|
||||
let tasksShowCommand: typeof import("./tasks.js").tasksShowCommand;
|
||||
let tasksNotifyCommand: typeof import("./tasks.js").tasksNotifyCommand;
|
||||
let tasksCancelCommand: typeof import("./tasks.js").tasksCancelCommand;
|
||||
let tasksAuditCommand: typeof import("./tasks.js").tasksAuditCommand;
|
||||
let tasksMaintenanceCommand: typeof import("./tasks.js").tasksMaintenanceCommand;
|
||||
|
||||
const taskFixture = {
|
||||
taskId: "task-12345678",
|
||||
runtime: "acp",
|
||||
|
|
@ -74,17 +90,6 @@ const taskFixture = {
|
|||
progressSummary: "No output for 60s. It may be waiting for input.",
|
||||
} as const;
|
||||
|
||||
beforeAll(async () => {
|
||||
({
|
||||
tasksListCommand,
|
||||
tasksShowCommand,
|
||||
tasksNotifyCommand,
|
||||
tasksCancelCommand,
|
||||
tasksAuditCommand,
|
||||
tasksMaintenanceCommand,
|
||||
} = await import("./tasks.js"));
|
||||
});
|
||||
|
||||
describe("tasks commands", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
|
|
|||
Loading…
Reference in New Issue