fix(e2e): approve intake via 三权 before UI-11 prelim_design

V0.1 blocking intake caused tasks/runs 403 for V0.5 prelim_design;
drive submit/review/approve on page and accept bd_prelim_design keys.
This commit is contained in:
WeiCHEN
2026-09-22 23:40:22 +08:00
parent 5e7fb240c3
commit e6b23772c9
+88 -6
View File
@@ -454,21 +454,92 @@ async function openWorkflowDocByControlledTaskKey(
const trigger = page.getByTestId('doc-selector-trigger');
await expect(trigger).toBeVisible({ timeout: 15_000 });
await trigger.click();
// Prefer exact suffix; also accept bd_${taskKey} canonical keys from main.v2.
const item = page
.locator(`.dropdown-menu button[data-doc-id^="doc_proj"][data-doc-id$="_${taskKey}"]`)
.locator(
[
`.dropdown-menu button[data-doc-id^="doc_proj"][data-doc-id$="_bd_${taskKey}"]`,
`.dropdown-menu button[data-doc-id^="doc_proj"][data-doc-id$="_${taskKey}"]`,
].join(', '),
)
.first();
if ((await item.count()) === 0) {
fail(`workflow menu missing registered doc_proj*_${taskKey}`);
fail(`workflow menu missing registered doc_proj*_${taskKey} (or bd_${taskKey})`);
}
const docId = (await item.getAttribute('data-doc-id')) || '';
const title = (await item.getAttribute('data-doc-title')) || '';
if (!new RegExp(`^doc_proj\\d+_${taskKey}$`).test(docId)) {
fail(`expected doc_proj{n}_${taskKey}, got ${JSON.stringify(docId)}`);
if (!new RegExp(`^doc_proj\\d+_(?:bd_)?${taskKey}$`).test(docId)) {
fail(`expected doc_proj{n}_(?:bd_)?${taskKey}, got ${JSON.stringify(docId)}`);
}
await item.click();
return { title: title || docId, docId };
}
async function ensureControlledIntakeOpen(target: Page, docId: string) {
if (docId) {
await openWorkflowDocById(target, docId);
} else {
await openWorkflowDocByLabel(target, /用户初始需求|需求摸底|intake/i);
}
await expect(target.locator('[data-testid="doc-rev-version"]')).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.
*/
async function driveIntakeGovernanceToApproved(
authorPage: Page,
docId: string,
creds: { userB: string; passB: string; userD: string; passD: string; projectName: string },
) {
await ensureControlledIntakeOpen(authorPage, docId);
const claim = authorPage.getByRole('button', { name: /认领此文档/ });
if (await claim.isVisible().catch(() => false)) {
await claim.click();
await expect(claim).toHaveCount(0, { timeout: 15_000 });
}
const submit = authorPage.getByRole('button', { name: /提交送审/ });
await expect(submit).toBeVisible({ timeout: 30_000 });
await submit.click();
await expect(authorPage.getByRole('button', { name: /提交送审/ })).toHaveCount(0, {
timeout: 30_000,
});
const browser = authorPage.context().browser();
if (!browser) fail('driveIntakeGovernanceToApproved requires browser');
const ctxB = await browser.newContext();
const pageB = await ctxB.newPage();
await login(pageB, creds.userB, creds.passB);
await pageB.getByText(creds.projectName, { exact: false }).first().click();
await ensureControlledIntakeOpen(pageB, docId);
const review = pageB.getByRole('button', { name: /审核通过/ });
await expect(review).toBeVisible({ timeout: 30_000 });
await review.click();
await expect(pageB.getByRole('button', { name: /审核通过/ })).toHaveCount(0, { timeout: 30_000 });
await ctxB.close();
const ctxD = await browser.newContext();
const pageD = await ctxD.newPage();
await login(pageD, creds.userD, creds.passD);
await pageD.getByText(creds.projectName, { exact: false }).first().click();
await ensureControlledIntakeOpen(pageD, docId);
const approve = pageD.getByRole('button', { name: /终审批准/ });
await expect(approve).toBeVisible({ timeout: 30_000 });
await approve.click();
await expect(pageD.getByRole('button', { name: /终审批准/ })).toHaveCount(0, { timeout: 60_000 });
await ctxD.close();
// Author session: reload so stage banner / task scope picks up approved intake.
await authorPage.reload();
await expect(authorPage.getByText(creds.projectName, { exact: false }).first()).toBeVisible({
timeout: 30_000,
});
await ensureControlledIntakeOpen(authorPage, docId);
await expect(authorPage.getByText('必需文档尚未批准')).toHaveCount(0, { timeout: 90_000 });
}
async function openWorkflowDocById(page: Page, docId: string): Promise<void> {
if (!docId) fail('openWorkflowDocById requires docId');
await selectDeliverableCategory(page, requiredCategoryForDocOpen({ kind: 'exact-id', docId }));
@@ -1267,6 +1338,15 @@ test.describe.serial('document-revision-runtime UI acceptance', () => {
test('UI-11 chat second controlled doc + page upload attachment', async () => {
const t0 = Date.now();
logs = [];
// prelim_design is V0.5; V0.1 intake must finish 三权 or tasks/runs returns 403.
if (!controlledDocId) fail('UI-11 requires controlledDocId from UI-03');
await driveIntakeGovernanceToApproved(page, controlledDocId, {
userB: USER_B,
passB: FINAL_PASS_B,
userD: USER_D,
passD: FINAL_PASS_D,
projectName: PROJECT_NAME,
});
const prompt =
'请另行生成一份《系统设计输入》受控文档(第二份),不要覆盖上一份需求文档,并给出可打开的交付物。';
const taskRunWait = waitForTasksRunsPost(page);
@@ -1276,8 +1356,10 @@ test.describe.serial('document-revision-runtime UI acceptance', () => {
fail(`UI-11 tasks/runs must be HTTP 202, got ${taskRes.status()}`);
}
const taskBody = taskRes.request().postDataJSON() as { task_key?: string };
if (taskBody.task_key !== 'prelim_design') {
fail(`UI-11 task_key must be prelim_design, got ${JSON.stringify(taskBody.task_key)}`);
if (taskBody.task_key !== 'prelim_design' && taskBody.task_key !== 'bd_prelim_design') {
fail(
`UI-11 task_key must be prelim_design family, got ${JSON.stringify(taskBody.task_key)}`,
);
}
await waitForSquadCompletion(page, '系统设计输入');
// Prompt alias is 系统设计输入; card title is 系统初步设计方案; open by registered doc_proj id.