From 46769467bfb79bd636047a203348e52f49a10e3e Mon Sep 17 00:00:00 2001 From: weichen Date: Sun, 13 Sep 2026 10:09:18 +0000 Subject: [PATCH] chore(web): add Playwright UI-only acceptance skeleton Add @playwright/test, headless config, and document-revision-runtime specs gated by RUN_UI_ACCEPTANCE without mocks, routes, or API/DB fixtures. Co-authored-by: Cursor --- web/.gitignore | 4 ++ web/e2e/document-revision-runtime.spec.ts | 40 ++++++++++++++++++++ web/package-lock.json | 46 +++++++++++++++++++++++ web/package.json | 4 +- web/playwright.config.ts | 31 +++++++++++++++ 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 web/e2e/document-revision-runtime.spec.ts create mode 100644 web/playwright.config.ts diff --git a/web/.gitignore b/web/.gitignore index 40cd7827..8ef435e8 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -2,3 +2,7 @@ node_modules dist dist-ssr *.local +playwright-report/ +test-results/ +blob-report/ +playwright/.cache/ diff --git a/web/e2e/document-revision-runtime.spec.ts b/web/e2e/document-revision-runtime.spec.ts new file mode 100644 index 00000000..ff702f44 --- /dev/null +++ b/web/e2e/document-revision-runtime.spec.ts @@ -0,0 +1,40 @@ +import { test, expect } from '@playwright/test'; + +/** + * Document revision runtime — Ubuntu headless UI acceptance skeleton. + * + * Hard rules (see `.doc/ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md`): + * - Real browser against BASE_URL (default http://127.0.0.1:8080) + * - NO page.route / request mocking + * - NO API/DB fixtures; create project and drive squad via the page only + * - Requires RUN_UI_ACCEPTANCE=1 and a live pi-agent stack + * + * This file is a skeleton: cases are skipped unless RUN_UI_ACCEPTANCE=1 so + * normal `npm test` / CI unit gates stay green without Playwright browsers. + */ + +const runAcceptance = process.env.RUN_UI_ACCEPTANCE === '1'; + +test.describe('document-revision-runtime UI acceptance', () => { + test.skip(!runAcceptance, 'set RUN_UI_ACCEPTANCE=1 with real env-service.dev + pi-agent'); + + test('UI-01 login and open/create project workbench', async ({ page }) => { + await page.goto('/'); + // Page-visible workbench chrome (selectors refined during real acceptance run). + await expect(page.locator('body')).toBeVisible(); + // TODO(acceptance): fill login → create/enter project → assert three-pane workbench. + }); + + test('UI-05a/b high-risk pending confirm/reject via toolbar', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('body')).toBeVisible(); + // TODO(acceptance): after real squad high-risk pending — + // assert 「待确认报告」 visible; confirm advances version; reject keeps head. + }); + + test('UI-06 save increments revision then survives hard refresh', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('body')).toBeVisible(); + // TODO(acceptance): edit block → save → r increments → reload → body persists. + }); +}); diff --git a/web/package-lock.json b/web/package-lock.json index 9a695a65..723873a4 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -20,6 +20,7 @@ "xlsx": "^0.18.5" }, "devDependencies": { + "@playwright/test": "^1.63.0", "@types/katex": "^0.16.8", "@types/node": "^24.10.1", "@types/react": "^19.2.7", @@ -876,6 +877,22 @@ "node": "^22.20 || ^24.12 || >=25" } }, + "node_modules/@playwright/test": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0.tgz", + "integrity": "sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.63.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-rc.3", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", @@ -3026,6 +3043,35 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", + "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.63.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright-core": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", + "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/points-on-curve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", diff --git a/web/package.json b/web/package.json index 143d955f..efc5150d 100644 --- a/web/package.json +++ b/web/package.json @@ -7,7 +7,8 @@ "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", - "test": "tsx --test \"src/**/!(*InteractiveCard*|*chatWindowArtifact*|*deliverableSync*).test.ts\" && vitest run src/components/chat/InteractiveCard.test.ts src/components/chat/chatWindowArtifact.test.ts src/components/chat/deliverableSync.test.ts" + "test": "tsx --test \"src/**/!(*InteractiveCard*|*chatWindowArtifact*|*deliverableSync*).test.ts\" && vitest run src/components/chat/InteractiveCard.test.ts src/components/chat/chatWindowArtifact.test.ts src/components/chat/deliverableSync.test.ts", + "test:ui-acceptance": "RUN_UI_ACCEPTANCE=1 playwright test e2e/document-revision-runtime.spec.ts --project=chromium" }, "dependencies": { "@tanstack/react-virtual": "^3.14.11", @@ -22,6 +23,7 @@ "xlsx": "^0.18.5" }, "devDependencies": { + "@playwright/test": "^1.63.0", "@types/katex": "^0.16.8", "@types/node": "^24.10.1", "@types/react": "^19.2.7", diff --git a/web/playwright.config.ts b/web/playwright.config.ts new file mode 100644 index 00000000..2e5cefde --- /dev/null +++ b/web/playwright.config.ts @@ -0,0 +1,31 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Ubuntu Server headless UI acceptance config (DOCREV runtime). + * Enable only when RUN_UI_ACCEPTANCE=1 against a real dev stack — no mocks. + */ +const runAcceptance = process.env.RUN_UI_ACCEPTANCE === '1'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: false, + forbidOnly: !!process.env.CI, + retries: 0, + workers: 1, + reporter: [['list'], ['html', { open: 'never', outputFolder: 'playwright-report' }]], + use: { + baseURL: process.env.BASE_URL || 'http://127.0.0.1:8080', + headless: true, + trace: runAcceptance ? 'on' : 'off', + screenshot: runAcceptance ? 'on' : 'off', + video: runAcceptance ? 'on' : 'off', + locale: 'zh-CN', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + // Do not start webServer here — acceptance assumes env-service.dev is already up. +});