diff --git a/web/e2e/document-revision-runtime.spec.ts b/web/e2e/document-revision-runtime.spec.ts index 32154def..90f57a02 100644 --- a/web/e2e/document-revision-runtime.spec.ts +++ b/web/e2e/document-revision-runtime.spec.ts @@ -494,6 +494,16 @@ async function ensureControlledIntakeOpen(target: Page, docId: string) { await expect(target.locator('[data-testid="doc-rev-version"]')).toBeVisible({ timeout: 30_000 }); } +/** Prelim/second docs often ship with author_id=0; without claim, currentDocRole is viewer and dblclick is a no-op. */ +async function ensureAuthorClaimedForEdit(target: Page) { + const claim = target.getByRole('button', { name: /认领此文档/ }); + if (await claim.isVisible().catch(() => false)) { + await claim.click(); + await expect(claim).toHaveCount(0, { timeout: 15_000 }); + } + await expect(target.getByText(/双击任意段落就地编辑/)).toBeVisible({ timeout: 30_000 }); +} + /** * V0.1 intake is blocking_when_enabled; prelim_design lives in V0.5 and is * 403'd until intake completes 三权. Drive submit→review→approve via page only. @@ -1564,21 +1574,14 @@ test.describe.serial('document-revision-runtime UI acceptance', () => { const t0 = Date.now(); logs = []; // Intake is locked 已生效受控 after UI-11 三权; conflict must use drafting prelim. + // Prelim ships author_id=0 → resolveCurrentDocRole is viewer until 认领此文档. if (!secondDocId) fail('UI-13b requires secondDocId from UI-11 (prelim drafting)'); const conflictDocId = secondDocId; await openWorkflowDocById(page, conflictDocId); await expect(page.locator('[data-testid="doc-rev-version"]')).toBeVisible({ timeout: 20_000 }); + await ensureAuthorClaimedForEdit(page); const a1Base = await readVersionBadge(page); const etagA1 = await fetchRevisionStateEtag(page, conflictDocId); - // Release A1 human lease so A2 (same user, other browser context) can open the editor. - if (controlledDocId && controlledDocId !== conflictDocId) { - await openWorkflowDocById(page, controlledDocId); - await expect(page.getByTestId('active-document-pane')).toHaveAttribute( - 'data-doc-id', - controlledDocId, - { timeout: 20_000 }, - ); - } const ctxA2 = await page.context().browser()!.newContext(); const pageA2 = await ctxA2.newPage(); @@ -1586,6 +1589,8 @@ test.describe.serial('document-revision-runtime UI acceptance', () => { await pageA2.getByText(PROJECT_NAME, { exact: false }).first().click(); await openWorkflowDocById(pageA2, conflictDocId); await expect(pageA2.locator('[data-testid="doc-rev-version"]')).toBeVisible({ timeout: 30_000 }); + // Same user is now author after A1 claim; wait for edit affordance (not claim button). + await expect(pageA2.getByText(/双击任意段落就地编辑/)).toBeVisible({ timeout: 30_000 }); const a2Base = await readVersionBadge(pageA2); const etagA2 = await fetchRevisionStateEtag(pageA2, conflictDocId); if (a2Base.r !== a1Base.r) { @@ -1597,8 +1602,7 @@ test.describe.serial('document-revision-runtime UI acceptance', () => { const a2Editor = await openFirstPaneEditorAndFill(pageA2, `人工修订段落 ${markerA2}`); await expect(a2Editor).toBeVisible(); - // A1 returns to conflict doc after A2 already holds an open editor draft. - await openWorkflowDocById(page, conflictDocId); + // A1 already on conflict doc; refresh etag then save while A2 keeps an open draft. await expect(page.locator('[data-testid="doc-rev-version"]')).toBeVisible({ timeout: 20_000 }); const etagA1Fresh = await fetchRevisionStateEtag(page, conflictDocId); if (etagA2 !== etagA1Fresh && etagA2 !== etagA1) {