fix(e2e): activate workflow in UI-01 before squad tasks
Product gate blocks document tasks until a human-approval workflow is active; add admin as third member for 三权 and drive 配置工作流.
This commit is contained in:
@@ -218,6 +218,74 @@ async function logoutViaUI(page: Page) {
|
||||
await expect(page.getByPlaceholder(/系统用户名/)).toBeVisible({ timeout: 20_000 });
|
||||
}
|
||||
|
||||
async function goToWorkflowDutyStep(page: Page) {
|
||||
const approval = page.locator('label', { hasText: '纳入人工审批' }).first();
|
||||
const selectHint = page.getByText('选择要激活的已发布工作流版本');
|
||||
await expect(selectHint.or(approval)).toBeVisible({ timeout: 20_000 });
|
||||
if (await approval.isVisible().catch(() => false)) return;
|
||||
await page.getByRole('button', { name: /下一步/ }).click();
|
||||
await expect(approval).toBeVisible({ timeout: 20_000 });
|
||||
}
|
||||
|
||||
function dutyRoleSelect(page: Page, placeholder: '作者' | '审核' | '批准') {
|
||||
return page
|
||||
.locator('select')
|
||||
.filter({ has: page.getByRole('option', { name: placeholder, exact: true }) })
|
||||
.first();
|
||||
}
|
||||
|
||||
/** Activate workflow with first intake doc under human approval + full 三权. */
|
||||
async function activateProjectWorkflow(page: Page) {
|
||||
await page.getByRole('button', { name: '配置工作流' }).click();
|
||||
await goToWorkflowDutyStep(page);
|
||||
const toggles = page.locator('label', { hasText: '纳入人工审批' });
|
||||
const toggleCount = await toggles.count();
|
||||
for (let i = 1; i < toggleCount; i += 1) {
|
||||
const box = toggles.nth(i).locator('input[type="checkbox"]');
|
||||
if (await box.isChecked()) await box.uncheck();
|
||||
}
|
||||
const firstToggle = toggles.first().locator('input[type="checkbox"]');
|
||||
if (!(await firstToggle.isChecked())) await firstToggle.check();
|
||||
const author = dutyRoleSelect(page, '作者');
|
||||
await expect(author).toBeVisible({ timeout: 10_000 });
|
||||
const values = (
|
||||
await author
|
||||
.locator('option')
|
||||
.evaluateAll((nodes) => nodes.map((n) => (n as HTMLOptionElement).value))
|
||||
).filter(Boolean);
|
||||
if (values.length < 3) {
|
||||
fail(`workflow activate needs ≥3 project members for 三权, got ${values.length}`);
|
||||
}
|
||||
await author.selectOption(values[0]);
|
||||
await dutyRoleSelect(page, '审核').selectOption(values[1]);
|
||||
await dutyRoleSelect(page, '批准').selectOption(values[2]);
|
||||
await page.getByRole('button', { name: /校验并预览/ }).click();
|
||||
await expect(page.getByText('激活预览')).toBeVisible({ timeout: 20_000 });
|
||||
await page.getByRole('button', { name: '确认激活' }).click();
|
||||
await expect(page.getByText('运行中')).toBeVisible({ timeout: 20_000 });
|
||||
// Close settings if still open.
|
||||
const closeBtn = page.getByRole('button', { name: '关闭' });
|
||||
if (await closeBtn.isVisible().catch(() => false)) await closeBtn.click();
|
||||
}
|
||||
|
||||
async function toggleCreateProjectMember(
|
||||
projectModal: ReturnType<Page['locator']>,
|
||||
displayName: string,
|
||||
role?: 'reviewer' | 'viewer' | 'editor',
|
||||
) {
|
||||
const memberName = projectModal.getByText(displayName, { exact: true });
|
||||
await expect(memberName).toBeVisible({ timeout: 15_000 });
|
||||
await memberName.locator('xpath=ancestor::div[contains(@style,"cursor: pointer")][1]').click();
|
||||
if (!role) return;
|
||||
const memberContainer = memberName.locator(
|
||||
'xpath=ancestor::div[contains(@style,"justify-content: space-between")][1]',
|
||||
);
|
||||
const memberRole = memberContainer.locator('select');
|
||||
await expect(memberRole).toBeEnabled();
|
||||
await memberRole.selectOption(role);
|
||||
await expect(memberRole).toHaveValue(role);
|
||||
}
|
||||
|
||||
async function openAdminConsole(page: Page) {
|
||||
await shot(page, 'UI-00-admin-logged-in.png');
|
||||
const btn = page.locator('button[title*="系统管理与准入治理"]');
|
||||
@@ -765,20 +833,9 @@ test.describe.serial('document-revision-runtime UI acceptance', () => {
|
||||
const desc = projectModal.locator('textarea');
|
||||
if ((await desc.count()) === 0) fail('project form missing required description textarea');
|
||||
await desc.fill('用于骨科微创手术的双频超声吸引与止血,需符合 GB 9706.1 与相关法规要求。');
|
||||
// Select B through the visible member row, then assign a real project duty.
|
||||
const memberName = projectModal.getByText(`协作者B-${suffix}`, { exact: true });
|
||||
await expect(memberName).toBeVisible({ timeout: 15_000 });
|
||||
const memberToggle = memberName.locator(
|
||||
'xpath=ancestor::div[contains(@style,"cursor: pointer")][1]',
|
||||
);
|
||||
await memberToggle.click();
|
||||
const memberContainer = memberName.locator(
|
||||
'xpath=ancestor::div[contains(@style,"justify-content: space-between")][1]',
|
||||
);
|
||||
const memberRole = memberContainer.locator('select');
|
||||
await expect(memberRole).toBeEnabled();
|
||||
await memberRole.selectOption('reviewer');
|
||||
await expect(memberRole).toHaveValue('reviewer');
|
||||
// B = reviewer; 系统管理员 = third member so workflow 三权 can activate (C stays non-member for UI-12).
|
||||
await toggleCreateProjectMember(projectModal, `协作者B-${suffix}`, 'reviewer');
|
||||
await toggleCreateProjectMember(projectModal, '系统管理员', 'viewer');
|
||||
await projectModal.getByRole('button', { name: /确认立项/ }).click();
|
||||
await expect(projectModalHeading).toBeHidden({ timeout: 15_000 });
|
||||
await expect(currentProjectBannerName(page, PROJECT_NAME)).toBeVisible({ timeout: 30_000 });
|
||||
@@ -792,6 +849,8 @@ test.describe.serial('document-revision-runtime UI acceptance', () => {
|
||||
await expect(page.getByTestId('doc-rev-template-hint')).toBeVisible({ timeout: 15_000 });
|
||||
await expect(page.getByTestId('doc-rev-template-hint')).toContainText('模板预览');
|
||||
await expect(page.locator('text=版本账本未就绪')).toHaveCount(0);
|
||||
// Squad tasks require an activated workflow with ≥1 human-approval doc (product gate).
|
||||
await activateProjectWorkflow(page);
|
||||
await shot(page, '01-project.png');
|
||||
|
||||
assertRevisionStateCleanForNewProject(logs);
|
||||
@@ -806,8 +865,8 @@ test.describe.serial('document-revision-runtime UI acceptance', () => {
|
||||
recordPass({
|
||||
id: 'UI-01',
|
||||
name: 'create project workbench',
|
||||
input: `login A; create project ${PROJECT_NAME}; assign B`,
|
||||
actual: 'template hint visible; doc-p revision-state count=0; no revision-state 404',
|
||||
input: `login A; create project ${PROJECT_NAME}; assign B+admin; activate workflow`,
|
||||
actual: 'template hint visible; workflow 运行中; doc-p revision-state count=0; no revision-state 404',
|
||||
networkLogs: logs,
|
||||
durationMs: Date.now() - t0,
|
||||
verdict: 'PASS',
|
||||
|
||||
Reference in New Issue
Block a user