From ab7e89873ff22b2d58546915adb1830ba7daf37a Mon Sep 17 00:00:00 2001 From: Devvyn <22340871+opticon454@users.noreply.github.com> Date: Fri, 2 Oct 2026 22:05:35 +0800 Subject: [PATCH] ci: nightly browser suite; fix stale session-id extraction in browser tests WIP: the suite still has failures on a clean master that are not fixed here. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/browser-suite.yml | 61 +++++++++++++++++++++++++++++ .github/workflows/ci.yml | 2 + test/opencode-resize.test.ts | 15 ++++--- test/perf-browser.test.ts | 3 +- 4 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/browser-suite.yml diff --git a/.github/workflows/browser-suite.yml b/.github/workflows/browser-suite.yml new file mode 100644 index 00000000..7581e07c --- /dev/null +++ b/.github/workflows/browser-suite.yml @@ -0,0 +1,61 @@ +name: Browser suite + +# The per-push CI gate deliberately skips the Playwright-driven suite (config/test-suites.ts), +# which has twice let two PRs that conflict semantically merge green. This job runs it on a +# schedule and on demand, so a browser-only regression (the Shift+Enter keypress bug was one) +# is caught within a day instead of by a user. It is NOT a merge gate: a red run means "look", +# and it never blocks a push or a PR. +# +# Needs: chromium (installed below), tmux, and the live server the tests start themselves. +# Not run here: test:mobile (per-machine PNG baselines), test:perf (wall-clock), and +# codex-predictive-echo (needs a real, authenticated codex binary). + +on: + schedule: + - cron: '17 3 * * *' + workflow_dispatch: + +permissions: + contents: read + +jobs: + browser: + name: Playwright browser suite + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 22 + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Install tmux + run: | + if ! command -v tmux >/dev/null; then + sudo apt-get update -qq + sudo apt-get install -y tmux + fi + + - name: Install chromium + run: npx playwright install --with-deps chromium + + - name: Run the browser suite + run: npm run test:browser -- --exclude test/codex-predictive-echo.test.ts + + - name: Keep the failure artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: browser-suite-results + path: | + test-results/ + screenshots-echo-diag/ + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe86f671..4df79374 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -219,6 +219,8 @@ jobs: run: npx vitest run working-directory: packages/xterm-zerolag-input +# The browser suite also runs nightly (and on demand) in .github/workflows/browser-suite.yml; +# that job is informational and never gates a push or a PR. # Note: three suites are excluded from CI, each with its own local runner: # npm run test:browser Playwright + chromium (+ a live server, and a real # codex binary for codex-predictive-echo) diff --git a/test/opencode-resize.test.ts b/test/opencode-resize.test.ts index ed5540a5..eea954b1 100644 --- a/test/opencode-resize.test.ts +++ b/test/opencode-resize.test.ts @@ -123,7 +123,8 @@ describe('OpenCode session initial resize', () => { body: JSON.stringify({ workingDir: '/tmp', name: 'oc-resize-test' }), }); const data = await res.json(); - return data.id ?? data.session?.id; + // POST /api/sessions answers in the { success, data: { session } } envelope. + return data.data?.session?.id ?? data.id ?? data.session?.id; }); expect(sessionId).toBeTruthy(); @@ -168,7 +169,8 @@ describe('OpenCode session initial resize', () => { body: JSON.stringify({ workingDir: '/tmp', name: 'oc-earlyret-test' }), }); const data = await res.json(); - return data.id ?? data.session?.id; + // POST /api/sessions answers in the { success, data: { session } } envelope. + return data.data?.session?.id ?? data.id ?? data.session?.id; }); expect(sessionId).toBeTruthy(); @@ -219,7 +221,8 @@ describe('OpenCode session initial resize', () => { body: JSON.stringify({ workingDir: '/tmp', name: 'oc-refresh-test' }), }); const data = await res.json(); - return data.id ?? data.session?.id; + // POST /api/sessions answers in the { success, data: { session } } envelope. + return data.data?.session?.id ?? data.id ?? data.session?.id; }); expect(sessionId).toBeTruthy(); @@ -287,7 +290,8 @@ describe('OpenCode close modal text', () => { body: JSON.stringify({ workingDir: '/tmp', name: 'oc-close-test', mode: 'opencode' }), }); const data = await res.json(); - return data.id ?? data.session?.id; + // POST /api/sessions answers in the { success, data: { session } } envelope. + return data.data?.session?.id ?? data.id ?? data.session?.id; }); expect(sessionId).toBeTruthy(); @@ -329,7 +333,8 @@ describe('OpenCode close modal text', () => { body: JSON.stringify({ workingDir: '/tmp', name: 'cc-close-test' }), }); const data = await res.json(); - return data.id ?? data.session?.id; + // POST /api/sessions answers in the { success, data: { session } } envelope. + return data.data?.session?.id ?? data.id ?? data.session?.id; }); expect(sessionId).toBeTruthy(); diff --git a/test/perf-browser.test.ts b/test/perf-browser.test.ts index 39f13a6c..97c65229 100644 --- a/test/perf-browser.test.ts +++ b/test/perf-browser.test.ts @@ -69,7 +69,8 @@ async function createSession(page: Page, name: string): Promise { body: JSON.stringify({ workingDir: '/tmp', name: n }), }); const data = await res.json(); - return data.id ?? data.session?.id; + // POST /api/sessions answers in the { success, data: { session } } envelope. + return data.data?.session?.id ?? data.id ?? data.session?.id; }, name); return result as string; }