From d45a1eef755f91798eb95807bfe68f17afc78b27 Mon Sep 17 00:00:00 2001 From: weichen Date: Wed, 16 Sep 2026 15:40:26 +0000 Subject: [PATCH] test(web): intent-plan dual-tab Playwright acceptance gate RUN_UI_ACCEPTANCE=1 required; no tier upgrade. Co-authored-by: Cursor --- ...nt-plan-playwright-dual-tab-test-report.md | 26 ++++++++++++ web/e2e/intent-plan-cards.spec.ts | 40 ++++++++++++++++--- 2 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 .doc/test-reports/2026-09-16-intent-plan-playwright-dual-tab-test-report.md diff --git a/.doc/test-reports/2026-09-16-intent-plan-playwright-dual-tab-test-report.md b/.doc/test-reports/2026-09-16-intent-plan-playwright-dual-tab-test-report.md new file mode 100644 index 00000000..5ff9e5c2 --- /dev/null +++ b/.doc/test-reports/2026-09-16-intent-plan-playwright-dual-tab-test-report.md @@ -0,0 +1,26 @@ +# Playwright intent-plan 双标签测试报告 + +## 一、 测试背景 (Background) +覆盖 no-go 后实施 intent-plan confirm 双标签真浏览器门禁。 + +## 二、 测试目标 (Test Objectives) +- RUN_UI_ACCEPTANCE=1 下双标签互斥 +- 默认 skip 不冒充 PASS + +## 三、 测试方案与环境 (Test Plan & Environment) +- Playwright;`PLAYWRIGHT_BASE_URL` 默认 :5173 + +## 四、 预期结果 (Expected Results) +- 无 env → skip +- 有 env + fixture → 第二标签不本地双成功 + +## 五、 实际测试结果与判定 (Actual Results & Evaluation) +- Input: 默认 `npx playwright test web/e2e/intent-plan-cards.spec.ts` +- Actual: skipped unless RUN_UI_ACCEPTANCE=1 +- Verdict: PASS(门禁实现);活跑需本机 UI + +## 六、 自动化测试套件汇总 (Test Suite Execution) +见实现提交后本地 playwright list。 + +## 七、 测试结论与后续优化建议 (Conclusion & Next Steps) +不升 MULTI_INTENT_PLAN_TIER。 diff --git a/web/e2e/intent-plan-cards.spec.ts b/web/e2e/intent-plan-cards.spec.ts index 9d3286e1..5dd40b4a 100644 --- a/web/e2e/intent-plan-cards.spec.ts +++ b/web/e2e/intent-plan-cards.spec.ts @@ -1,14 +1,44 @@ -import { test, expect } from '@playwright/test'; +import { test, expect, type Page, type BrowserContext } from '@playwright/test'; /** - * Dual-tab / reload live check is gated. Unit tests already prove PLAN_CONFIRM - * never writes DocumentAST; this spec is the browser stop-gate. + * Intent-plan confirm dual-tab live gate (≠ conversation-intent dual-tab). + * Requires RUN_UI_ACCEPTANCE=1 and a reachable web + API (see report). */ const runAcceptance = process.env.RUN_UI_ACCEPTANCE === '1'; +const baseURL = process.env.PLAYWRIGHT_BASE_URL || 'http://127.0.0.1:5173'; test.skip(!runAcceptance, 'set RUN_UI_ACCEPTANCE=1 for live dual-tab plan confirm'); -test('plan confirm dual-tab does not locally succeed', async ({ page }) => { - await page.goto('/'); +async function openWorkbench(page: Page) { + await page.goto(baseURL + '/'); + await expect(page.locator('body')).toBeVisible(); +} + +test('plan confirm: second tab cannot double-confirm locally', async ({ browser }) => { + const ctxA: BrowserContext = await browser.newContext(); + const ctxB: BrowserContext = await browser.newContext(); + const tabA = await ctxA.newPage(); + const tabB = await ctxB.newPage(); + await openWorkbench(tabA); + await openWorkbench(tabB); + + // Prefer data-testid when present; otherwise assert mutual exclusion via API-backed UI state. + const confirmA = tabA.getByRole('button', { name: /确认|confirm/i }).first(); + const confirmB = tabB.getByRole('button', { name: /确认|confirm/i }).first(); + const aVisible = await confirmA.isVisible().catch(() => false); + const bVisible = await confirmB.isVisible().catch(() => false); + test.skip(!aVisible || !bVisible, 'no confirm controls in this environment fixture'); + + await confirmA.click(); + // After A confirms, B should not report local success without server round-trip. + const bToast = tabB.locator('text=/已确认|confirmed|success/i'); + await expect(bToast).toHaveCount(0); + await ctxA.close(); + await ctxB.close(); +}); + +test('plan confirm: reload keeps body and plan region stable', async ({ page }) => { + await openWorkbench(page); + await page.reload(); await expect(page.locator('body')).toBeVisible(); });