Download src/mocks/workspaces-handlers.ts from SaylorTwift/openhands: direct link, hf CLI and curl.
- Browser
- Download file 3.9 kB
-
https://huggingface.co/SaylorTwift/openhands/resolve/main/src/mocks/workspaces-handlers.ts
- Command line
-
hf download hf://SaylorTwift/openhands/src/mocks/workspaces-handlers.ts
-
curl -L -o workspaces-handlers.ts https://huggingface.co/SaylorTwift/openhands/resolve/main/src/mocks/workspaces-handlers.ts
3.9 kB
| import { http, HttpResponse } from "msw"; | |
| import type { | |
| WorkspaceItem, | |
| WorkspaceParentItem, | |
| WorkspacesListResponse, | |
| } from "@openhands/typescript-client/clients"; | |
| /** | |
| * MSW handlers for the agent-server's `/api/workspaces` and | |
| * `/api/auth/workspace-session` endpoints used by `useLocalWorkspaces`, | |
| * `WorkspacesService`, and `useWorkspaceSession`. | |
| * | |
| * Without these handlers, mock-mode renders of the home / sidebar / | |
| * conversation pages let those requests fall through to the Vite proxy | |
| * (`127.0.0.1:8000` ECONNREFUSED), which spams logs and surfaces | |
| * global error toasts in mock-mode screens. | |
| * | |
| * The mock keeps an in-memory list so the install / remove flow round-trips | |
| * cleanly within a single page load. State resets on every test reload. | |
| */ | |
| let workspaces: WorkspaceItem[] = []; | |
| let workspaceParents: WorkspaceParentItem[] = []; | |
| function snapshot(): WorkspacesListResponse { | |
| return { | |
| workspaces: workspaces.map((w) => ({ ...w })), | |
| workspaceParents: workspaceParents.map((p) => ({ ...p })), | |
| }; | |
| } | |
| export function resetMockWorkspaces(): void { | |
| workspaces = []; | |
| workspaceParents = []; | |
| } | |
| export const WORKSPACES_HANDLERS = [ | |
| http.get("*/api/workspaces", async () => HttpResponse.json(snapshot())), | |
| http.post("*/api/workspaces", async ({ request }) => { | |
| // `workspaces` is the top-level key used by WorkspacesClient.addWorkspaces() | |
| // in @openhands/typescript-client — aligns with the agent-server SDK contract. | |
| const body = (await request.json()) as { workspaces?: WorkspaceItem[] }; | |
| for (const incoming of body.workspaces ?? []) { | |
| const existingIndex = workspaces.findIndex( | |
| (w) => w.path === incoming.path, | |
| ); | |
| if (existingIndex >= 0) { | |
| workspaces[existingIndex] = { ...incoming }; | |
| } else { | |
| workspaces.push({ ...incoming }); | |
| } | |
| } | |
| return HttpResponse.json(snapshot()); | |
| }), | |
| http.delete("*/api/workspaces", async ({ request }) => { | |
| const url = new URL(request.url); | |
| const path = url.searchParams.get("path"); | |
| const before = workspaces.length; | |
| workspaces = workspaces.filter((w) => w.path !== path); | |
| // WorkspacesService.removeWorkspace() discards the response body (returns | |
| // void), so the shape here is mock-only and not coupled to the real contract. | |
| return HttpResponse.json({ deleted: workspaces.length !== before }); | |
| }), | |
| http.post("*/api/workspaces/parents", async ({ request }) => { | |
| const body = (await request.json()) as { parents?: WorkspaceParentItem[] }; | |
| for (const incoming of body.parents ?? []) { | |
| const existingIndex = workspaceParents.findIndex( | |
| (p) => p.path === incoming.path, | |
| ); | |
| if (existingIndex >= 0) { | |
| workspaceParents[existingIndex] = { ...incoming }; | |
| } else { | |
| workspaceParents.push({ ...incoming }); | |
| } | |
| } | |
| return HttpResponse.json(snapshot()); | |
| }), | |
| http.delete("*/api/workspaces/parents", async ({ request }) => { | |
| const url = new URL(request.url); | |
| const path = url.searchParams.get("path"); | |
| const before = workspaceParents.length; | |
| workspaceParents = workspaceParents.filter((p) => p.path !== path); | |
| // WorkspacesService.removeWorkspaceParent() discards the response body | |
| // (returns void), so the shape here is mock-only and not coupled to the | |
| // real contract. | |
| return HttpResponse.json({ deleted: workspaceParents.length !== before }); | |
| }), | |
| // Workspace static-asset session: minted on conversation pages by | |
| // `useWorkspaceSession`. The real endpoint sets an HttpOnly cookie; in | |
| // mock mode we just acknowledge the POST/DELETE so the call doesn't fall | |
| // through to the Vite proxy. | |
| http.post("*/api/auth/workspace-session", async () => | |
| HttpResponse.json({ ok: true }), | |
| ), | |
| http.delete( | |
| "*/api/auth/workspace-session", | |
| async () => new HttpResponse(null, { status: 204 }), | |
| ), | |
| ]; | |