test(cli): dedupe config-guard harness and cover invalid-config gates

This commit is contained in:
Peter Steinberger
2026-02-21 20:04:13 +00:00
parent 4503bd0591
commit 6de7f9d9b0

View File

@@ -29,10 +29,26 @@ function makeRuntime() {
}
describe("ensureConfigReady", () => {
async function runEnsureConfigReady(commandPath: string[]) {
async function loadEnsureConfigReady() {
vi.resetModules();
const { ensureConfigReady } = await import("./config-guard.js");
await ensureConfigReady({ runtime: makeRuntime() as never, commandPath });
return await import("./config-guard.js");
}
async function runEnsureConfigReady(commandPath: string[]) {
const runtime = makeRuntime();
const { ensureConfigReady } = await loadEnsureConfigReady();
await ensureConfigReady({ runtime: runtime as never, commandPath });
return runtime;
}
function setInvalidSnapshot(overrides?: Partial<ReturnType<typeof makeSnapshot>>) {
readConfigFileSnapshotMock.mockResolvedValue({
...makeSnapshot(),
exists: true,
valid: false,
issues: [{ path: "channels.whatsapp", message: "invalid" }],
...overrides,
});
}
beforeEach(() => {
@@ -55,4 +71,33 @@ describe("ensureConfigReady", () => {
await runEnsureConfigReady(commandPath);
expect(loadAndMaybeMigrateDoctorConfigMock).toHaveBeenCalledTimes(expectedDoctorCalls);
});
it("exits for invalid config on non-allowlisted commands", async () => {
setInvalidSnapshot();
const runtime = await runEnsureConfigReady(["message"]);
expect(runtime.error).toHaveBeenCalledWith(expect.stringContaining("Config invalid"));
expect(runtime.error).toHaveBeenCalledWith(expect.stringContaining("doctor --fix"));
expect(runtime.exit).toHaveBeenCalledWith(1);
});
it("does not exit for invalid config on allowlisted commands", async () => {
setInvalidSnapshot();
const statusRuntime = await runEnsureConfigReady(["status"]);
expect(statusRuntime.exit).not.toHaveBeenCalled();
const gatewayRuntime = await runEnsureConfigReady(["gateway", "health"]);
expect(gatewayRuntime.exit).not.toHaveBeenCalled();
});
it("runs doctor migration flow only once per module instance", async () => {
const runtimeA = makeRuntime();
const runtimeB = makeRuntime();
const { ensureConfigReady } = await loadEnsureConfigReady();
await ensureConfigReady({ runtime: runtimeA as never, commandPath: ["message"] });
await ensureConfigReady({ runtime: runtimeB as never, commandPath: ["message"] });
expect(loadAndMaybeMigrateDoctorConfigMock).toHaveBeenCalledTimes(1);
});
});