Skip to content

Commit 1ac0980

Browse files
committed
test(app): windows e2e
1 parent 1d6f650 commit 1ac0980

2 files changed

Lines changed: 93 additions & 7 deletions

File tree

.github/workflows/test.yml

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,29 @@ on:
88
workflow_dispatch:
99
jobs:
1010
test:
11-
runs-on: blacksmith-4vcpu-ubuntu-2404
11+
name: test (${{ matrix.settings.name }})
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
settings:
16+
- name: linux
17+
host: blacksmith-4vcpu-ubuntu-2404
18+
playwright: bunx playwright install --with-deps
19+
workdir: .
20+
command: |
21+
git config --global user.email "bot@opencode.ai"
22+
git config --global user.name "opencode"
23+
bun turbo typecheck
24+
bun turbo test
25+
- name: windows
26+
host: windows-latest
27+
playwright: bunx playwright install
28+
workdir: packages/app
29+
command: bun test:e2e
30+
runs-on: ${{ matrix.settings.host }}
31+
defaults:
32+
run:
33+
shell: bash
1234
steps:
1335
- name: Checkout repository
1436
uses: actions/checkout@v4
@@ -20,7 +42,7 @@ jobs:
2042

2143
- name: Install Playwright browsers
2244
working-directory: packages/app
23-
run: bunx playwright install --with-deps
45+
run: ${{ matrix.settings.playwright }}
2446

2547
- name: Seed opencode data
2648
working-directory: packages/opencode
@@ -67,11 +89,8 @@ jobs:
6789
exit 1
6890
6991
- name: run
70-
run: |
71-
git config --global user.email "bot@opencode.ai"
72-
git config --global user.name "opencode"
73-
bun turbo typecheck
74-
bun turbo test
92+
working-directory: ${{ matrix.settings.workdir }}
93+
run: ${{ matrix.settings.command }}
7594
env:
7695
CI: true
7796
MODELS_DEV_API_JSON: ${{ github.workspace }}/packages/opencode/test/tool/fixtures/models-api.json

packages/app/e2e/prompt.spec.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { test, expect } from "./fixtures"
2+
import { promptSelector } from "./utils"
3+
4+
function sessionIDFromUrl(url: string) {
5+
const match = /\/session\/([^/?#]+)/.exec(url)
6+
return match?.[1]
7+
}
8+
9+
test("can send a prompt and receive a reply", async ({ page, sdk, gotoSession }) => {
10+
test.setTimeout(120_000)
11+
12+
const pageErrors: string[] = []
13+
const onPageError = (err: Error) => {
14+
pageErrors.push(err.message)
15+
}
16+
page.on("pageerror", onPageError)
17+
18+
await gotoSession()
19+
20+
const token = `E2E_OK_${Date.now()}`
21+
22+
const prompt = page.locator(promptSelector)
23+
await prompt.click()
24+
await page.keyboard.type(`Reply with exactly: ${token}`)
25+
await page.keyboard.press("Enter")
26+
27+
await expect(page).toHaveURL(/\/session\/[^/?#]+/, { timeout: 30_000 })
28+
29+
const sessionID = (() => {
30+
const id = sessionIDFromUrl(page.url())
31+
if (!id) throw new Error(`Failed to parse session id from url: ${page.url()}`)
32+
return id
33+
})()
34+
35+
try {
36+
await expect
37+
.poll(
38+
async () => {
39+
const messages = await sdk.session.messages({ sessionID, limit: 50 }).then((r) => r.data ?? [])
40+
const assistant = messages
41+
.slice()
42+
.reverse()
43+
.find((m) => m.info.role === "assistant")
44+
45+
return (
46+
assistant?.parts
47+
.filter((p) => p.type === "text")
48+
.map((p) => p.text)
49+
.join("\n") ?? ""
50+
)
51+
},
52+
{ timeout: 90_000 },
53+
)
54+
55+
.toContain(token)
56+
57+
const reply = page.locator('[data-component="text-part"]').filter({ hasText: token }).first()
58+
await expect(reply).toBeVisible({ timeout: 90_000 })
59+
} finally {
60+
page.off("pageerror", onPageError)
61+
await sdk.session.delete({ sessionID }).catch(() => undefined)
62+
}
63+
64+
if (pageErrors.length > 0) {
65+
throw new Error(`Page error(s):\n${pageErrors.join("\n")}`)
66+
}
67+
})

0 commit comments

Comments
 (0)