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 <cursoragent@cursor.com>
This commit is contained in:
weichen
2026-09-13 10:09:18 +00:00
co-authored by Cursor
parent 9c8a41982c
commit 46769467bf
5 changed files with 124 additions and 1 deletions
+4
View File
@@ -2,3 +2,7 @@ node_modules
dist
dist-ssr
*.local
playwright-report/
test-results/
blob-report/
playwright/.cache/
+40
View File
@@ -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.
});
});
+46
View File
@@ -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",
+3 -1
View File
@@ -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",
+31
View File
@@ -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.
});