import { test, expect } from '@playwright/test'; test.describe('展播模式', () => { let baseURL = 'http://localhost:5173'; test.beforeEach(async ({ page }) => { await page.goto(baseURL); await page.waitForLoadState('networkidle'); await page.click('text=教师'); await page.waitForTimeout(500); const accountInput = page.locator('input[placeholder*="账号"]').or(page.locator('input[name="account"]')); await accountInput.fill('teacher1'); const passwordInput = page.locator('input[placeholder*="密码"]').or(page.locator('input[type="password"]')); await passwordInput.fill('123456'); const loginButton = page.locator('button[type="submit"]').or(page.locator('.login-btn')).or(page.locator('button:has-text("登录")')); await loginButton.click(); await page.waitForURL('**/dashboard', { timeout: 10000 }).catch(() => { return page.waitForURL('**/courses', { timeout: 5000 }); }); await page.waitForTimeout(1000); }); test('测试1: 从上课页面进入展播模式', async ({ page }) => { test.slow(); // 1. 进入上课模式 await page.click('text=上课记录'); await page.waitForTimeout(2000); const recordItems = page.locator('[class*="record"], [class*="lesson"]'); if (await recordItems.count() > 0) { await recordItems.first().click(); await page.waitForTimeout(2000); } else { await page.click('text=课程中心'); await page.waitForTimeout(1000); const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first(); await firstCourseCard.click(); await page.waitForTimeout(2000); const selectLessonsButton = page.locator('button:has-text("选择课程上课")'); if (await selectLessonsButton.count() > 0) { await selectLessonsButton.click(); await page.waitForTimeout(2000); const confirmButton = page.locator('button:has-text("确定")'); if (await confirmButton.count() > 0) { await confirmButton.click(); await page.waitForTimeout(3000); } } } await page.waitForTimeout(2000); // 2. 查找展播模式按钮 const broadcastButton = page.locator('button:has-text("展播")').or(page.locator('button:has-text("全屏")')); const buttonCount = await broadcastButton.count(); if (buttonCount > 0) { // 3. 点击展播模式(新标签页) const [newPage] = await Promise.all([ page.context().waitForEvent('page'), broadcastButton.first().click() ]); await newPage.waitForLoadState('networkidle'); await newPage.waitForTimeout(2000); // 4. 验证新标签页URL const broadcastUrl = newPage.url(); test.info().annotations.push({ type: 'success', description: `展播模式已打开: ${broadcastUrl}`, }); // 5. 验证展播模式全屏状态 const isFullscreen = await newPage.locator('[class*="fullscreen"], [class*="broadcast"]').count() > 0; test.info().annotations.push({ type: 'info', description: isFullscreen ? '进入全屏展播模式' : '展播页面已打开', }); await newPage.screenshot({ path: 'test-results/broadcast-open.png', fullPage: true }); await newPage.close(); } else { test.info().annotations.push({ type: 'warning', description: '未找到展播模式按钮', }); } }); test('测试2: 展播模式布局验证', async ({ page }) => { test.slow(); // 1. 直接访问展播模式URL(如果有上课记录ID) await page.goto('http://localhost:5173/teacher/lessons'); await page.waitForTimeout(2000); // 2. 查找展播入口 const broadcastButton = page.locator('button:has-text("展播")'); if (await broadcastButton.count() > 0) { const [newPage] = await Promise.all([ page.context().waitForEvent('page'), broadcastButton.click() ]); await newPage.waitForLoadState('networkidle'); await newPage.waitForTimeout(2000); // 3. 验证展播页面结构 const mainContainer = newPage.locator('main, [class*="container"], [class*="broadcast"]'); expect(await mainContainer.count()).toBeGreaterThan(0); // 4. 验证内容显示区 const contentArea = newPage.locator('[class*="content"], [class*="display"]'); expect(await contentArea.count()).toBeGreaterThan(0); // 5. 验证控制按钮区域 const controls = newPage.locator('[class*="control"], [class*="button"]'); const controlCount = await controls.count(); test.info().annotations.push({ type: 'info', description: `控制按钮数量: ${controlCount}`, }); await newPage.screenshot({ path: 'test-results/broadcast-layout.png', fullPage: true }); await newPage.close(); } else { test.skip('无法找到展播入口'); } }); test('测试3: 展播模式Kids Mode展示', async ({ page }) => { test.slow(); // 进入展播模式 await page.goto('http://localhost:5173/teacher/lessons'); await page.waitForTimeout(2000); const broadcastButton = page.locator('button:has-text("展播")'); if (await broadcastButton.count() > 0) { const [newPage] = await Promise.all([ page.context().waitForEvent('page'), broadcastButton.click() ]); await newPage.waitForLoadState('networkidle'); await newPage.waitForTimeout(2000); // 1. 验证Kids Mode组件显示 const kidsMode = newPage.locator('[class*="kids"], [class*="child"], [class*="display"]'); const hasKidsMode = await kidsMode.count() > 0; test.info().annotations.push({ type: 'info', description: hasKidsMode ? 'Kids Mode组件已显示' : '未找到Kids Mode', }); // 2. 验证内容元素 if (hasKidsMode) { const images = kidsMode.first().locator('img'); const imageCount = await images.count(); const textContent = await kidsMode.first().allTextContents(); const textCount = textContent.filter(t => t.trim()).length; test.info().annotations.push({ type: 'info', description: `图片数量: ${imageCount}, 文本段落数: ${textCount}`, }); } await newPage.screenshot({ path: 'test-results/broadcast-kids-mode.png', fullPage: true }); await newPage.close(); } else { test.skip('无法找到展播入口'); } }); test('测试4: 展播模式全屏功能', async ({ page }) => { test.slow(); // 进入展播模式 await page.goto('http://localhost:5173/teacher/lessons'); await page.waitForTimeout(2000); const broadcastButton = page.locator('button:has-text("展播")'); if (await broadcastButton.count() > 0) { const [newPage] = await Promise.all([ page.context().waitForEvent('page'), broadcastButton.click() ]); await newPage.waitForLoadState('networkidle'); await newPage.waitForTimeout(2000); // 1. 检查是否自动全屏 const isFullscreen = await newPage.evaluate(() => { return document.fullscreenElement != null || document.webkitFullscreenElement != null || document.mozFullScreenElement != null; }); test.info().annotations.push({ type: 'info', description: isFullscreen ? '已自动进入全屏模式' : '未自动全屏', }); // 2. 手动触发全屏(如果未自动全屏) if (!isFullscreen) { const fullscreenButton = newPage.locator('button:has-text("全屏")').or(page.locator('[class*="fullscreen"]')); if (await fullscreenButton.count() > 0) { await fullscreenButton.first().click(); await newPage.waitForTimeout(1000); } } await newPage.screenshot({ path: 'test-results/broadcast-fullscreen.png', fullPage: true }); await newPage.close(); } else { test.skip('无法找到展播入口'); } }); test('测试5: 展播模式环节切换', async ({ page }) => { test.slow(); // 进入展播模式 await page.goto('http://localhost:5173/teacher/lessons'); await page.waitForTimeout(2000); const broadcastButton = page.locator('button:has-text("展播")'); if (await broadcastButton.count() > 0) { const [newPage] = await Promise.all([ page.context().waitForEvent('page'), broadcastButton.click() ]); await newPage.waitForLoadState('networkidle'); await newPage.waitForTimeout(2000); // 1. 查找环节导航 const stepNav = newPage.locator('[class*="step"], [class*="nav"], .ant-steps'); const stepCount = await stepNav.count(); // 2. 尝试下一个环节 const nextButton = newPage.locator('button:has-text("下一")').or(page.locator('button:has-text("下一步")')); const nextCount = await nextButton.count(); if (nextCount > 0) { await nextButton.first().click(); await newPage.waitForTimeout(1500); test.info().annotations.push({ type: 'success', description: '切换到下一个环节', }); } // 3. 尝试上一个环节 const prevButton = newPage.locator('button:has-text("上一")').or(page.locator('button:has-text("上一步")')); const prevCount = await prevButton.count(); if (prevCount > 0) { await prevButton.first().click(); await newPage.waitForTimeout(1500); } test.info().annotations.push({ type: 'info', description: `导航区域: ${stepCount}, 下一按钮: ${nextCount}, 上一按钮: ${prevCount}`, }); await newPage.screenshot({ path: 'test-results/broadcast-switch-step.png' }); await newPage.close(); } else { test.skip('无法找到展播入口'); } }); test('测试6: 展播模式键盘控制', async ({ page }) => { test.slow(); // 进入展播模式 await page.goto('http://localhost:5173/teacher/lessons'); await page.waitForTimeout(2000); const broadcastButton = page.locator('button:has-text("展播")'); if (await broadcastButton.count() > 0) { const [newPage] = await Promise.all([ page.context().waitForEvent('page'), broadcastButton.click() ]); await newPage.waitForLoadState('networkidle'); await newPage.waitForTimeout(2000); // 1. 测试空格键 await newPage.keyboard.press('Space'); await newPage.waitForTimeout(1000); // 2. 测试左右箭头 await newPage.keyboard.press('ArrowRight'); await newPage.waitForTimeout(1000); await newPage.keyboard.press('ArrowLeft'); await newPage.waitForTimeout(1000); // 3. 测试ESC退出 await newPage.keyboard.press('Escape'); await newPage.waitForTimeout(1000); test.info().annotations.push({ type: 'success', description: '键盘控制测试完成', }); await newPage.screenshot({ path: 'test-results/broadcast-keyboard.png' }); await newPage.close(); } else { test.skip('无法找到展播入口'); } }); test('测试7: 展播模式资源展示', async ({ page }) => { test.slow(); // 进入展播模式 await page.goto('http://localhost:5173/teacher/lessons'); await page.waitForTimeout(2000); const broadcastButton = page.locator('button:has-text("展播")'); if (await broadcastButton.count() > 0) { const [newPage] = await Promise.all([ page.context().waitForEvent('page'), broadcastButton.click() ]); await newPage.waitForLoadState('networkidle'); await newPage.waitForTimeout(2000); // 1. 查找图片资源 const images = newPage.locator('img'); const imageCount = await images.count(); // 2. 查找视频资源 const videos = newPage.locator('video'); const videoCount = await videos.count(); // 3. 查找文字内容 const textElements = await newPage.locator('body').allTextContents(); const textLength = textElements.join('').length; test.info().annotations.push({ type: 'info', description: `图片: ${imageCount}, 视频: ${videoCount}, 文字长度: ${textLength}`, }); await newPage.screenshot({ path: 'test-results/broadcast-resources.png', fullPage: true }); await newPage.close(); } else { test.skip('无法找到展播入口'); } }); test('测试8: 展播模式颜色主题', async ({ page }) => { test.slow(); // 进入展播模式 await page.goto('http://localhost:5173/teacher/lessons'); await page.waitForTimeout(2000); const broadcastButton = page.locator('button:has-text("展播")'); if (await broadcastButton.count() > 0) { const [newPage] = await Promise.all([ page.context().waitForEvent('page'), broadcastButton.click() ]); await newPage.waitForLoadState('networkidle'); await newPage.waitForTimeout(2000); // 1. 检查背景色(深色主题适合投影) const backgroundColor = await newPage.evaluate(() => { return window.getComputedStyle(document.body).backgroundColor; }); // 2. 检查文字颜色(高对比度) const textColor = await newPage.evaluate(() => { const mainElement = document.querySelector('main, [class*="content"]'); return mainElement ? window.getComputedStyle(mainElement).color : 'rgb(0, 0, 0)'; }); test.info().annotations.push({ type: 'info', description: `背景色: ${backgroundColor}, 文字色: ${textColor}`, }); await newPage.screenshot({ path: 'test-results/broadcast-theme.png', fullPage: true }); await newPage.close(); } else { test.skip('无法找到展播入口'); } }); test('测试9: 展播模式关闭和返回', async ({ page }) => { test.slow(); // 进入展播模式 await page.goto('http://localhost:5173/teacher/lessons'); await page.waitForTimeout(2000); const broadcastButton = page.locator('button:has-text("展播")'); if (await broadcastButton.count() > 0) { const [newPage] = await Promise.all([ page.context().waitForEvent('page'), broadcastButton.click() ]); await newPage.waitForLoadState('networkidle'); await newPage.waitForTimeout(2000); // 1. 查找关闭按钮 const closeButton = newPage.locator('button:has-text("关闭")').or(page.locator('.ant-modal-close')); const closeCount = await closeButton.count(); // 2. 查找返回按钮 const backButton = newPage.locator('button:has-text("返回")').or(page.locator('[class*="back"]')); const backCount = await backButton.count(); test.info().annotations.push({ type: 'info', description: `关闭按钮: ${closeCount}, 返回按钮: ${backCount}`, }); // 3. 测试ESC关闭 await newPage.keyboard.press('Escape'); await newPage.waitForTimeout(1000); // 4. 检查页面是否还在 const isStillOpen = await newPage.evaluate(() => document.readyState !== 'unloaded'); test.info().annotations.push({ type: 'info', description: isStillOpen ? '页面仍然打开' : '页面已关闭', }); if (isStillOpen) { await newPage.close(); } } else { test.skip('无法找到展播入口'); } }); test('测试10: 展播模式URL参数支持', async ({ page }) => { test.slow(); // 1. 测试带step参数的URL const testUrls = [ 'http://localhost:5173/teacher/broadcast/1', 'http://localhost:5173/teacher/lessons/1/broadcast', ]; for (const testUrl of testUrls) { try { await page.goto(testUrl); await page.waitForTimeout(2000); // 2. 检查页面是否正常加载 const content = page.locator('main, [class*="content"]'); const hasContent = await content.count() > 0; test.info().annotations.push({ type: 'info', description: `${testUrl}: ${hasContent ? '加载成功' : '加载失败'}`, }); if (hasContent) { await page.screenshot({ path: `test-results/broadcast-url-${testUrls.indexOf(testUrl)}.png` }); } } catch (e) { test.info().annotations.push({ type: 'warning', description: `${testUrl}: 访问失败`, }); } } }); });