import { test, expect, type Page } from '@playwright/test'; /** * SWBOOT L6 UI 二次验收(W5 关闭条件):软件向导在真实 dev 栈上的完整冒烟。 * 与其他 e2e 一致:仅 RUN_UI_ACCEPTANCE=1 时运行(无 mock),需要 * ACCEPTANCE_USERNAME / ACCEPTANCE_PASSWORD(具备 project:create 的账号)。 * 断言:纯软件域切换、solo 未评审横幅、catalog 类型、必填三要素、 * 创建成功进入项目、页面无医疗污染默认词(设计 §11.4)。 */ const runAcceptance = process.env.RUN_UI_ACCEPTANCE === '1'; const USER = process.env.ACCEPTANCE_USERNAME?.trim() || ''; const PASS = process.env.ACCEPTANCE_PASSWORD?.trim() || ''; test.skip(!runAcceptance, 'set RUN_UI_ACCEPTANCE=1 against the real dev stack'); async function login(page: Page, username: string, password: string) { await page.goto('/'); await page.fill('input[placeholder*="系统用户名"]', username); await page.fill('input[placeholder*="登录密码"]', password); await page.click('button:has-text("进入医疗协同工作台")'); await expect(page.getByText('新建立项会话')).toBeVisible({ timeout: 30_000 }); } test('swboot wizard: software domain, solo banner, catalog type, create project', async ({ page }) => { if (!USER || !PASS) { throw new Error('ACCEPTANCE_USERNAME / ACCEPTANCE_PASSWORD are required'); } await login(page, USER, PASS); await page.click('button:has-text("新建立项会话")'); await expect(page.getByText('发起医疗器械新项目立项')).toBeVisible({ timeout: 10_000 }); await page.click('[data-testid="create-domain-software"]'); await expect(page.getByText('发起软件项目')).toBeVisible(); // 切到 solo:未独立评审横幅(W5a 契约) const teamSelect = page.locator('select', { has: page.locator('option[value="solo"]') }); await teamSelect.selectOption('solo'); await expect(page.locator('[data-testid="solo-unreviewed-banner"]')).toBeVisible(); // 服务端 catalog 项目类型可选 const typeSelect = page.locator('[data-testid="software-project-type"]'); await expect(typeSelect).toBeVisible(); const options = await typeSelect.locator('option').allTextContents(); expect(options.join('|')).toContain('绿地立项'); // 必填软件三要素 + 项目名称 const suffix = Date.now().toString().slice(-6); await page.fill('input[placeholder="例如:无线便携式双频超声骨动力微创手术系统"]', `swboot-ui-${suffix}`); await page.fill('input[placeholder="问题陈述"]', '手工回归成本高,需要自举工具链'); await page.fill('input[placeholder="目标用户"]', '平台工程团队'); await page.fill('input[placeholder="目标结果"]', '一条命令完成环境自举'); await page.click('button:has-text("确认立项并创建会话")'); await expect(page.getByText(`swboot-ui-${suffix}`).first()).toBeVisible({ timeout: 30_000 }); // 软件项目页面不出现医疗污染默认词(抽查) const body = await page.locator('body').innerText(); for (const banned of ['注册检验', 'GB 9706', '器械分类']) { expect(body, `software page must not default to medical term ${banned}`).not.toContain(banned); } });