import type { Page, Route } from "@playwright/test" const emptyList = new Set([ "/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/status", "/vcs/diff", ]) const emptyObject = new Set(["/global/config", "/config", "/provider/auth", "/mcp", "/session/status"]) export interface MockServerConfig { provider: unknown directory: string project: unknown sessions: ({ id: string } & Record)[] pageMessages: (sessionId: string, limit: number, before?: string) => { items: unknown[]; cursor?: string } } export async function mockOpenCodeServer(page: Page, config: MockServerConfig) { const staticRoutes: Record = { "/provider": config.provider, "/path": { state: config.directory, config: config.directory, worktree: config.directory, directory: config.directory, home: "C:/OpenCode", }, "/project": [config.project], "/project/current": config.project, "/agent": [{ name: "build", mode: "primary" }], "/vcs": { branch: "main", default_branch: "main" }, "/session": config.sessions, } await page.route("**/*", async (route) => { const url = new URL(route.request().url()) const targetPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" if (url.port !== targetPort) return route.fallback() const path = url.pathname if (path === "/global/event" || path === "/event") return sse(route) if (emptyObject.has(path)) return json(route, {}) if (emptyList.has(path)) return json(route, []) if (path in staticRoutes) return json(route, staticRoutes[path]) const sessionMatch = path.match(/^\/session\/([^/]+)$/) if (sessionMatch) { const session = config.sessions.find((s) => s.id === sessionMatch[1]) return json(route, session ?? {}) } if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(path)) return json(route, []) const messagesMatch = path.match(/^\/session\/([^/]+)\/message$/) if (messagesMatch) { const limit = Number(url.searchParams.get("limit") ?? 80) const before = url.searchParams.get("before") ?? undefined const pageData = config.pageMessages(messagesMatch[1], limit, before) return json(route, pageData.items, pageData.cursor ? { "x-next-cursor": pageData.cursor } : undefined) } return json(route, {}) }) } function json(route: Route, body: unknown, headers?: Record) { return route.fulfill({ status: 200, contentType: "application/json", headers: { "access-control-allow-origin": "*", "access-control-expose-headers": "x-next-cursor", ...headers, }, body: JSON.stringify(body ?? null), }) } function sse(route: Route) { return route.fulfill({ status: 200, contentType: "text/event-stream", body: ": ok\n\n" }) }