test: tighten update cli post core assertions

This commit is contained in:
Peter Steinberger
2026-05-10 04:45:50 +01:00
parent 1f99cddb61
commit 71ebedee95
+50 -66
View File
@@ -380,6 +380,23 @@ describe("update-cli", () => {
return calls[index];
};
const syncPluginCall = (index = 0) => {
const calls = syncPluginsForUpdateChannel.mock.calls as unknown as Array<
[{ channel?: string; config?: OpenClawConfig }]
>;
return calls[index]?.[0];
};
const npmPluginUpdateCall = (index = 0) => {
const calls = updateNpmInstalledPlugins.mock.calls as unknown as Array<
[{ timeoutMs?: number }]
>;
return calls[index]?.[0];
};
const pluginWarning = (result?: UpdateRunResult) => result?.postUpdate?.plugins?.warnings?.[0];
const pluginOutcome = (result?: UpdateRunResult) => result?.postUpdate?.plugins?.npm.outcomes[0];
const expectPackageInstallSpec = (spec: string) => {
expect(runGatewayUpdate).not.toHaveBeenCalled();
const call = (
@@ -799,18 +816,13 @@ describe("update-cli", () => {
await updateCommand({ channel: "dev", yes: true, restart: false });
expect(spawn).toHaveBeenCalledWith(
expect.stringMatching(/node/),
[entrypoints[0], "update", "--no-restart", "--yes"],
expect.objectContaining({
stdio: "inherit",
env: expect.objectContaining({
OPENCLAW_UPDATE_POST_CORE: "1",
OPENCLAW_UPDATE_POST_CORE_CHANNEL: "dev",
OPENCLAW_UPDATE_POST_CORE_REQUESTED_CHANNEL: "dev",
}),
}),
);
const call = spawnCall();
expect(call?.[0]).toMatch(/node/);
expect(call?.[1]).toEqual([entrypoints[0], "update", "--no-restart", "--yes"]);
expect(call?.[2]?.stdio).toBe("inherit");
expect(call?.[2]?.env?.OPENCLAW_UPDATE_POST_CORE).toBe("1");
expect(call?.[2]?.env?.OPENCLAW_UPDATE_POST_CORE_CHANNEL).toBe("dev");
expect(call?.[2]?.env?.OPENCLAW_UPDATE_POST_CORE_REQUESTED_CHANNEL).toBe("dev");
expect(replaceConfigFile).not.toHaveBeenCalled();
expect(syncPluginsForUpdateChannel).not.toHaveBeenCalled();
expect(updateNpmInstalledPlugins).not.toHaveBeenCalled();
@@ -891,10 +903,10 @@ describe("update-cli", () => {
);
expect(runGatewayUpdate).not.toHaveBeenCalled();
expect(runCommandWithTimeout).not.toHaveBeenCalledWith(
["npm", "i", "-g", expect.any(String)],
expect.anything(),
);
const installCall = (
vi.mocked(runCommandWithTimeout).mock.calls as unknown as Array<[string[], unknown]>
).find(([argv]) => argv[0] === "npm" && argv[1] === "i" && argv[2] === "-g");
expect(installCall).toBeUndefined();
expect(defaultRuntime.exit).toHaveBeenCalledWith(0);
expect(syncPluginsForUpdateChannel).toHaveBeenCalledTimes(1);
expect(updateNpmInstalledPlugins).toHaveBeenCalledTimes(1);
@@ -999,14 +1011,8 @@ describe("update-cli", () => {
},
baseHash: "stable-hash",
});
expect(syncPluginsForUpdateChannel).toHaveBeenCalledWith(
expect.objectContaining({
channel: "dev",
config: expect.objectContaining({
update: expect.objectContaining({ channel: "dev" }),
}),
}),
);
expect(syncPluginCall()?.channel).toBe("dev");
expect(syncPluginCall()?.config?.update?.channel).toBe("dev");
});
it("post-core resume mode retries update channel persistence after config hash drift", async () => {
@@ -1071,14 +1077,8 @@ describe("update-cli", () => {
},
baseHash: "newer-hash",
});
expect(syncPluginsForUpdateChannel).toHaveBeenCalledWith(
expect.objectContaining({
config: expect.objectContaining({
meta: expect.objectContaining({ lastTouchedVersion: "2026.4.30" }),
update: expect.objectContaining({ channel: "dev" }),
}),
}),
);
expect(syncPluginCall()?.config?.meta?.lastTouchedVersion).toBe("2026.4.30");
expect(syncPluginCall()?.config?.update?.channel).toBe("dev");
});
it("passes the update timeout budget into post-core plugin updates", async () => {
@@ -1092,9 +1092,7 @@ describe("update-cli", () => {
},
);
expect(updateNpmInstalledPlugins).toHaveBeenCalledWith(
expect.objectContaining({ timeoutMs: 1_800_000 }),
);
expect(npmPluginUpdateCall()?.timeoutMs).toBe(1_800_000);
});
it("uses a fail-closed integrity policy for post-core plugin updates", async () => {
@@ -1200,16 +1198,12 @@ describe("update-cli", () => {
},
]);
expect(jsonOutput?.postUpdate?.plugins?.status).toBe("warning");
expect(jsonOutput?.postUpdate?.plugins?.warnings?.[0]).toMatchObject({
pluginId: "demo",
guidance: [
"Run openclaw doctor --fix to attempt automatic repair.",
"Run openclaw plugins inspect demo --runtime --json for details.",
],
});
expect(jsonOutput?.postUpdate?.plugins?.warnings?.[0]?.reason).toContain(
"npm package integrity drift",
);
expect(pluginWarning(jsonOutput)?.pluginId).toBe("demo");
expect(pluginWarning(jsonOutput)?.guidance).toEqual([
"Run openclaw doctor --fix to attempt automatic repair.",
"Run openclaw plugins inspect demo --runtime --json for details.",
]);
expect(pluginWarning(jsonOutput)?.reason).toContain("npm package integrity drift");
expect(jsonOutput?.postUpdate?.plugins?.npm.outcomes[0]?.status).toBe("error");
expect(jsonOutput?.postUpdate?.plugins?.npm.outcomes[0]?.message).toContain(
"Run openclaw doctor --fix to attempt automatic repair.",
@@ -1268,16 +1262,10 @@ describe("update-cli", () => {
| undefined;
expect(jsonOutput?.status).toBe("ok");
expect(jsonOutput?.postUpdate?.plugins?.status).toBe("warning");
expect(jsonOutput?.postUpdate?.plugins?.warnings?.[0]).toMatchObject({
pluginId: "demo",
});
expect(jsonOutput?.postUpdate?.plugins?.warnings?.[0]?.reason).toContain(
"package.json is missing",
);
expect(jsonOutput?.postUpdate?.plugins?.npm.outcomes[0]).toMatchObject({
pluginId: "demo",
status: "error",
});
expect(pluginWarning(jsonOutput)?.pluginId).toBe("demo");
expect(pluginWarning(jsonOutput)?.reason).toContain("package.json is missing");
expect(pluginOutcome(jsonOutput)?.pluginId).toBe("demo");
expect(pluginOutcome(jsonOutput)?.status).toBe("error");
});
it("prints non-fatal plugin warnings in human update output", async () => {
@@ -1335,17 +1323,13 @@ describe("update-cli", () => {
| UpdateRunResult
| undefined;
expect(jsonOutput?.postUpdate?.plugins?.status).toBe("warning");
expect(jsonOutput?.postUpdate?.plugins?.warnings?.[0]).toMatchObject({
pluginId: "demo",
guidance: [
"Run openclaw doctor --fix to attempt automatic repair.",
"Run openclaw plugins inspect demo --runtime --json for details.",
],
});
expect(jsonOutput?.postUpdate?.plugins?.npm.outcomes[0]).toMatchObject({
pluginId: "demo",
status: "skipped",
});
expect(pluginWarning(jsonOutput)?.pluginId).toBe("demo");
expect(pluginWarning(jsonOutput)?.guidance).toEqual([
"Run openclaw doctor --fix to attempt automatic repair.",
"Run openclaw plugins inspect demo --runtime --json for details.",
]);
expect(pluginOutcome(jsonOutput)?.pluginId).toBe("demo");
expect(pluginOutcome(jsonOutput)?.status).toBe("skipped");
});
it("fails unexpected post-core plugin sync exceptions", async () => {