deer-flow/frontend/tests/unit/core/agents/features.test.ts
zhangwei-way b6503e9a35
feat(knowledge): add per-message RAGFlow retrieval scope (#5238)
* feat(knowledge): integrate RAGFlow retrieval and management

* test(knowledge): cover merged listing tool

* feat(knowledge): add per-message retrieval scope

* chore(docs): remove unrelated document

* docs(knowledge): add interaction screenshots

* feat(knowledge): simplify scope selector trigger

* docs(knowledge): refresh selector screenshot

* feat(knowledge): defer standalone management

* docs(knowledge): show chat-only scope UI

* fix(knowledge): honor scope on clarification replies

* fix(knowledge): harden scoped replay validation

* docs(knowledge): clarify replay scope precedence

* fix(knowledge): keep provider settings on tools

* fix(config): preserve tools-only knowledge settings

* fix(knowledge): submit custom assistant identity

* refactor(knowledge): trim PR scope changes

* fix(knowledge): sanitize document scope display

* feat(knowledge): enable scope selection in main chat

* fix(knowledge): emphasize active scope icon without button frame

* fix(knowledge): close context scrubbing and refresh e2e checks

* fix(knowledge): preserve idempotent canonical retries

* fix(knowledge): accept promptless conversation runs

* style(knowledge): format backend regression tests

* chore(knowledge): trim PR scope and fix frontend format

* fix(knowledge): remove shared-scope notice

* fix(knowledge): remove scope persistence notice

* docs(knowledge): include main chat in catalog scope

* fix(knowledge): preserve scope recovery and upgrades

* fix(config): preserve LightRAG knowledge upgrades

---------

Co-authored-by: foreleven <for-eleven@hotmail.com>
2026-09-18 16:59:31 +08:00

144 lines
4.4 KiB
TypeScript

import { beforeEach, describe, expect, test, rs } from "@rstest/core";
rs.mock("@/core/api/fetcher", () => ({
fetch: rs.fn(),
}));
rs.mock("@/core/config", () => ({
getBackendBaseURL: () => "",
}));
import { fetchAgentsApiEnabled } from "@/core/agents/api";
import { fetch as fetcher } from "@/core/api/fetcher";
import {
fetchBrowserControlEnabled,
fetchKnowledgeBaseFeature,
fetchMcpTasksEnabled,
} from "@/core/features/api";
const mockedFetch = rs.mocked(fetcher);
function jsonResponse(status: number, body: unknown): Response {
return new Response(JSON.stringify(body), {
status,
headers: { "Content-Type": "application/json" },
});
}
beforeEach(() => {
mockedFetch.mockReset();
});
describe("fetchAgentsApiEnabled", () => {
test("returns true when backend reports agents_api enabled", async () => {
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, { agents_api: { enabled: true } }),
);
await expect(fetchAgentsApiEnabled()).resolves.toBe(true);
expect(mockedFetch).toHaveBeenCalledWith("/api/features");
});
test("returns false when backend reports agents_api disabled", async () => {
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, { agents_api: { enabled: false } }),
);
await expect(fetchAgentsApiEnabled()).resolves.toBe(false);
});
test("throws when the features request fails", async () => {
mockedFetch.mockResolvedValueOnce(jsonResponse(500, {}));
await expect(fetchAgentsApiEnabled()).rejects.toThrow();
});
});
describe("fetchBrowserControlEnabled", () => {
test("returns true when backend reports browser_control enabled", async () => {
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, {
agents_api: { enabled: true },
browser_control: { enabled: true },
}),
);
await expect(fetchBrowserControlEnabled()).resolves.toBe(true);
expect(mockedFetch).toHaveBeenCalledWith("/api/features");
});
test("returns false when browser_control is disabled or omitted", async () => {
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, {
agents_api: { enabled: true },
browser_control: { enabled: false },
}),
);
await expect(fetchBrowserControlEnabled()).resolves.toBe(false);
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, { agents_api: { enabled: true } }),
);
await expect(fetchBrowserControlEnabled()).resolves.toBe(false);
});
test("throws when the features request fails", async () => {
mockedFetch.mockResolvedValueOnce(jsonResponse(500, {}));
await expect(fetchBrowserControlEnabled()).rejects.toThrow();
});
});
describe("fetchMcpTasksEnabled", () => {
test("returns true when backend reports mcp_tasks enabled", async () => {
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, {
agents_api: { enabled: true },
mcp_tasks: { enabled: true },
}),
);
await expect(fetchMcpTasksEnabled()).resolves.toBe(true);
expect(mockedFetch).toHaveBeenCalledWith("/api/features");
});
test("returns false when mcp_tasks is disabled or omitted", async () => {
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, {
agents_api: { enabled: true },
mcp_tasks: { enabled: false },
}),
);
await expect(fetchMcpTasksEnabled()).resolves.toBe(false);
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, { agents_api: { enabled: true } }),
);
await expect(fetchMcpTasksEnabled()).resolves.toBe(false);
});
test("throws when the features request fails", async () => {
mockedFetch.mockResolvedValueOnce(jsonResponse(500, {}));
await expect(fetchMcpTasksEnabled()).rejects.toThrow();
});
});
describe("fetchKnowledgeBaseFeature", () => {
test("reads the knowledge-base retrieval-scope flags", async () => {
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, {
agents_api: { enabled: true },
knowledge_base: {
scope_selection_enabled: true,
},
}),
);
await expect(fetchKnowledgeBaseFeature()).resolves.toEqual({
scopeSelectionEnabled: true,
});
});
test("defaults to disabled when omitted", async () => {
mockedFetch.mockResolvedValueOnce(
jsonResponse(200, { agents_api: { enabled: true } }),
);
await expect(fetchKnowledgeBaseFeature()).resolves.toEqual({
scopeSelectionEnabled: false,
});
});
});