From dd19c3d8f2cfbb7d1b157bbe6f5a9a969cb6c239 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Sun, 18 Jan 2026 05:43:34 -0600 Subject: [PATCH] test(app): e2e utilities --- packages/app/e2e/home.spec.ts | 15 ++++------ packages/app/e2e/navigation.spec.ts | 21 +++----------- packages/app/e2e/palette.spec.ts | 26 +++-------------- packages/app/e2e/session.spec.ts | 21 +++----------- packages/app/e2e/terminal.spec.ts | 28 ++++-------------- packages/app/e2e/utils.ts | 45 +++++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 87 deletions(-) create mode 100644 packages/app/e2e/utils.ts diff --git a/packages/app/e2e/home.spec.ts b/packages/app/e2e/home.spec.ts index 29a070609..5bb701076 100644 --- a/packages/app/e2e/home.spec.ts +++ b/packages/app/e2e/home.spec.ts @@ -1,24 +1,21 @@ import { test, expect } from "@playwright/test" +import { serverName } from "./utils" -test("home renders and shows an open project entrypoint", async ({ page }) => { +test("home renders and shows core entrypoints", async ({ page }) => { await page.goto("/") - await expect(page.getByText("Recent projects").or(page.getByText("No recent projects"))).toBeVisible() await expect(page.getByRole("button", { name: "Open project" }).first()).toBeVisible() + await expect(page.getByRole("button", { name: serverName })).toBeVisible() }) test("server picker dialog opens from home", async ({ page }) => { - const host = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" - const port = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" - const name = `${host}:${port}` - await page.goto("/") - const trigger = page.getByRole("button", { name }) + const trigger = page.getByRole("button", { name: serverName }) await expect(trigger).toBeVisible() await trigger.click() - const dialog = page.getByRole("dialog", { name: "Servers" }) + const dialog = page.getByRole("dialog") await expect(dialog).toBeVisible() - await expect(dialog.getByPlaceholder("Search servers")).toBeVisible() + await expect(dialog.getByRole("textbox").first()).toBeVisible() }) diff --git a/packages/app/e2e/navigation.spec.ts b/packages/app/e2e/navigation.spec.ts index 2783c5222..4d0d3b2b9 100644 --- a/packages/app/e2e/navigation.spec.ts +++ b/packages/app/e2e/navigation.spec.ts @@ -1,24 +1,11 @@ import { test, expect } from "@playwright/test" -import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" -import { base64Encode } from "@opencode-ai/util/encode" - -const host = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" -const port = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" -const url = `http://${host}:${port}` - -async function getWorktree() { - const sdk = createOpencodeClient({ baseUrl: url, throwOnError: true }) - const result = await sdk.path.get() - const data = result.data - if (!data?.worktree) throw new Error(`Failed to resolve a worktree from ${url}/path`) - return data.worktree -} +import { dirPath, dirSlug, getWorktree, promptSelector } from "./utils" test("project route redirects to /session", async ({ page }) => { const directory = await getWorktree() - const slug = base64Encode(directory) + const slug = dirSlug(directory) - await page.goto(`/${slug}`) + await page.goto(dirPath(directory)) await expect(page).toHaveURL(new RegExp(`/${slug}/session`)) - await expect(page.locator('[data-component="prompt-input"]')).toBeVisible() + await expect(page.locator(promptSelector)).toBeVisible() }) diff --git a/packages/app/e2e/palette.spec.ts b/packages/app/e2e/palette.spec.ts index 062945629..bad09aab9 100644 --- a/packages/app/e2e/palette.spec.ts +++ b/packages/app/e2e/palette.spec.ts @@ -1,29 +1,11 @@ import { test, expect } from "@playwright/test" -import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" -import { base64Encode } from "@opencode-ai/util/encode" - -const host = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" -const port = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" -const url = `http://${host}:${port}` - -async function getWorktree() { - const sdk = createOpencodeClient({ baseUrl: url, throwOnError: true }) - const result = await sdk.path.get() - const data = result.data - if (!data?.worktree) throw new Error(`Failed to resolve a worktree from ${url}/path`) - return data.worktree -} - -const mod = process.platform === "darwin" ? "Meta" : "Control" +import { gotoSession, modKey, promptSelector } from "./utils" test("search palette opens and closes", async ({ page }) => { - const directory = await getWorktree() - const slug = base64Encode(directory) + await gotoSession(page) + await expect(page.locator(promptSelector)).toBeVisible() - await page.goto(`/${slug}/session`) - await expect(page.locator('[data-component="prompt-input"]')).toBeVisible() - - await page.keyboard.press(`${mod}+P`) + await page.keyboard.press(`${modKey}+P`) const dialog = page.getByRole("dialog") await expect(dialog).toBeVisible() diff --git a/packages/app/e2e/session.spec.ts b/packages/app/e2e/session.spec.ts index e1ca12449..d44736a4f 100644 --- a/packages/app/e2e/session.spec.ts +++ b/packages/app/e2e/session.spec.ts @@ -1,22 +1,9 @@ import { test, expect } from "@playwright/test" -import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" -import { base64Encode } from "@opencode-ai/util/encode" - -const host = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" -const port = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" -const url = `http://${host}:${port}` - -async function getWorktree() { - const sdk = createOpencodeClient({ baseUrl: url, throwOnError: true }) - const result = await sdk.path.get() - const data = result.data - if (!data?.worktree) throw new Error(`Failed to resolve a worktree from ${url}/path`) - return data.worktree -} +import { createSdk, getWorktree, promptSelector, sessionPath } from "./utils" test("can open an existing session and type into the prompt", async ({ page }) => { const directory = await getWorktree() - const sdk = createOpencodeClient({ baseUrl: url, directory, throwOnError: true }) + const sdk = createSdk(directory) const title = `e2e smoke ${Date.now()}` const created = await sdk.session.create({ title }).then((r) => r.data) @@ -24,9 +11,9 @@ test("can open an existing session and type into the prompt", async ({ page }) = const sessionID = created.id try { - await page.goto(`/${base64Encode(directory)}/session/${sessionID}`) + await page.goto(sessionPath(directory, sessionID)) - const prompt = page.locator('[data-component="prompt-input"]') + const prompt = page.locator(promptSelector) await expect(prompt).toBeVisible() await prompt.click() diff --git a/packages/app/e2e/terminal.spec.ts b/packages/app/e2e/terminal.spec.ts index 9bb9947fe..8f90a3c0c 100644 --- a/packages/app/e2e/terminal.spec.ts +++ b/packages/app/e2e/terminal.spec.ts @@ -1,33 +1,17 @@ import { test, expect } from "@playwright/test" -import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" -import { base64Encode } from "@opencode-ai/util/encode" - -const host = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" -const port = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" -const url = `http://${host}:${port}` - -async function getWorktree() { - const sdk = createOpencodeClient({ baseUrl: url, throwOnError: true }) - const result = await sdk.path.get() - const data = result.data - if (!data?.worktree) throw new Error(`Failed to resolve a worktree from ${url}/path`) - return data.worktree -} +import { gotoSession, promptSelector, terminalSelector, terminalToggleKey } from "./utils" test("terminal panel can be toggled", async ({ page }) => { - const directory = await getWorktree() - const slug = base64Encode(directory) + await gotoSession(page) + await expect(page.locator(promptSelector)).toBeVisible() - await page.goto(`/${slug}/session`) - await expect(page.locator('[data-component="prompt-input"]')).toBeVisible() - - const terminal = page.locator('[data-component="terminal"]') + const terminal = page.locator(terminalSelector) const initiallyOpen = await terminal.isVisible() if (initiallyOpen) { - await page.keyboard.press("Control+Backquote") + await page.keyboard.press(terminalToggleKey) await expect(terminal).toHaveCount(0) } - await page.keyboard.press("Control+Backquote") + await page.keyboard.press(terminalToggleKey) await expect(terminal).toBeVisible() }) diff --git a/packages/app/e2e/utils.ts b/packages/app/e2e/utils.ts new file mode 100644 index 000000000..c18b36802 --- /dev/null +++ b/packages/app/e2e/utils.ts @@ -0,0 +1,45 @@ +import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" +import { base64Encode } from "@opencode-ai/util/encode" +import type { Page } from "@playwright/test" + +export const serverHost = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" +export const serverPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" + +export const serverUrl = `http://${serverHost}:${serverPort}` +export const serverName = `${serverHost}:${serverPort}` + +export const modKey = process.platform === "darwin" ? "Meta" : "Control" +export const terminalToggleKey = "Control+Backquote" + +export const promptSelector = '[data-component="prompt-input"]' +export const terminalSelector = '[data-component="terminal"]' + +export function createSdk(directory?: string) { + return createOpencodeClient({ baseUrl: serverUrl, directory, throwOnError: true }) +} + +export async function getWorktree() { + const sdk = createSdk() + const result = await sdk.path.get() + const data = result.data + if (!data?.worktree) throw new Error(`Failed to resolve a worktree from ${serverUrl}/path`) + return data.worktree +} + +export function dirSlug(directory: string) { + return base64Encode(directory) +} + +export function dirPath(directory: string) { + return `/${dirSlug(directory)}` +} + +export function sessionPath(directory: string, sessionID?: string) { + return `${dirPath(directory)}/session${sessionID ? `/${sessionID}` : ""}` +} + +export async function gotoSession(page: Page, sessionID?: string) { + const directory = await getWorktree() + await page.goto(sessionPath(directory, sessionID)) + return { directory, slug: dirSlug(directory) } +}