mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-20 16:42:25 +00:00
Let WebUI users configure the single web search provider credential from BYOK while keeping saved secrets masked and hot-reloaded for new searches. Co-authored-by: Cursor <cursoragent@cursor.com>
158 lines
4.2 KiB
TypeScript
158 lines
4.2 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import {
|
|
deleteSession,
|
|
fetchSessionMessages,
|
|
listSessions,
|
|
listSlashCommands,
|
|
updateProviderSettings,
|
|
updateSettings,
|
|
updateWebSearchSettings,
|
|
} from "@/lib/api";
|
|
|
|
describe("webui API helpers", () => {
|
|
beforeEach(() => {
|
|
vi.stubGlobal(
|
|
"fetch",
|
|
vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
json: async () => ({ deleted: true, key: "websocket:chat-1", messages: [] }),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("percent-encodes websocket keys when fetching session history", async () => {
|
|
await fetchSessionMessages("tok", "websocket:chat-1");
|
|
|
|
expect(fetch).toHaveBeenCalledWith(
|
|
"/api/sessions/websocket%3Achat-1/messages",
|
|
expect.objectContaining({
|
|
headers: { Authorization: "Bearer tok" },
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("percent-encodes websocket keys when deleting a session", async () => {
|
|
await deleteSession("tok", "websocket:chat-1");
|
|
|
|
expect(fetch).toHaveBeenCalledWith(
|
|
"/api/sessions/websocket%3Achat-1/delete",
|
|
expect.objectContaining({
|
|
headers: { Authorization: "Bearer tok" },
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("serializes settings updates as a narrow query string", async () => {
|
|
await updateSettings("tok", {
|
|
model: "openrouter/test",
|
|
provider: "openrouter",
|
|
});
|
|
|
|
expect(fetch).toHaveBeenCalledWith(
|
|
"/api/settings/update?model=openrouter%2Ftest&provider=openrouter",
|
|
expect.objectContaining({
|
|
headers: { Authorization: "Bearer tok" },
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("serializes provider settings updates without returning secrets", async () => {
|
|
await updateProviderSettings("tok", {
|
|
provider: "openrouter",
|
|
apiKey: "sk-or-test",
|
|
apiBase: "https://openrouter.ai/api/v1",
|
|
});
|
|
|
|
expect(fetch).toHaveBeenCalledWith(
|
|
"/api/settings/provider/update?provider=openrouter&api_key=sk-or-test&api_base=https%3A%2F%2Fopenrouter.ai%2Fapi%2Fv1",
|
|
expect.objectContaining({
|
|
headers: { Authorization: "Bearer tok" },
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("serializes web search settings updates", async () => {
|
|
await updateWebSearchSettings("tok", {
|
|
provider: "searxng",
|
|
baseUrl: "https://search.example.com",
|
|
});
|
|
|
|
expect(fetch).toHaveBeenCalledWith(
|
|
"/api/settings/web-search/update?provider=searxng&base_url=https%3A%2F%2Fsearch.example.com",
|
|
expect.objectContaining({
|
|
headers: { Authorization: "Bearer tok" },
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("maps generated session titles from the sessions list", async () => {
|
|
vi.mocked(fetch).mockResolvedValueOnce({
|
|
ok: true,
|
|
json: async () => ({
|
|
sessions: [
|
|
{
|
|
key: "websocket:chat-1",
|
|
created_at: "2026-05-01T10:00:00",
|
|
updated_at: "2026-05-01T10:01:00",
|
|
title: "优化 WebUI 标题",
|
|
},
|
|
],
|
|
}),
|
|
} as Response);
|
|
|
|
await expect(listSessions("tok")).resolves.toMatchObject([
|
|
{
|
|
key: "websocket:chat-1",
|
|
title: "优化 WebUI 标题",
|
|
preview: "",
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("maps slash command metadata from the commands endpoint", async () => {
|
|
vi.mocked(fetch).mockResolvedValueOnce({
|
|
ok: true,
|
|
json: async () => ({
|
|
commands: [
|
|
{
|
|
command: "/stop",
|
|
title: "Stop current task",
|
|
description: "Cancel the active task.",
|
|
icon: "square",
|
|
},
|
|
{
|
|
command: "/restart",
|
|
title: "Restart nanobot",
|
|
description: "Restart the bot process.",
|
|
icon: "rotate-cw",
|
|
},
|
|
{
|
|
command: "/history",
|
|
title: "Show conversation history",
|
|
description: "Print the last N messages.",
|
|
icon: "history",
|
|
arg_hint: "[n]",
|
|
},
|
|
],
|
|
}),
|
|
} as Response);
|
|
|
|
await expect(listSlashCommands("tok")).resolves.toEqual([
|
|
{
|
|
command: "/history",
|
|
title: "Show conversation history",
|
|
description: "Print the last N messages.",
|
|
icon: "history",
|
|
argHint: "[n]",
|
|
},
|
|
]);
|
|
expect(fetch).toHaveBeenCalledWith(
|
|
"/api/commands",
|
|
expect.objectContaining({
|
|
headers: { Authorization: "Bearer tok" },
|
|
}),
|
|
);
|
|
});
|
|
});
|