import { test, expect } from '@playwright/test'; test.describe('Phase 6: 校本课程包功能测试', () => { 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(); // 等待登录成功 - 跳转到 dashboard 或 courses await page.waitForURL('**/dashboard', { timeout: 10000 }).catch(() => { // 如果没有跳转到 dashboard,可能已经跳转到其他页面,检查是否成功 return page.waitForURL('**/courses', { timeout: 5000 }); }); await page.waitForTimeout(1000); }); test('测试1: 创建校本课程包流程', async ({ page }) => { test.slow(); // 1. 进入课程中心 await page.click('text=课程中心'); await page.waitForURL('**/courses', { timeout: 10000 }); await page.waitForTimeout(1000); // 2. 点击第一个课程卡片(整个卡片可点击) const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first(); const cardCount = await firstCourseCard.count(); if (cardCount > 0) { await firstCourseCard.click(); await page.waitForTimeout(2000); // 3. 检查是否有"创建校本版本"按钮 const createSchoolVersionButton = page.locator('button:has-text("创建校本版本")'); const buttonExists = await createSchoolVersionButton.count(); if (buttonExists > 0) { // 记录当前URL const beforeUrl = page.url(); // 4. 点击"创建校本版本"按钮 await createSchoolVersionButton.click(); // 5. 等待自动创建并跳转到编辑页面(系统自动创建并跳转) await page.waitForURL('**/school-courses/**/edit', { timeout: 15000 }); await page.waitForTimeout(2000); // 6. 验证页面标题显示正确 await expect(page.locator('text=创建校本课程包').or(page.locator('text=编辑校本课程包'))).toBeVisible(); // 7. 验证URL包含school-courses编辑页路径 const currentUrl = page.url(); expect(currentUrl).toMatch(/\/school-courses\/\d+\/edit/); test.info().annotations.push({ type: 'result', description: `创建成功,从 ${beforeUrl} 跳转到 ${currentUrl}`, }); } else { test.info().annotations.push({ type: 'warning', description: '未找到"创建校本版本"按钮', }); } } else { test.info().annotations.push({ type: 'warning', description: '未找到课程卡片', }); } }); test('测试2: 个人课程中心列表', async ({ page }) => { // 1. 进入校本课程包页面 await page.click('text=校本课程包'); await page.waitForURL('**/school-courses', { timeout: 10000 }); await page.waitForTimeout(2000); // 2. 验证页面标题 await expect(page.locator('text=我的校本课程包').or(page.locator('text=校本课程包')).first()).toBeVisible({ timeout: 5000 }); // 3. 检查保存位置筛选器 const filterTabs = page.locator('text=全部').or(page.locator('text=个人')).or(page.locator('text=校本')); const filterCount = await filterTabs.count(); test.info().annotations.push({ type: 'info', description: `筛选器数量: ${filterCount}`, }); // 4. 检查课程列表 const courseCards = page.locator('.ant-card, [class*="course"], [class*="Course"]'); const courseCount = await courseCards.count(); test.info().annotations.push({ type: 'info', description: `课程数量: ${courseCount}`, }); // 截图 await page.screenshot({ path: 'test-results/school-course-list.png' }); }); test('测试3: 编辑校本课程包', async ({ page }) => { test.slow(); // 1. 进入校本课程包页面 await page.click('text=校本课程包'); await page.waitForURL('**/school-courses', { timeout: 10000 }); await page.waitForTimeout(2000); // 2. 查找编辑按钮 const editButton = page.locator('button:has-text("编辑")').first(); if (await editButton.count() > 0) { await editButton.click(); await page.waitForTimeout(2000); // 3. 验证进入编辑页面 const url = page.url(); expect(url).toContain('/edit'); // 4. 检查步骤导航 const steps = page.locator('.ant-steps-item, [class*="step"]'); const stepCount = await steps.count(); test.info().annotations.push({ type: 'info', description: `编辑步骤数量: ${stepCount}`, }); // 5. 尝试切换步骤 const step2 = page.locator('text=课程介绍').or(page.locator('text=步骤2')); if (await step2.count() > 0) { await step2.first().click(); await page.waitForTimeout(1000); } // 6. 保存修改 const saveButton = page.locator('button:has-text("保存")').or(page.locator('button:has-text("保存到个人")')); if (await saveButton.count() > 0) { await saveButton.first().click(); await page.waitForTimeout(2000); } // 截图 await page.screenshot({ path: 'test-results/school-course-edit.png' }); } else { test.info().annotations.push({ type: 'warning', description: '未找到可编辑的课程', }); } }); test('测试4: 查看校本课程详情', async ({ page }) => { // 1. 进入校本课程包页面 await page.click('text=校本课程包'); await page.waitForURL('**/school-courses', { timeout: 10000 }); await page.waitForTimeout(2000); // 2. 查找查看按钮 const viewButton = page.locator('button:has-text("查看")').first(); if (await viewButton.count() > 0) { await viewButton.click(); await page.waitForTimeout(2000); // 3. 验证详情页面 const url = page.url(); expect(url).toContain('/school-courses/'); // 4. 检查详情页内容 const detailElements = page.locator('text=开始备课').or(page.locator('text=课程介绍')); await expect(detailElements.first()).toBeVisible({ timeout: 5000 }); // 截图 await page.screenshot({ path: 'test-results/school-course-detail.png' }); } else { test.info().annotations.push({ type: 'warning', description: '未找到可查看的课程', }); } }); test('测试5: 备课模式', async ({ page }) => { test.slow(); // 1. 进入校本课程包页面 await page.click('text=校本课程包'); await page.waitForURL('**/school-courses', { timeout: 10000 }); await page.waitForTimeout(2000); // 2. 查找"开始备课"按钮 const prepareButton = page.locator('button:has-text("开始备课")').first(); if (await prepareButton.count() > 0) { await prepareButton.click(); await page.waitForTimeout(3000); // 3. 验证进入备课模式 const url = page.url(); expect(url).toContain('/prepare'); // 4. 检查备课模式布局 const navigation = page.locator('aside, [class*="navigation"], [class*="sidebar"]'); await expect(navigation.first()).toBeVisible({ timeout: 5000 }); // 5. 检查课程列表 const lessonItems = page.locator('[class*="lesson"], [class*="course"]'); const lessonCount = await lessonItems.count(); test.info().annotations.push({ type: 'info', description: `备课模式课程数量: ${lessonCount}`, }); // 截图 await page.screenshot({ path: 'test-results/prepare-mode.png' }); } else { test.info().annotations.push({ type: 'warning', description: '未找到"开始备课"按钮', }); } }); test('测试6: 删除校本课程包', async ({ page }) => { // 1. 进入校本课程包页面 await page.click('text=校本课程包'); await page.waitForURL('**/school-courses', { timeout: 10000 }); await page.waitForTimeout(2000); // 2. 记录删除前的课程数量 const courseCards = page.locator('.ant-card, [class*="course"]'); const beforeCount = await courseCards.count(); // 3. 查找删除按钮 const deleteButton = page.locator('button:has-text("删除")').first(); if (await deleteButton.count() > 0) { // 4. 点击删除 await deleteButton.click(); await page.waitForTimeout(1000); // 5. 确认删除 const confirmButton = page.locator('button:has-text("确定")').or(page.locator('button:has-text("确认")')); if (await confirmButton.count() > 0) { await confirmButton.first().click(); await page.waitForTimeout(2000); } // 6. 验证删除成功 const afterCount = await courseCards.count(); test.info().annotations.push({ type: 'info', description: `删除前: ${beforeCount}, 删除后: ${afterCount}`, }); } else { test.info().annotations.push({ type: 'warning', description: '未找到删除按钮', }); } }); test('测试7: 筛选功能', async ({ page }) => { // 1. 进入校本课程包页面 await page.click('text=校本课程包'); await page.waitForURL('**/school-courses', { timeout: 10000 }); await page.waitForTimeout(2000); // 2. 查找筛选器 const personalFilter = page.locator('text=个人').or(page.locator('[role="tab"]:has-text("个人")')); const schoolFilter = page.locator('text=校本').or(page.locator('[role="tab"]:has-text("校本")')); if (await personalFilter.count() > 0) { // 3. 点击"个人"筛选 await personalFilter.first().click(); await page.waitForTimeout(1000); // 4. 点击"校本"筛选 if (await schoolFilter.count() > 0) { await schoolFilter.first().click(); await page.waitForTimeout(1000); } test.info().annotations.push({ type: 'success', description: '筛选功能测试完成', }); } else { test.info().annotations.push({ type: 'warning', description: '未找到筛选器', }); } // 截图 await page.screenshot({ path: 'test-results/school-course-filter.png' }); }); });