diff options
| author | Adam <[email protected]> | 2026-01-20 13:53:55 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-01-20 14:02:09 -0600 |
| commit | 95e9407e6313b42c3a7fc480f283ec151c386355 (patch) | |
| tree | 2dbd25c35abacf077d46bfa7fa41200afb859dc8 /packages/app/script | |
| parent | 1466b43c5c09f81607e616b24f567d472111afe7 (diff) | |
| download | opencode-95e9407e6313b42c3a7fc480f283ec151c386355.tar.gz opencode-95e9407e6313b42c3a7fc480f283ec151c386355.zip | |
test(app): fix e2e
Diffstat (limited to 'packages/app/script')
| -rw-r--r-- | packages/app/script/e2e-local.ts | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/packages/app/script/e2e-local.ts b/packages/app/script/e2e-local.ts new file mode 100644 index 000000000..dd0e9a52e --- /dev/null +++ b/packages/app/script/e2e-local.ts @@ -0,0 +1,130 @@ +import fs from "node:fs/promises" +import net from "node:net" +import os from "node:os" +import path from "node:path" + +async function freePort() { + return await new Promise<number>((resolve, reject) => { + const server = net.createServer() + server.once("error", reject) + server.listen(0, () => { + const address = server.address() + if (!address || typeof address === "string") { + server.close(() => reject(new Error("Failed to acquire a free port"))) + return + } + server.close((err) => { + if (err) { + reject(err) + return + } + resolve(address.port) + }) + }) + }) +} + +async function waitForHealth(url: string) { + const timeout = Date.now() + 60_000 + while (Date.now() < timeout) { + const ok = await fetch(url) + .then((r) => r.ok) + .catch(() => false) + if (ok) return + await new Promise((r) => setTimeout(r, 250)) + } + throw new Error(`Timed out waiting for server health: ${url}`) +} + +const appDir = process.cwd() +const repoDir = path.resolve(appDir, "../..") +const opencodeDir = path.join(repoDir, "packages", "opencode") +const modelsJson = path.join(opencodeDir, "test", "tool", "fixtures", "models-api.json") + +const extraArgs = (() => { + const args = process.argv.slice(2) + if (args[0] === "--") return args.slice(1) + return args +})() + +const [serverPort, webPort] = await Promise.all([freePort(), freePort()]) + +const sandbox = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-e2e-")) + +const serverEnv = { + ...process.env, + MODELS_DEV_API_JSON: modelsJson, + OPENCODE_DISABLE_MODELS_FETCH: "true", + OPENCODE_DISABLE_SHARE: "true", + OPENCODE_DISABLE_LSP_DOWNLOAD: "true", + OPENCODE_DISABLE_DEFAULT_PLUGINS: "true", + OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: "true", + OPENCODE_TEST_HOME: path.join(sandbox, "home"), + XDG_DATA_HOME: path.join(sandbox, "share"), + XDG_CACHE_HOME: path.join(sandbox, "cache"), + XDG_CONFIG_HOME: path.join(sandbox, "config"), + XDG_STATE_HOME: path.join(sandbox, "state"), + OPENCODE_E2E_PROJECT_DIR: repoDir, + OPENCODE_E2E_SESSION_TITLE: "E2E Session", + OPENCODE_E2E_MESSAGE: "Seeded for UI e2e", + OPENCODE_E2E_MODEL: "opencode/gpt-5-nano", + OPENCODE_CLIENT: "app", +} satisfies Record<string, string> + +const runnerEnv = { + ...process.env, + PLAYWRIGHT_SERVER_HOST: "localhost", + PLAYWRIGHT_SERVER_PORT: String(serverPort), + VITE_OPENCODE_SERVER_HOST: "localhost", + VITE_OPENCODE_SERVER_PORT: String(serverPort), + PLAYWRIGHT_PORT: String(webPort), +} satisfies Record<string, string> + +const seed = Bun.spawn(["bun", "script/seed-e2e.ts"], { + cwd: opencodeDir, + env: serverEnv, + stdout: "inherit", + stderr: "inherit", +}) + +const seedExit = await seed.exited +if (seedExit !== 0) { + process.exit(seedExit) +} + +const server = Bun.spawn( + [ + "bun", + "dev", + "--", + "--print-logs", + "--log-level", + "WARN", + "serve", + "--port", + String(serverPort), + "--hostname", + "127.0.0.1", + ], + { + cwd: opencodeDir, + env: serverEnv, + stdout: "inherit", + stderr: "inherit", + }, +) + +try { + await waitForHealth(`http://localhost:${serverPort}/global/health`) + + const runner = Bun.spawn(["bun", "test:e2e", ...extraArgs], { + cwd: appDir, + env: runnerEnv, + stdout: "inherit", + stderr: "inherit", + }) + + process.exitCode = await runner.exited +} finally { + server.kill() +} |
