diff options
| author | Kit Langton <[email protected]> | 2026-04-01 11:58:11 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-01 15:58:11 +0000 |
| commit | 38d22765920ef5047db4d9f1bdc0bdf602e6906f (patch) | |
| tree | 378eb3358326fb91bef194fea04aeea64cb75279 /packages/app/e2e/fixtures.ts | |
| parent | d58004a864ee04a34a30fbbcdde9336d477fc8fa (diff) | |
| download | opencode-38d22765920ef5047db4d9f1bdc0bdf602e6906f.tar.gz opencode-38d22765920ef5047db4d9f1bdc0bdf602e6906f.zip | |
test(e2e): isolate prompt tests with per-worker backend (#20464)
Diffstat (limited to 'packages/app/e2e/fixtures.ts')
| -rw-r--r-- | packages/app/e2e/fixtures.ts | 165 |
1 files changed, 116 insertions, 49 deletions
diff --git a/packages/app/e2e/fixtures.ts b/packages/app/e2e/fixtures.ts index 7fc4cda05..c94c93992 100644 --- a/packages/app/e2e/fixtures.ts +++ b/packages/app/e2e/fixtures.ts @@ -3,6 +3,7 @@ import { ManagedRuntime } from "effect" import type { E2EWindow } from "../src/testing/terminal" import type { Item, Reply, Usage } from "../../opencode/test/lib/llm-server" import { TestLLMServer } from "../../opencode/test/lib/llm-server" +import { startBackend } from "./backend" import { healthPhase, cleanupSession, @@ -19,6 +20,20 @@ import { createSdk, dirSlug, getWorktree, sessionPath } from "./utils" type LLMFixture = { url: string push: (...input: (Item | Reply)[]) => Promise<void> + pushMatch: ( + match: (hit: { url: URL; body: Record<string, unknown> }) => boolean, + ...input: (Item | Reply)[] + ) => Promise<void> + textMatch: ( + match: (hit: { url: URL; body: Record<string, unknown> }) => boolean, + value: string, + opts?: { usage?: Usage }, + ) => Promise<void> + toolMatch: ( + match: (hit: { url: URL; body: Record<string, unknown> }) => boolean, + name: string, + input: unknown, + ) => Promise<void> text: (value: string, opts?: { usage?: Usage }) => Promise<void> tool: (name: string, input: unknown) => Promise<void> toolHang: (name: string, input: unknown) => Promise<void> @@ -46,32 +61,54 @@ const seedModel = (() => { } })() +type ProjectHandle = { + directory: string + slug: string + gotoSession: (sessionID?: string) => Promise<void> + trackSession: (sessionID: string, directory?: string) => void + trackDirectory: (directory: string) => void + sdk: ReturnType<typeof createSdk> +} + +type ProjectOptions = { + extra?: string[] + model?: { providerID: string; modelID: string } + setup?: (directory: string) => Promise<void> + beforeGoto?: (project: { directory: string; sdk: ReturnType<typeof createSdk> }) => Promise<void> +} + type TestFixtures = { llm: LLMFixture sdk: ReturnType<typeof createSdk> gotoSession: (sessionID?: string) => Promise<void> - withProject: <T>( - callback: (project: { - directory: string - slug: string - gotoSession: (sessionID?: string) => Promise<void> - trackSession: (sessionID: string, directory?: string) => void - trackDirectory: (directory: string) => void - }) => Promise<T>, - options?: { - extra?: string[] - model?: { providerID: string; modelID: string } - setup?: (directory: string) => Promise<void> - }, - ) => Promise<T> + withProject: <T>(callback: (project: ProjectHandle) => Promise<T>, options?: ProjectOptions) => Promise<T> + withBackendProject: <T>(callback: (project: ProjectHandle) => Promise<T>, options?: ProjectOptions) => Promise<T> } type WorkerFixtures = { + backend: { + url: string + sdk: (directory?: string) => ReturnType<typeof createSdk> + } directory: string slug: string } export const test = base.extend<TestFixtures, WorkerFixtures>({ + backend: [ + async ({}, use, workerInfo) => { + const handle = await startBackend(`w${workerInfo.workerIndex}`) + try { + await use({ + url: handle.url, + sdk: (directory?: string) => createSdk(directory, handle.url), + }) + } finally { + await handle.stop() + } + }, + { scope: "worker" }, + ], llm: async ({}, use) => { const rt = ManagedRuntime.make(TestLLMServer.layer) try { @@ -79,6 +116,9 @@ export const test = base.extend<TestFixtures, WorkerFixtures>({ await use({ url: svc.url, push: (...input) => rt.runPromise(svc.push(...input)), + pushMatch: (match, ...input) => rt.runPromise(svc.pushMatch(match, ...input)), + textMatch: (match, value, opts) => rt.runPromise(svc.textMatch(match, value, opts)), + toolMatch: (match, name, input) => rt.runPromise(svc.toolMatch(match, name, input)), text: (value, opts) => rt.runPromise(svc.text(value, opts)), tool: (name, input) => rt.runPromise(svc.tool(name, input)), toolHang: (name, input) => rt.runPromise(svc.toolHang(name, input)), @@ -146,44 +186,70 @@ export const test = base.extend<TestFixtures, WorkerFixtures>({ await use(gotoSession) }, withProject: async ({ page }, use) => { - await use(async (callback, options) => { - const root = await createTestProject() - const sessions = new Map<string, string>() - const dirs = new Set<string>() - await options?.setup?.(root) - await seedStorage(page, { directory: root, extra: options?.extra, model: options?.model }) - - const gotoSession = async (sessionID?: string) => { - await page.goto(sessionPath(root, sessionID)) - await waitSession(page, { directory: root, sessionID }) - const current = sessionIDFromUrl(page.url()) - if (current) trackSession(current) - } + await use((callback, options) => + runProject(page, callback, options), + ) + }, + withBackendProject: async ({ page, backend }, use) => { + await use((callback, options) => + runProject(page, callback, { ...options, serverUrl: backend.url, sdk: backend.sdk }), + ) + }, +}) - const trackSession = (sessionID: string, directory?: string) => { - sessions.set(sessionID, directory ?? root) - } +async function runProject<T>( + page: Page, + callback: (project: ProjectHandle) => Promise<T>, + options?: ProjectOptions & { + serverUrl?: string + sdk?: (directory?: string) => ReturnType<typeof createSdk> + }, +) { + const url = options?.serverUrl + const root = await createTestProject(url ? { serverUrl: url } : undefined) + const sdk = options?.sdk?.(root) ?? createSdk(root, url) + const sessions = new Map<string, string>() + const dirs = new Set<string>() + await options?.setup?.(root) + await seedStorage(page, { + directory: root, + extra: options?.extra, + model: options?.model, + serverUrl: url, + }) - const trackDirectory = (directory: string) => { - if (directory !== root) dirs.add(directory) - } + const gotoSession = async (sessionID?: string) => { + await page.goto(sessionPath(root, sessionID)) + await waitSession(page, { directory: root, sessionID, serverUrl: url }) + const current = sessionIDFromUrl(page.url()) + if (current) trackSession(current) + } - try { - await gotoSession() - const slug = await waitSlug(page) - return await callback({ directory: root, slug, gotoSession, trackSession, trackDirectory }) - } finally { - setHealthPhase(page, "cleanup") - await Promise.allSettled( - Array.from(sessions, ([sessionID, directory]) => cleanupSession({ sessionID, directory })), - ) - await Promise.allSettled(Array.from(dirs, (directory) => cleanupTestProject(directory))) - await cleanupTestProject(root) - setHealthPhase(page, "test") - } - }) - }, -}) + const trackSession = (sessionID: string, directory?: string) => { + sessions.set(sessionID, directory ?? root) + } + + const trackDirectory = (directory: string) => { + if (directory !== root) dirs.add(directory) + } + + try { + await options?.beforeGoto?.({ directory: root, sdk }) + await gotoSession() + const slug = await waitSlug(page) + return await callback({ directory: root, slug, gotoSession, trackSession, trackDirectory, sdk }) + } finally { + setHealthPhase(page, "cleanup") + await Promise.allSettled( + Array.from(sessions, ([sessionID, directory]) => + cleanupSession({ sessionID, directory, serverUrl: url }), + ), + ) + await Promise.allSettled(Array.from(dirs, (directory) => cleanupTestProject(directory))) + await cleanupTestProject(root) + setHealthPhase(page, "test") + } +} async function seedStorage( page: Page, @@ -191,6 +257,7 @@ async function seedStorage( directory: string extra?: string[] model?: { providerID: string; modelID: string } + serverUrl?: string }, ) { await seedProjects(page, input) |
