mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-23 12:54:42 +00:00
86 lines
2.8 KiB
TypeScript
86 lines
2.8 KiB
TypeScript
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<string, unknown>)[]
|
|
pageMessages: (sessionId: string, limit: number, before?: string) => { items: unknown[]; cursor?: string }
|
|
}
|
|
|
|
export async function mockOpenCodeServer(page: Page, config: MockServerConfig) {
|
|
const staticRoutes: Record<string, unknown> = {
|
|
"/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<string, string>) {
|
|
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" })
|
|
}
|