| @@ -17,10 +17,11 @@ test.describe('教学实施真实环境只读联调', () => { | |||
| }) | |||
| test('六个教学入口读取真实 UAT 保留数据并生成验收截图', async ({ page }, testInfo) => { | |||
| const visitTaskCenter = async (path: string, heading: string, uatCode: string, screenshotName: string) => { | |||
| const visitTaskCenter = async (path: string, uatCode: string, screenshotName: string) => { | |||
| await page.goto(path) | |||
| await expect(page).toHaveURL(new RegExp(`${path.replaceAll('/', '\\/')}$`)) | |||
| await expect(page.getByRole('heading', { name: heading, exact: true })).toBeVisible() | |||
| await expect(page.getByTestId('teaching-task-center')).toBeVisible() | |||
| await expect(page.locator('.ttc-hero')).toHaveCount(0) | |||
| await expect(page.locator('.ttc-assignment-card').first()).toBeVisible() | |||
| await expect(page.getByText(uatCode, { exact: false }).first()).toBeVisible() | |||
| await expect.poll(async () => page.locator('.ttc-assignment-card img').first().evaluate((image: HTMLImageElement) => image.complete && image.naturalWidth > 0)).toBe(true) | |||
| @@ -28,12 +29,12 @@ test.describe('教学实施真实环境只读联调', () => { | |||
| await captureScreenshot(page, testInfo, screenshotName) | |||
| } | |||
| await visitTaskCenter('/teaching/virtual-training', '虚拟仿真任务管理', 'UAT-TEACH-VIRTUAL-001', '真实环境-01-虚拟仿真') | |||
| await visitTaskCenter('/teaching/physical-training', '实装实训任务管理', 'UAT-TEACH-PHYSICAL-001', '真实环境-02-实装实训') | |||
| await visitTaskCenter('/teaching/confrontation', '对抗训练任务管理', 'UAT-TEACH-CONFRONTATION-001', '真实环境-03-对抗训练') | |||
| await visitTaskCenter('/teaching/virtual-training', 'UAT-TEACH-VIRTUAL-001', '真实环境-01-虚拟仿真') | |||
| await visitTaskCenter('/teaching/physical-training', 'UAT-TEACH-PHYSICAL-001', '真实环境-02-实装实训') | |||
| await visitTaskCenter('/teaching/confrontation', 'UAT-TEACH-CONFRONTATION-001', '真实环境-03-对抗训练') | |||
| await page.goto('/teaching/immersive') | |||
| await expect(page.getByRole('heading', { name: '沉浸交互与外设联调', exact: true })).toBeVisible() | |||
| await expect(page.locator('.teaching-v2-hero')).toHaveCount(0) | |||
| await expect(page.getByTestId('immersive-device-panel')).toBeVisible() | |||
| await expect(page.getByTestId('immersive-viewer-panel')).toBeVisible() | |||
| await expect(page.locator('.immersive-viewer canvas')).toBeVisible({ timeout: 30_000 }) | |||
| @@ -45,10 +46,11 @@ test.describe('教学实施真实环境只读联调', () => { | |||
| await expect(page.locator('iframe')).toHaveCount(0) | |||
| await captureScreenshot(page, testInfo, '真实环境-04-沉浸交互') | |||
| await visitTaskCenter('/teaching/exams', '考试测评', 'UAT-EXAM-VIRTUAL-001', '真实环境-05-考试测评') | |||
| await visitTaskCenter('/teaching/exams', 'UAT-EXAM-VIRTUAL-001', '真实环境-05-考试测评') | |||
| await page.goto('/teaching/data-center') | |||
| await expect(page.getByRole('heading', { name: '教学数据中心', exact: true })).toBeVisible() | |||
| await expect(page.locator('.teaching-v2-hero')).toHaveCount(0) | |||
| await expect(page.getByTestId('analytics-workspace')).toBeVisible() | |||
| await expect(page.getByTestId('teaching-dashboard-metrics')).toBeVisible() | |||
| await expect(page.getByTestId('analytics-channel-summary')).toBeVisible() | |||
| await expect(page.getByTestId('analytics-learner-table')).toBeVisible() | |||
| @@ -29,18 +29,32 @@ test.describe('教学实施模块状态化 UI 契约', () => { | |||
| await contract.install(page) | |||
| const entries = [ | |||
| ['/teaching/virtual-training', '虚拟仿真任务管理'], | |||
| ['/teaching/physical-training', '实装实训任务管理'], | |||
| ['/teaching/confrontation', '对抗训练任务管理'], | |||
| ['/teaching/immersive', '沉浸交互与外设联调'], | |||
| ['/teaching/exams', '考试测评'], | |||
| ['/teaching/data-center', '教学数据中心'], | |||
| ['/teaching/virtual-training', 'teaching-task-center'], | |||
| ['/teaching/physical-training', 'teaching-task-center'], | |||
| ['/teaching/confrontation', 'teaching-task-center'], | |||
| ['/teaching/immersive', 'immersive-viewer-panel'], | |||
| ['/teaching/exams', 'teaching-task-center'], | |||
| ['/teaching/data-center', 'analytics-workspace'], | |||
| ] as const | |||
| for (const [path, heading] of entries) { | |||
| for (const [path, workspaceTestId] of entries) { | |||
| await page.goto(path) | |||
| await expect(page.getByRole('heading', { name: heading, exact: true })).toBeVisible() | |||
| await expect(page.getByTestId('teaching-dashboard-hero').or(page.locator('.ttc-hero'))).toBeVisible() | |||
| await expect(page.getByTestId(workspaceTestId)).toBeVisible() | |||
| await expect(page.locator('.ttc-hero, .teaching-v2-hero, .guide-standalone-hero')).toHaveCount(0) | |||
| if (workspaceTestId === 'teaching-task-center') { | |||
| const toolbar = page.locator('.ttc-task-workspace > .ttc-filter-row') | |||
| const keyword = toolbar.locator('.ttc-keyword') | |||
| const createButton = toolbar.getByRole('button', { name: /新建/ }) | |||
| await expect(toolbar.locator('.el-select').first()).toBeVisible() | |||
| await expect(page.locator('.ttc-status-bar, .ttc-metrics')).toHaveCount(0) | |||
| await expect(page.locator('.ttc-task-workspace > .ttc-inline-summary')).toBeVisible() | |||
| await expect(createButton).toBeVisible() | |||
| const [toolbarBox, keywordBox, createBox] = await Promise.all([toolbar.boundingBox(), keyword.boundingBox(), createButton.boundingBox()]) | |||
| for (const box of [toolbarBox, keywordBox, createBox]) expect(box).not.toBeNull() | |||
| expect(keywordBox!.width).toBeGreaterThan(230) | |||
| expect(keywordBox!.width).toBeLessThanOrEqual(270) | |||
| expect(createBox!.x + createBox!.width).toBeGreaterThan(toolbarBox!.x + toolbarBox!.width - 40) | |||
| } | |||
| await expect(page.locator('iframe')).toHaveCount(0) | |||
| } | |||
| @@ -589,7 +603,8 @@ test.describe('教学实施模块状态化 UI 契约', () => { | |||
| page.on('request', (request) => { if (new URL(request.url()).pathname === '/models/excavator-a.glb') modelRequests += 1 }) | |||
| await page.goto('/teaching/immersive') | |||
| await expect(page.getByRole('heading', { name: '沉浸交互与外设联调', exact: true })).toBeVisible() | |||
| await expect(page.getByTestId('immersive-viewer-panel')).toBeVisible() | |||
| await expect(page.locator('.teaching-v2-hero')).toHaveCount(0) | |||
| await expect.poll(() => contract.count('GET', '/runs/run-immersive/assets')).toBeGreaterThan(0) | |||
| await expect(page.locator('.immersive-scene-status')).toContainText('已加载“虚拟维修训练”发布场景', { timeout: 30_000 }) | |||
| await expect.poll(() => modelRequests).toBeGreaterThan(0) | |||