rowboat/apps/cli/test/server.test.mjs
nocxcloud-oss 4239f9f1ef strengthen repo verification and runtime coverage
Add clearer app docs plus targeted desktop, CLI, web, and worker tests so cross-surface regressions are caught earlier and the repo is easier to navigate.
2026-04-15 19:10:41 +08:00

131 lines
3.8 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { createApp } from "../dist/server.js";
test("message endpoint creates a message and returns its id", async () => {
const calls = [];
const app = createApp({
createMessage: async (runId, message) => {
calls.push({ runId, message });
return "msg-123";
},
authorizePermission: async () => {},
replyToHumanInputRequest: async () => {},
stop: async () => {},
subscribeToEvents: async () => () => {},
});
const response = await app.request("/runs/run-1/messages/new", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ message: "hello" }),
});
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), { messageId: "msg-123" });
assert.deepEqual(calls, [{ runId: "run-1", message: "hello" }]);
});
test("permission endpoint validates payload and calls dependency", async () => {
const calls = [];
const app = createApp({
createMessage: async () => "unused",
authorizePermission: async (runId, payload) => {
calls.push({ runId, payload });
},
replyToHumanInputRequest: async () => {},
stop: async () => {},
subscribeToEvents: async () => () => {},
});
const response = await app.request("/runs/run-2/permissions/authorize", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
subflow: ["child"],
toolCallId: "tool-1",
response: "approve",
}),
});
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), { success: true });
assert.deepEqual(calls, [{
runId: "run-2",
payload: {
subflow: ["child"],
toolCallId: "tool-1",
response: "approve",
},
}]);
});
test("invalid message payload returns a validation error", async () => {
const app = createApp({
createMessage: async () => "unused",
authorizePermission: async () => {},
replyToHumanInputRequest: async () => {},
stop: async () => {},
subscribeToEvents: async () => () => {},
});
const response = await app.request("/runs/run-1/messages/new", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({}),
});
assert.equal(response.status, 400);
});
test("openapi endpoint is exposed", async () => {
const app = createApp({
createMessage: async () => "unused",
authorizePermission: async () => {},
replyToHumanInputRequest: async () => {},
stop: async () => {},
subscribeToEvents: async () => () => {},
});
const response = await app.request("/openapi.json");
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(body.info.title, "Hono");
assert.ok(body.paths["/runs/{runId}/messages/new"]);
});
test("stream endpoint emits SSE payloads and unsubscribes on cancel", async () => {
let listener;
let unsubscribed = false;
const app = createApp({
createMessage: async () => "unused",
authorizePermission: async () => {},
replyToHumanInputRequest: async () => {},
stop: async () => {},
subscribeToEvents: async (fn) => {
listener = fn;
return () => {
unsubscribed = true;
};
},
});
const response = await app.request("/stream");
assert.equal(response.status, 200);
assert.equal(response.headers.get("content-type"), "text/event-stream");
await listener({ type: "message", data: { hello: "world" } });
const reader = response.body.getReader();
const chunk = await reader.read();
const text = new TextDecoder().decode(chunk.value);
assert.match(text, /event: message/);
assert.match(text, /"hello":"world"/);
await reader.cancel();
await new Promise((resolve) => setTimeout(resolve, 0));
assert.equal(unsubscribed, true);
});