mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-12 01:50:49 +08:00
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
160 lines
4.8 KiB
TypeScript
160 lines
4.8 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const resolveFeishuRuntimeAccountMock = vi.hoisted(() => vi.fn());
|
|
const createFeishuClientMock = vi.hoisted(() => vi.fn());
|
|
const createReplyPrefixContextMock = vi.hoisted(() => vi.fn());
|
|
const createCommentTypingReactionLifecycleMock = vi.hoisted(() => vi.fn());
|
|
const deliverCommentThreadTextMock = vi.hoisted(() => vi.fn());
|
|
const createReplyDispatcherWithTypingMock = vi.hoisted(() => vi.fn());
|
|
const getFeishuRuntimeMock = vi.hoisted(() => vi.fn());
|
|
|
|
vi.mock("./accounts.js", () => ({
|
|
resolveFeishuRuntimeAccount: resolveFeishuRuntimeAccountMock,
|
|
}));
|
|
|
|
vi.mock("./client.js", () => ({
|
|
createFeishuClient: createFeishuClientMock,
|
|
}));
|
|
|
|
vi.mock("./comment-dispatcher-runtime-api.js", () => ({
|
|
createReplyPrefixContext: createReplyPrefixContextMock,
|
|
}));
|
|
|
|
vi.mock("./comment-reaction.js", () => ({
|
|
createCommentTypingReactionLifecycle: createCommentTypingReactionLifecycleMock,
|
|
}));
|
|
|
|
vi.mock("./drive.js", () => ({
|
|
deliverCommentThreadText: deliverCommentThreadTextMock,
|
|
}));
|
|
|
|
vi.mock("./runtime.js", () => ({
|
|
getFeishuRuntime: getFeishuRuntimeMock,
|
|
}));
|
|
|
|
import { createFeishuCommentReplyDispatcher } from "./comment-dispatcher.js";
|
|
|
|
describe("createFeishuCommentReplyDispatcher", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
resolveFeishuRuntimeAccountMock.mockReturnValue({
|
|
accountId: "main",
|
|
appId: "app_id",
|
|
appSecret: "app_secret",
|
|
domain: "feishu",
|
|
config: {},
|
|
});
|
|
createFeishuClientMock.mockReturnValue({});
|
|
createReplyPrefixContextMock.mockReturnValue({
|
|
responsePrefix: undefined,
|
|
responsePrefixContextProvider: undefined,
|
|
});
|
|
deliverCommentThreadTextMock.mockResolvedValue({
|
|
delivery_mode: "reply_comment",
|
|
reply_id: "reply_1",
|
|
});
|
|
createCommentTypingReactionLifecycleMock.mockReturnValue({
|
|
start: vi.fn(async () => {}),
|
|
cleanup: vi.fn(async () => {}),
|
|
});
|
|
createReplyDispatcherWithTypingMock.mockImplementation(() => ({
|
|
dispatcher: {
|
|
markComplete: vi.fn(),
|
|
waitForIdle: vi.fn(async () => {}),
|
|
},
|
|
replyOptions: {},
|
|
markDispatchIdle: vi.fn(),
|
|
markRunComplete: vi.fn(),
|
|
}));
|
|
getFeishuRuntimeMock.mockReturnValue({
|
|
channel: {
|
|
text: {
|
|
resolveTextChunkLimit: vi.fn(() => 4000),
|
|
resolveChunkMode: vi.fn(() => "line"),
|
|
chunkTextWithMode: vi.fn((text: string) => [text]),
|
|
},
|
|
reply: {
|
|
createReplyDispatcherWithTyping: createReplyDispatcherWithTypingMock,
|
|
resolveHumanDelayConfig: vi.fn(() => undefined),
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
it("sends final comment text without waiting for typing cleanup", async () => {
|
|
let resolveCleanup: (() => void) | undefined;
|
|
const cleanup = vi.fn(
|
|
() =>
|
|
new Promise<void>((resolve) => {
|
|
resolveCleanup = resolve;
|
|
}),
|
|
);
|
|
createCommentTypingReactionLifecycleMock.mockReturnValue({
|
|
start: vi.fn(async () => {}),
|
|
cleanup,
|
|
});
|
|
|
|
createFeishuCommentReplyDispatcher({
|
|
cfg: {} as never,
|
|
agentId: "main",
|
|
runtime: { log: vi.fn(), error: vi.fn() } as never,
|
|
accountId: "main",
|
|
fileToken: "doc_token_1",
|
|
fileType: "docx",
|
|
commentId: "comment_1",
|
|
replyId: "reply_1",
|
|
isWholeComment: false,
|
|
});
|
|
|
|
const options = createReplyDispatcherWithTypingMock.mock.calls.at(-1)?.[0];
|
|
const deliverPromise = options.deliver({ text: "hello world" }, { kind: "final" });
|
|
const status = await Promise.race([
|
|
deliverPromise.then(() => "done"),
|
|
new Promise<string>((resolve) => setTimeout(() => resolve("pending"), 0)),
|
|
]);
|
|
|
|
expect(status).toBe("done");
|
|
expect(deliverCommentThreadTextMock).toHaveBeenCalledWith(
|
|
expect.anything(),
|
|
expect.objectContaining({
|
|
file_token: "doc_token_1",
|
|
file_type: "docx",
|
|
comment_id: "comment_1",
|
|
content: "hello world",
|
|
is_whole_comment: false,
|
|
}),
|
|
);
|
|
expect(cleanup).not.toHaveBeenCalled();
|
|
|
|
options.onCleanup?.();
|
|
expect(cleanup).toHaveBeenCalledTimes(1);
|
|
|
|
resolveCleanup?.();
|
|
await deliverPromise;
|
|
});
|
|
|
|
it("starts the typing reaction from dispatcher onReplyStart", async () => {
|
|
const start = vi.fn(async () => {});
|
|
createCommentTypingReactionLifecycleMock.mockReturnValue({
|
|
start,
|
|
cleanup: vi.fn(async () => {}),
|
|
});
|
|
|
|
createFeishuCommentReplyDispatcher({
|
|
cfg: {} as never,
|
|
agentId: "main",
|
|
runtime: { log: vi.fn(), error: vi.fn() } as never,
|
|
accountId: "main",
|
|
fileToken: "doc_token_1",
|
|
fileType: "docx",
|
|
commentId: "comment_1",
|
|
replyId: "reply_1",
|
|
isWholeComment: false,
|
|
});
|
|
|
|
const options = createReplyDispatcherWithTypingMock.mock.calls.at(-1)?.[0];
|
|
await options.onReplyStart?.();
|
|
|
|
expect(start).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|