test: dedupe gateway browser discord and channel coverage

This commit is contained in:
Peter Steinberger
2026-02-22 17:11:42 +00:00
parent 34ea33f057
commit 296b19e413
29 changed files with 938 additions and 1041 deletions

View File

@@ -21,6 +21,54 @@ let gatewayPort: number;
const gatewayToken = "test-token";
let envSnapshot: ReturnType<typeof captureEnv>;
type SessionSendTool = ReturnType<typeof createOpenClawTools>[number];
function getSessionsSendTool(): SessionSendTool {
const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send");
if (!tool) {
throw new Error("missing sessions_send tool");
}
return tool;
}
async function emitLifecycleAssistantReply(params: {
opts: unknown;
defaultSessionId: string;
includeTimestamp?: boolean;
resolveText: (extraSystemPrompt?: string) => string;
}) {
const commandParams = params.opts as {
sessionId?: string;
runId?: string;
extraSystemPrompt?: string;
};
const sessionId = commandParams.sessionId ?? params.defaultSessionId;
const runId = commandParams.runId ?? sessionId;
const sessionFile = resolveSessionTranscriptPath(sessionId);
await fs.mkdir(path.dirname(sessionFile), { recursive: true });
const startedAt = Date.now();
emitAgentEvent({
runId,
stream: "lifecycle",
data: { phase: "start", startedAt },
});
const text = params.resolveText(commandParams.extraSystemPrompt);
const message = {
role: "assistant",
content: [{ type: "text", text }],
...(params.includeTimestamp ? { timestamp: Date.now() } : {}),
};
await fs.appendFile(sessionFile, `${JSON.stringify({ message })}\n`, "utf8");
emitAgentEvent({
runId,
stream: "lifecycle",
data: { phase: "end", startedAt, endedAt: Date.now() },
});
}
beforeAll(async () => {
envSnapshot = captureEnv(["OPENCLAW_GATEWAY_PORT", "OPENCLAW_GATEWAY_TOKEN"]);
gatewayPort = await getFreePort();
@@ -52,52 +100,24 @@ afterAll(async () => {
describe("sessions_send gateway loopback", () => {
it("returns reply when lifecycle ends before agent.wait", async () => {
const spy = agentCommand as unknown as Mock<(opts: unknown) => Promise<void>>;
spy.mockImplementation(async (opts: unknown) => {
const params = opts as {
sessionId?: string;
runId?: string;
extraSystemPrompt?: string;
};
const sessionId = params.sessionId ?? "main";
const runId = params.runId ?? sessionId;
const sessionFile = resolveSessionTranscriptPath(sessionId);
await fs.mkdir(path.dirname(sessionFile), { recursive: true });
const startedAt = Date.now();
emitAgentEvent({
runId,
stream: "lifecycle",
data: { phase: "start", startedAt },
});
let text = "pong";
if (params.extraSystemPrompt?.includes("Agent-to-agent reply step")) {
text = "REPLY_SKIP";
} else if (params.extraSystemPrompt?.includes("Agent-to-agent announce step")) {
text = "ANNOUNCE_SKIP";
}
const message = {
role: "assistant",
content: [{ type: "text", text }],
timestamp: Date.now(),
};
await fs.appendFile(sessionFile, `${JSON.stringify({ message })}\n`, "utf8");
emitAgentEvent({
runId,
stream: "lifecycle",
data: {
phase: "end",
startedAt,
endedAt: Date.now(),
spy.mockImplementation(async (opts: unknown) =>
emitLifecycleAssistantReply({
opts,
defaultSessionId: "main",
includeTimestamp: true,
resolveText: (extraSystemPrompt) => {
if (extraSystemPrompt?.includes("Agent-to-agent reply step")) {
return "REPLY_SKIP";
}
if (extraSystemPrompt?.includes("Agent-to-agent announce step")) {
return "ANNOUNCE_SKIP";
}
return "pong";
},
});
});
}),
);
const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send");
if (!tool) {
throw new Error("missing sessions_send tool");
}
const tool = getSessionsSendTool();
const result = await tool.execute("call-loopback", {
sessionKey: "main",
@@ -139,37 +159,13 @@ describe("sessions_send label lookup", () => {
);
const spy = agentCommand as unknown as Mock<(opts: unknown) => Promise<void>>;
spy.mockImplementation(async (opts: unknown) => {
const params = opts as {
sessionId?: string;
runId?: string;
extraSystemPrompt?: string;
};
const sessionId = params.sessionId ?? "test-labeled";
const runId = params.runId ?? sessionId;
const sessionFile = resolveSessionTranscriptPath(sessionId);
await fs.mkdir(path.dirname(sessionFile), { recursive: true });
const startedAt = Date.now();
emitAgentEvent({
runId,
stream: "lifecycle",
data: { phase: "start", startedAt },
});
const text = "labeled response";
const message = {
role: "assistant",
content: [{ type: "text", text }],
};
await fs.appendFile(sessionFile, `${JSON.stringify({ message })}\n`, "utf8");
emitAgentEvent({
runId,
stream: "lifecycle",
data: { phase: "end", startedAt, endedAt: Date.now() },
});
});
spy.mockImplementation(async (opts: unknown) =>
emitLifecycleAssistantReply({
opts,
defaultSessionId: "test-labeled",
resolveText: () => "labeled response",
}),
);
// First, create a session with a label via sessions.patch
const { callGateway } = await import("./call.js");
@@ -179,10 +175,7 @@ describe("sessions_send label lookup", () => {
timeoutMs: 5000,
});
const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send");
if (!tool) {
throw new Error("missing sessions_send tool");
}
const tool = getSessionsSendTool();
// Send using label instead of sessionKey
const result = await tool.execute("call-by-label", {
@@ -201,10 +194,7 @@ describe("sessions_send label lookup", () => {
});
it("returns error when label not found", { timeout: 60_000 }, async () => {
const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send");
if (!tool) {
throw new Error("missing sessions_send tool");
}
const tool = getSessionsSendTool();
const result = await tool.execute("call-missing-label", {
label: "nonexistent-label",
@@ -217,10 +207,7 @@ describe("sessions_send label lookup", () => {
});
it("returns error when neither sessionKey nor label provided", { timeout: 60_000 }, async () => {
const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send");
if (!tool) {
throw new Error("missing sessions_send tool");
}
const tool = getSessionsSendTool();
const result = await tool.execute("call-no-key", {
message: "hello",