Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ jobs:
run: bun --cwd packages/app test:e2e:local
env:
CI: true
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
OPENCODE_E2E_MODEL: ${{ secrets.OPENCODE_API_KEY != '' && 'opencode/gpt-5' || 'opencode/gpt-5-nano' }}
timeout-minutes: 30

- name: Upload Playwright artifacts
Expand Down
4 changes: 3 additions & 1 deletion packages/app/e2e/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import os from "node:os"
import path from "node:path"
import { execSync } from "node:child_process"
import { terminalAttr, type E2EWindow } from "../src/testing/terminal"
import { createSdk, modKey, resolveDirectory, serverUrl } from "./utils"
import { createSdk, e2eModel, modKey, resolveDirectory, serverUrl } from "./utils"
import {
dropdownMenuTriggerSelector,
dropdownMenuContentSelector,
Expand Down Expand Up @@ -719,9 +719,11 @@ const seed = async <T>(input: {
timeout?: number
attempts?: number
}) => {
const model = e2eModel()
for (let i = 0; i < (input.attempts ?? 2); i++) {
await input.sdk.session.promptAsync({
sessionID: input.sessionID,
...(model && { model }),
agent: "build",
system: seedSystem,
parts: [{ type: "text", text: input.prompt }],
Expand Down
53 changes: 28 additions & 25 deletions packages/app/e2e/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
waitSlug,
waitSession,
} from "./actions"
import { createSdk, dirSlug, getWorktree, sessionPath } from "./utils"
import { createSdk, dirSlug, e2eModel, getWorktree, sessionPath } from "./utils"

export const settingsKey = "settings.v3"

Expand Down Expand Up @@ -125,30 +125,33 @@ export const test = base.extend<TestFixtures, WorkerFixtures>({

async function seedStorage(page: Page, input: { directory: string; extra?: string[] }) {
await seedProjects(page, input)
await page.addInitScript(() => {
const win = window as E2EWindow
win.__opencode_e2e = {
...win.__opencode_e2e,
model: {
enabled: true,
},
prompt: {
enabled: true,
},
terminal: {
enabled: true,
terminals: {},
},
}
localStorage.setItem(
"opencode.global.dat:model",
JSON.stringify({
recent: [{ providerID: "opencode", modelID: "big-pickle" }],
user: [],
variant: {},
}),
)
})
await page.addInitScript(
(model) => {
const win = window as E2EWindow
win.__opencode_e2e = {
...win.__opencode_e2e,
model: {
enabled: true,
},
prompt: {
enabled: true,
},
terminal: {
enabled: true,
terminals: {},
},
}
localStorage.setItem(
"opencode.global.dat:model",
JSON.stringify({
recent: [model],
user: [],
variant: {},
}),
)
},
e2eModel() ?? { providerID: "opencode", modelID: "big-pickle" },
)
}

export { expect }
3 changes: 3 additions & 0 deletions packages/app/e2e/prompt/context.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { test, expect } from "../fixtures"
import type { Page } from "@playwright/test"
import { promptSelector } from "../selectors"
import { withSession } from "../actions"
import { e2eModel } from "../utils"

function contextButton(page: Page) {
return page
Expand All @@ -11,8 +12,10 @@ function contextButton(page: Page) {
}

async function seedContextSession(input: { sessionID: string; sdk: Parameters<typeof withSession>[0] }) {
const model = e2eModel()
await input.sdk.session.promptAsync({
sessionID: input.sessionID,
...(model && { model }),
noReply: true,
parts: [
{
Expand Down
3 changes: 3 additions & 0 deletions packages/app/e2e/prompt/prompt-slash-share.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { test, expect } from "../fixtures"
import { promptSelector } from "../selectors"
import { withSession } from "../actions"
import { e2eModel } from "../utils"

const shareDisabled = process.env.OPENCODE_DISABLE_SHARE === "true" || process.env.OPENCODE_DISABLE_SHARE === "1"

async function seed(sdk: Parameters<typeof withSession>[0], sessionID: string) {
const model = e2eModel()
await sdk.session.promptAsync({
sessionID,
...(model && { model }),
noReply: true,
parts: [{ type: "text", text: "e2e share seed" }],
})
Expand Down
4 changes: 3 additions & 1 deletion packages/app/e2e/session/session-review.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { waitSessionIdle, withSession } from "../actions"
import { test, expect } from "../fixtures"
import { createSdk } from "../utils"
import { createSdk, e2eModel } from "../utils"

const count = 14

Expand Down Expand Up @@ -41,8 +41,10 @@ function edit(file: string, prev: string, next: string) {
}

async function patch(sdk: ReturnType<typeof createSdk>, sessionID: string, patchText: string) {
const model = e2eModel()
await sdk.session.promptAsync({
sessionID,
...(model && { model }),
agent: "build",
system: [
"You are seeding deterministic e2e UI state.",
Expand Down
4 changes: 3 additions & 1 deletion packages/app/e2e/session/session-undo-redo.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Page } from "@playwright/test"
import { test, expect } from "../fixtures"
import { withSession } from "../actions"
import { createSdk, modKey } from "../utils"
import { createSdk, e2eModel, modKey } from "../utils"
import { promptSelector } from "../selectors"

async function seedConversation(input: {
Expand All @@ -17,8 +17,10 @@ async function seedConversation(input: {

const prompt = input.page.locator(promptSelector)
await expect(prompt).toBeVisible()
const model = e2eModel()
await input.sdk.session.promptAsync({
sessionID: input.sessionID,
...(model && { model }),
noReply: true,
parts: [{ type: "text", text: input.token }],
})
Expand Down
3 changes: 3 additions & 0 deletions packages/app/e2e/session/session.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ import {
withSession,
} from "../actions"
import { sessionItemSelector, inlineInputSelector } from "../selectors"
import { e2eModel } from "../utils"

const shareDisabled = process.env.OPENCODE_DISABLE_SHARE === "true" || process.env.OPENCODE_DISABLE_SHARE === "1"

type Sdk = Parameters<typeof withSession>[0]

async function seedMessage(sdk: Sdk, sessionID: string) {
const model = e2eModel()
await sdk.session.promptAsync({
sessionID,
...(model && { model }),
noReply: true,
parts: [{ type: "text", text: "e2e seed" }],
})
Expand Down
9 changes: 9 additions & 0 deletions packages/app/e2e/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ export function createSdk(directory?: string) {
return createOpencodeClient({ baseUrl: serverUrl, directory, throwOnError: true })
}

export function e2eModel() {
const value = process.env.OPENCODE_E2E_MODEL
if (!value) return
const [providerID, ...rest] = value.split("/")
const modelID = rest.join("/")
if (!providerID || !modelID) return
return { providerID, modelID }
}

export async function resolveDirectory(directory: string) {
return createSdk(directory)
.path.get()
Expand Down
2 changes: 1 addition & 1 deletion packages/app/script/e2e-local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const serverEnv = {
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_E2E_MODEL: process.env.OPENCODE_E2E_MODEL || "opencode/gpt-5-nano",
OPENCODE_CLIENT: "app",
OPENCODE_STRICT_CONFIG_DEPS: "true",
} satisfies Record<string, string>
Expand Down
Loading