mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 07:50:43 +00:00
test: tighten small tool assertions
This commit is contained in:
@@ -3,6 +3,18 @@ import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
|
||||
const loadConfigMock = vi.fn<() => OpenClawConfig>();
|
||||
|
||||
type AgentListDetails = {
|
||||
requester?: string;
|
||||
allowAny?: boolean;
|
||||
agents?: Array<{
|
||||
id?: string;
|
||||
name?: string;
|
||||
configured?: boolean;
|
||||
model?: string;
|
||||
agentRuntime?: { id?: string; source?: string };
|
||||
}>;
|
||||
};
|
||||
|
||||
vi.mock("../../config/config.js", async () => {
|
||||
const actual =
|
||||
await vi.importActual<typeof import("../../config/config.js")>("../../config/config.js");
|
||||
@@ -46,19 +58,16 @@ describe("agents_list tool", () => {
|
||||
"call",
|
||||
{},
|
||||
);
|
||||
const details = result.details as AgentListDetails;
|
||||
|
||||
expect(result.details).toMatchObject({
|
||||
requester: "main",
|
||||
agents: [
|
||||
{
|
||||
id: "codex",
|
||||
name: "Codex",
|
||||
configured: true,
|
||||
model: "openai/gpt-5.5",
|
||||
agentRuntime: { id: "codex", source: "model" },
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(details.requester).toBe("main");
|
||||
expect(details.agents).toHaveLength(1);
|
||||
expect(details.agents?.[0]?.id).toBe("codex");
|
||||
expect(details.agents?.[0]?.name).toBe("Codex");
|
||||
expect(details.agents?.[0]?.configured).toBe(true);
|
||||
expect(details.agents?.[0]?.model).toBe("openai/gpt-5.5");
|
||||
expect(details.agents?.[0]?.agentRuntime?.id).toBe("codex");
|
||||
expect(details.agents?.[0]?.agentRuntime?.source).toBe("model");
|
||||
});
|
||||
|
||||
it("returns requester as the only target when no subagent allowlist is configured", async () => {
|
||||
@@ -73,17 +82,13 @@ describe("agents_list tool", () => {
|
||||
"call",
|
||||
{},
|
||||
);
|
||||
const details = result.details as AgentListDetails;
|
||||
|
||||
expect(result.details).toMatchObject({
|
||||
requester: "main",
|
||||
allowAny: false,
|
||||
agents: [
|
||||
{
|
||||
id: "main",
|
||||
configured: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(details.requester).toBe("main");
|
||||
expect(details.allowAny).toBe(false);
|
||||
expect(details.agents).toHaveLength(1);
|
||||
expect(details.agents?.[0]?.id).toBe("main");
|
||||
expect(details.agents?.[0]?.configured).toBe(true);
|
||||
});
|
||||
|
||||
it("ignores legacy env-forced plugin runtime selections", async () => {
|
||||
@@ -102,15 +107,12 @@ describe("agents_list tool", () => {
|
||||
"call",
|
||||
{},
|
||||
);
|
||||
const details = result.details as AgentListDetails;
|
||||
|
||||
expect(result.details).toMatchObject({
|
||||
agents: [
|
||||
{
|
||||
id: "main",
|
||||
agentRuntime: { id: "codex", source: "implicit" },
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(details.agents).toHaveLength(1);
|
||||
expect(details.agents?.[0]?.id).toBe("main");
|
||||
expect(details.agents?.[0]?.agentRuntime?.id).toBe("codex");
|
||||
expect(details.agents?.[0]?.agentRuntime?.source).toBe("implicit");
|
||||
});
|
||||
|
||||
it("ignores legacy per-agent runtime overrides", async () => {
|
||||
@@ -132,14 +134,11 @@ describe("agents_list tool", () => {
|
||||
"call",
|
||||
{},
|
||||
);
|
||||
const details = result.details as AgentListDetails;
|
||||
|
||||
expect(result.details).toMatchObject({
|
||||
agents: [
|
||||
{
|
||||
id: "strict",
|
||||
agentRuntime: { id: "codex", source: "implicit" },
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(details.agents).toHaveLength(1);
|
||||
expect(details.agents?.[0]?.id).toBe("strict");
|
||||
expect(details.agents?.[0]?.agentRuntime?.id).toBe("codex");
|
||||
expect(details.agents?.[0]?.agentRuntime?.source).toBe("implicit");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,6 +11,16 @@ function readSchemaProperty(schema: unknown, key: string): Record<string, unknow
|
||||
return property as Record<string, unknown>;
|
||||
}
|
||||
|
||||
type HeartbeatResponseDetails = {
|
||||
status?: string;
|
||||
outcome?: string;
|
||||
notify?: boolean;
|
||||
summary?: string;
|
||||
notificationText?: string;
|
||||
priority?: string;
|
||||
nextCheck?: string;
|
||||
};
|
||||
|
||||
describe("createHeartbeatResponseTool", () => {
|
||||
it("uses flat enum schemas for provider portability", () => {
|
||||
const tool = createHeartbeatResponseTool();
|
||||
@@ -18,14 +28,10 @@ describe("createHeartbeatResponseTool", () => {
|
||||
const outcome = readSchemaProperty(tool.parameters, "outcome");
|
||||
const priority = readSchemaProperty(tool.parameters, "priority");
|
||||
|
||||
expect(outcome).toMatchObject({
|
||||
type: "string",
|
||||
enum: ["no_change", "progress", "done", "blocked", "needs_attention"],
|
||||
});
|
||||
expect(priority).toMatchObject({
|
||||
type: "string",
|
||||
enum: ["low", "normal", "high"],
|
||||
});
|
||||
expect(outcome.type).toBe("string");
|
||||
expect(outcome.enum).toEqual(["no_change", "progress", "done", "blocked", "needs_attention"]);
|
||||
expect(priority.type).toBe("string");
|
||||
expect(priority.enum).toEqual(["low", "normal", "high"]);
|
||||
expect(outcome).not.toHaveProperty("anyOf");
|
||||
expect(priority).not.toHaveProperty("anyOf");
|
||||
});
|
||||
@@ -40,12 +46,11 @@ describe("createHeartbeatResponseTool", () => {
|
||||
});
|
||||
|
||||
expect(tool.name).toBe(HEARTBEAT_RESPONSE_TOOL_NAME);
|
||||
expect(result.details).toMatchObject({
|
||||
status: "recorded",
|
||||
outcome: "no_change",
|
||||
notify: false,
|
||||
summary: "Nothing needs attention.",
|
||||
});
|
||||
const details = result.details as HeartbeatResponseDetails;
|
||||
expect(details.status).toBe("recorded");
|
||||
expect(details.outcome).toBe("no_change");
|
||||
expect(details.notify).toBe(false);
|
||||
expect(details.summary).toBe("Nothing needs attention.");
|
||||
});
|
||||
|
||||
it("accepts notification text and optional scheduling metadata", async () => {
|
||||
@@ -60,15 +65,14 @@ describe("createHeartbeatResponseTool", () => {
|
||||
nextCheck: "2026-05-01T17:00:00Z",
|
||||
});
|
||||
|
||||
expect(result.details).toMatchObject({
|
||||
status: "recorded",
|
||||
outcome: "needs_attention",
|
||||
notify: true,
|
||||
summary: "Build is blocked.",
|
||||
notificationText: "Build is blocked on missing credentials.",
|
||||
priority: "high",
|
||||
nextCheck: "2026-05-01T17:00:00Z",
|
||||
});
|
||||
const details = result.details as HeartbeatResponseDetails;
|
||||
expect(details.status).toBe("recorded");
|
||||
expect(details.outcome).toBe("needs_attention");
|
||||
expect(details.notify).toBe(true);
|
||||
expect(details.summary).toBe("Build is blocked.");
|
||||
expect(details.notificationText).toBe("Build is blocked on missing credentials.");
|
||||
expect(details.priority).toBe("high");
|
||||
expect(details.nextCheck).toBe("2026-05-01T17:00:00Z");
|
||||
});
|
||||
|
||||
it("rejects missing notify because quiet vs visible delivery must be explicit", async () => {
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createSessionsYieldTool } from "./sessions-yield-tool.js";
|
||||
|
||||
type SessionsYieldDetails = {
|
||||
status?: string;
|
||||
message?: string;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
describe("sessions_yield tool", () => {
|
||||
it("returns error when no sessionId is provided", async () => {
|
||||
const onYield = vi.fn();
|
||||
const tool = createSessionsYieldTool({ onYield });
|
||||
const result = await tool.execute("call-1", {});
|
||||
expect(result.details).toMatchObject({
|
||||
status: "error",
|
||||
error: "No session context",
|
||||
});
|
||||
const details = result.details as SessionsYieldDetails;
|
||||
expect(details.status).toBe("error");
|
||||
expect(details.error).toBe("No session context");
|
||||
expect(onYield).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -17,7 +22,9 @@ describe("sessions_yield tool", () => {
|
||||
const onYield = vi.fn();
|
||||
const tool = createSessionsYieldTool({ sessionId: "test-session", onYield });
|
||||
const result = await tool.execute("call-1", {});
|
||||
expect(result.details).toMatchObject({ status: "yielded", message: "Turn yielded." });
|
||||
const details = result.details as SessionsYieldDetails;
|
||||
expect(details.status).toBe("yielded");
|
||||
expect(details.message).toBe("Turn yielded.");
|
||||
expect(onYield).toHaveBeenCalledOnce();
|
||||
expect(onYield).toHaveBeenCalledWith("Turn yielded.");
|
||||
});
|
||||
@@ -26,10 +33,9 @@ describe("sessions_yield tool", () => {
|
||||
const onYield = vi.fn();
|
||||
const tool = createSessionsYieldTool({ sessionId: "test-session", onYield });
|
||||
const result = await tool.execute("call-1", { message: "Waiting for fact-checker" });
|
||||
expect(result.details).toMatchObject({
|
||||
status: "yielded",
|
||||
message: "Waiting for fact-checker",
|
||||
});
|
||||
const details = result.details as SessionsYieldDetails;
|
||||
expect(details.status).toBe("yielded");
|
||||
expect(details.message).toBe("Waiting for fact-checker");
|
||||
expect(onYield).toHaveBeenCalledOnce();
|
||||
expect(onYield).toHaveBeenCalledWith("Waiting for fact-checker");
|
||||
});
|
||||
@@ -37,9 +43,8 @@ describe("sessions_yield tool", () => {
|
||||
it("returns error without onYield callback", async () => {
|
||||
const tool = createSessionsYieldTool({ sessionId: "test-session" });
|
||||
const result = await tool.execute("call-1", {});
|
||||
expect(result.details).toMatchObject({
|
||||
status: "error",
|
||||
error: "Yield not supported in this context",
|
||||
});
|
||||
const details = result.details as SessionsYieldDetails;
|
||||
expect(details.status).toBe("error");
|
||||
expect(details.error).toBe("Yield not supported in this context");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user