Files
agent-desktop/console/src/hooks/useWorkspaceWatch.connection.test.ts
T
Pine 9b30f681c6 feat: 智能体控制台前端(console)
- React+antd+zustand,注册表驱动路由/菜单/权限
- Tauri 桌面壳、后端托管 SPA、跨标签页消息队列
2026-08-23 22:43:18 +08:00

116 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { renderHook, act, waitFor } from "@testing-library/react";
// 顶层 mockVitest 会提升这些),使用 doMock 以兼容 resetModules
vi.mock("../api/modules/workspace", () => ({
workspaceApi: { getWatchUrl: vi.fn().mockReturnValue("http://test/watch") },
}));
vi.mock("../api/authHeaders", () => ({
buildAuthHeaders: vi.fn().mockReturnValue({}),
}));
// 创建一个永远挂起的 fetch(用于不关心 SSE 内容的测试)
function makePendingFetchMock() {
return vi.fn().mockReturnValue(new Promise(() => {}));
}
describe("useWorkspaceWatch — connection lifecycle", () => {
let useWorkspaceWatch: typeof import("./useWorkspaceWatch").useWorkspaceWatch;
beforeEach(async () => {
vi.clearAllMocks();
vi.resetModules();
vi.doMock("../api/modules/workspace", () => ({
workspaceApi: {
getWatchUrl: vi.fn().mockReturnValue("http://test/watch"),
},
}));
vi.doMock("../api/authHeaders", () => ({
buildAuthHeaders: vi.fn().mockReturnValue({}),
}));
({ useWorkspaceWatch } = await import("./useWorkspaceWatch"));
});
afterEach(() => {
// 恢复原始 fetch(防止 mock 泄漏)
vi.restoreAllMocks();
});
// ─── 测试 1disabled 时不调用 fetch ───────────────────────────────────────
it("disabled 时不调用 fetch", async () => {
const mockFetch = makePendingFetchMock();
vi.stubGlobal("fetch", mockFetch);
const { unmount } = renderHook(() => useWorkspaceWatch(vi.fn(), false));
// 等一个 tick,确保 effect 已执行
await act(async () => {});
expect(mockFetch).not.toHaveBeenCalled();
unmount();
});
// ─── 测试 2enabled 时会调用 fetch ───────────────────────────────────────
it("enabled 时挂载后会调用 fetch", async () => {
const mockFetch = makePendingFetchMock();
vi.stubGlobal("fetch", mockFetch);
const { unmount } = renderHook(() => useWorkspaceWatch(vi.fn(), true));
await waitFor(() => {
expect(mockFetch).toHaveBeenCalledWith(
"http://test/watch",
expect.objectContaining({ method: "GET" }),
);
});
unmount();
});
// ─── 测试 7:最后一个 listener unmount 后断开连接(abort 被调用)──────────
it("最后一个 listener unmount 后 AbortController.abort 被调用", async () => {
const mockFetch = makePendingFetchMock();
vi.stubGlobal("fetch", mockFetch);
const abortSpy = vi.spyOn(AbortController.prototype, "abort");
const { unmount } = renderHook(() => useWorkspaceWatch(vi.fn(), true));
await waitFor(() => expect(mockFetch).toHaveBeenCalled());
act(() => {
unmount();
});
expect(abortSpy).toHaveBeenCalled();
});
// ─── 测试 8enabled 从 false 变为 true 时启动连接 ────────────────────────
it("enabled 从 false 变为 true 时启动连接", async () => {
const mockFetch = makePendingFetchMock();
vi.stubGlobal("fetch", mockFetch);
const { rerender, unmount } = renderHook(
({ enabled }: { enabled: boolean }) =>
useWorkspaceWatch(vi.fn(), enabled),
{ initialProps: { enabled: false } },
);
await act(async () => {});
expect(mockFetch).not.toHaveBeenCalled();
rerender({ enabled: true });
await waitFor(() => {
expect(mockFetch).toHaveBeenCalledWith(
"http://test/watch",
expect.objectContaining({ method: "GET" }),
);
});
unmount();
});
});