feat(workbench): expand SCADA monitoring and investigation presentation
This commit is contained in:
@@ -9,6 +9,77 @@ import {
|
||||
} from "./project-client";
|
||||
|
||||
describe("workbench project client", () => {
|
||||
it("explains project-list timeouts using the Server readiness result", async () => {
|
||||
const fetchMock = vi.fn(async (input: RequestInfo | URL, _init?: RequestInit) => {
|
||||
if (new URL(String(input)).pathname === "/ready") return Response.json({
|
||||
status: "not_ready", checks: { startup: "ready", metadata_database: "unavailable", mcp_transport: "ready" }
|
||||
}, { status: 503 });
|
||||
throw new DOMException("signal timed out", "TimeoutError");
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(fetchWorkbenchProjects(async () => "token")).rejects.toThrow("读取授权项目超时(已等待 15 秒)");
|
||||
expect(fetchMock).toHaveBeenCalledTimes(2);
|
||||
const probe = fetchMock.mock.calls.find(([url]) => new URL(String(url)).pathname === "/ready");
|
||||
expect(probe).toBeDefined();
|
||||
expect(new Headers(probe?.[1]?.headers).has("Authorization")).toBe(false);
|
||||
});
|
||||
|
||||
it("identifies metadata unavailability instead of exposing the raw abort message", async () => {
|
||||
vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => {
|
||||
if (new URL(String(input)).pathname === "/ready") return Response.json({
|
||||
status: "not_ready", checks: { startup: "ready", metadata_database: "unavailable", mcp_transport: "ready" }
|
||||
}, { status: 503 });
|
||||
throw new DOMException("signal timed out", "TimeoutError");
|
||||
}));
|
||||
await expect(fetchWorkbenchProjects(async () => "token")).rejects.toThrow("项目元数据库暂不可用");
|
||||
});
|
||||
|
||||
it("names backend startup and an unavailable listener separately", async () => {
|
||||
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
|
||||
if (new URL(String(input)).pathname === "/ready") return Response.json({
|
||||
status: "not_ready", checks: { startup: "not_ready", metadata_database: "not_checked", mcp_transport: "not_ready" }
|
||||
}, { status: 503 });
|
||||
throw new DOMException("signal timed out", "TimeoutError");
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
await expect(fetchWorkbenchProjects(async () => "token")).rejects.toThrow("后端服务正在启动");
|
||||
fetchMock.mockRejectedValue(new DOMException("signal timed out", "TimeoutError"));
|
||||
await expect(fetchWorkbenchProjects(async () => "token")).rejects.toThrow("后端服务未响应");
|
||||
});
|
||||
|
||||
it("preserves caller cancellation without probing readiness or presenting a timeout", async () => {
|
||||
const controller = new AbortController();
|
||||
controller.abort();
|
||||
const fetchMock = vi.fn();
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
await expect(fetchWorkbenchProjects(undefined, controller.signal)).rejects.toMatchObject({ name: "AbortError" });
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("retries a timed-out lookup after the backend recovers without keeping its cached failure", async () => {
|
||||
let available = false;
|
||||
vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => {
|
||||
if (new URL(String(input)).pathname === "/ready") return Response.json({
|
||||
status: "ready", checks: { startup: "ready", metadata_database: "ready", mcp_transport: "ready" }
|
||||
});
|
||||
if (!available) throw new DOMException("signal timed out", "TimeoutError");
|
||||
return Response.json({ items: [{ project_id: "supply", gs_workspace: "tjwater_next", status: "active" }],
|
||||
total: 1, limit: 1000, offset: 0 });
|
||||
}));
|
||||
const provider = async () => "token";
|
||||
await expect(findOwnedWorkbenchProject(provider)).rejects.toThrow("后端当前已就绪");
|
||||
available = true;
|
||||
await expect(findOwnedWorkbenchProject(provider)).resolves.toMatchObject({ project: { project_id: "supply" } });
|
||||
});
|
||||
|
||||
it("keeps authorization failures distinct from service availability", async () => {
|
||||
const fetchMock = vi.fn(async () => Response.json({ detail: "当前账号没有项目访问权限" }, { status: 403 }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
await expect(fetchWorkbenchProjects(async () => "token")).rejects.toThrow("当前账号没有项目访问权限");
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("caches complete authorized lists across repeated openings and refreshes explicitly or after expiry", async () => {
|
||||
const clock = vi.spyOn(Date, "now").mockReturnValue(100);
|
||||
const fetch = vi.fn(async () => Response.json({ items: [{ project_id: "supply", gs_workspace: "tjwater_next", status: "active" }], total: 1, limit: 1000, offset: 0 }));
|
||||
|
||||
Reference in New Issue
Block a user