
























1+// Feishu tests cover wiki plugin pagination behavior.
2+import { createTestPluginApi } from "openclaw/plugin-sdk/plugin-test-api";
3+import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
4+import type { OpenClawPluginApi, PluginRuntime } from "../runtime-api.js";
5+6+const createFeishuToolClientMock = vi.hoisted(() => vi.fn());
7+const resolveAnyEnabledFeishuToolsConfigMock = vi.hoisted(() => vi.fn());
8+9+vi.mock("./tool-account.js", () => ({
10+createFeishuToolClient: createFeishuToolClientMock,
11+resolveAnyEnabledFeishuToolsConfig: resolveAnyEnabledFeishuToolsConfigMock,
12+}));
13+14+let registerFeishuWikiTools: typeof import("./wiki.js").registerFeishuWikiTools;
15+16+type FeishuWikiTool = {
17+parameters: { properties?: Record<string, unknown> };
18+execute: (callId: string, input: Record<string, unknown>) => Promise<{ details?: unknown }>;
19+};
20+21+type FeishuWikiToolFactory = (context: { agentAccountId?: string }) => FeishuWikiTool;
22+23+function createFeishuToolRuntime(): PluginRuntime {
24+return {} as PluginRuntime;
25+}
26+27+function createWikiToolApi(registerTool: OpenClawPluginApi["registerTool"]): OpenClawPluginApi {
28+return createTestPluginApi({
29+id: "feishu-test",
30+name: "Feishu Test",
31+source: "local",
32+config: {
33+channels: {
34+feishu: {
35+enabled: true,
36+appId: "app_id",
37+appSecret: "app_secret", // pragma: allowlist secret
38+tools: { wiki: true },
39+},
40+},
41+},
42+runtime: createFeishuToolRuntime(),
43+logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
44+ registerTool,
45+});
46+}
47+48+function buildWikiTool(): FeishuWikiTool {
49+const registerTool = vi.fn();
50+registerFeishuWikiTools(createWikiToolApi(registerTool));
51+expect(registerTool).toHaveBeenCalledTimes(1);
52+const factory = registerTool.mock.calls[0]?.[0] as FeishuWikiToolFactory;
53+return factory({ agentAccountId: undefined });
54+}
55+56+describe("registerFeishuWikiTools pagination", () => {
57+beforeAll(async () => {
58+({ registerFeishuWikiTools } = await import("./wiki.js"));
59+});
60+61+afterAll(() => {
62+vi.doUnmock("./tool-account.js");
63+vi.resetModules();
64+});
65+66+afterEach(() => {
67+vi.restoreAllMocks();
68+});
69+70+beforeEach(() => {
71+vi.clearAllMocks();
72+resolveAnyEnabledFeishuToolsConfigMock.mockReturnValue({ wiki: true });
73+});
74+75+it("nodes: forwards pagination and returns continuation metadata", async () => {
76+const spaceNodeList = vi.fn().mockResolvedValue({
77+code: 0,
78+data: {
79+items: [{ node_token: "node-1", obj_type: "docx", node_type: "origin" }],
80+has_more: true,
81+page_token: "page-2",
82+},
83+});
84+createFeishuToolClientMock.mockReturnValue({ wiki: { spaceNode: { list: spaceNodeList } } });
85+86+const result = await buildWikiTool().execute("call-1", {
87+action: "nodes",
88+space_id: "space-1",
89+parent_node_token: "parent-1",
90+page_size: 25,
91+page_token: "page-1",
92+});
93+94+expect(spaceNodeList).toHaveBeenCalledWith({
95+path: { space_id: "space-1" },
96+params: { parent_node_token: "parent-1", page_size: 25, page_token: "page-1" },
97+});
98+expect(result.details).toMatchObject({
99+nodes: [{ node_token: "node-1" }],
100+has_more: true,
101+page_token: "page-2",
102+});
103+});
104+105+it("spaces: defaults page size and returns continuation metadata", async () => {
106+const spaceList = vi.fn().mockResolvedValue({
107+code: 0,
108+data: {
109+items: [{ space_id: "space-1", name: "Space 1" }],
110+has_more: false,
111+},
112+});
113+createFeishuToolClientMock.mockReturnValue({ wiki: { space: { list: spaceList } } });
114+115+const result = await buildWikiTool().execute("call-1", { action: "spaces" });
116+117+expect(spaceList).toHaveBeenCalledWith({
118+params: { page_size: 50, page_token: undefined },
119+});
120+expect(result.details).toMatchObject({
121+spaces: [{ space_id: "space-1" }],
122+has_more: false,
123+});
124+});
125+126+it("spaces: does not emit the access hint for an empty page with a continuation", async () => {
127+const spaceList = vi.fn().mockResolvedValue({
128+code: 0,
129+data: {
130+items: [],
131+has_more: true,
132+page_token: "page-2",
133+},
134+});
135+createFeishuToolClientMock.mockReturnValue({ wiki: { space: { list: spaceList } } });
136+137+const result = await buildWikiTool().execute("call-1", { action: "spaces" });
138+139+expect(result.details).toEqual({
140+spaces: [],
141+has_more: true,
142+page_token: "page-2",
143+});
144+});
145+146+it("spaces: does not emit the access hint on an empty terminal continuation page", async () => {
147+const spaceList = vi.fn().mockResolvedValue({
148+code: 0,
149+data: {
150+items: [],
151+has_more: false,
152+},
153+});
154+createFeishuToolClientMock.mockReturnValue({ wiki: { space: { list: spaceList } } });
155+156+const result = await buildWikiTool().execute("call-1", {
157+action: "spaces",
158+page_token: "page-2",
159+});
160+161+expect(result.details).toEqual({
162+spaces: [],
163+has_more: false,
164+});
165+});
166+167+it("rejects out-of-range page sizes before calling Feishu", async () => {
168+const spaceList = vi.fn();
169+createFeishuToolClientMock.mockReturnValue({ wiki: { space: { list: spaceList } } });
170+171+const result = await buildWikiTool().execute("call-1", {
172+action: "spaces",
173+page_size: 51,
174+});
175+176+expect(spaceList).not.toHaveBeenCalled();
177+expect(result.details).toMatchObject({
178+error: "page_size must be a positive integer between 1 and 50",
179+});
180+});
181+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。