kindergarten_java/lesingle-edu-reading-platform-frontend/tests/e2e/admin/package-create-from-template.spec.ts
En 40589f59e7 chore: 重命名项目目录
前后端目录重命名:
- reading-platform-java/ → lesingle-edu-reading-platform-backend/
- reading-platform-frontend/ → lesingle-edu-reading-platform-frontend/

更新相关文件:
- 所有 shell 脚本中的目录引用
- pom.xml 和 application.yml 中的项目名称
- package.json 中的项目名称
- .claude/CLAUDE.md 中的路径引用
- README 文档中的路径引用
2026-03-26 11:31:47 +08:00

553 lines
26 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 课程包创建 E2E 测试 - 基于"折耳兔奇奇测试课程 01"模板
*
* 测试流程:
* 1. 超管登录
* 2. 进入课程管理页面
* 3. 新建课程包
* 4. 完成 7 个步骤(基本信息、课程介绍、排课参考、导入课、集体课、领域课、环创建设)
* 5. 验证创建成功
*
* 数据来源:基于提供的 JSON 模板数据简化
*/
import { test, expect } from '@playwright/test';
import { loginAsAdmin, waitForTable, waitForSuccess } from './helpers';
// 测试数据 - 基于 JSON 模板
const TEST_COURSE = {
// 基本信息
name: '折耳兔奇奇测试课程 01',
theme: '社会认知', // 使用实际存在的主题
grades: ['小班'] as string[],
domainTags: ['社会适应'] as string[],
pictureBookName: '折耳兔奇奇',
coreContent: '通过折耳兔奇奇的故事,帮助孩子理解友谊和分享的重要性',
duration: 25,
// 课程介绍
introSummary: '本课程以绘本《折耳兔奇奇》为核心载体,面向幼儿园小班幼儿,紧扣"接受认同自己"的核心主题,帮助幼儿建立自信、乐观的心态。',
introHighlights: '1. 主题鲜明,情感真挚\n2. 领域融合,全面发展\n3. 形式多样,趣味十足\n4. 家园协同,全程联动\n5. 环创赋能,延伸教育',
introGoals: '1. 认知目标:理解《折耳兔奇奇》绘本核心情节\n2. 能力目标:提升幼儿语言表达、社会交往能力\n3. 情感目标:感受奇奇从自卑到自信的情绪变化',
introSchedule: '周一:导入课认识奇奇;周二:语言领域绘本解读;周三:社会领域夸夸我和你;周四:健康领域保护耳朵;周五:科学领域兔子的小秘密',
introKeyPoints: '1. 掌握绘本核心内容\n2. 落实五大领域目标\n3. 推动家校协同',
introMethods: '1. 绘本阅读法\n2. 课件演示法\n3. 互动游戏法\n4. 情境教学法',
introEvaluation: '1. 过程性评价\n2. 作品评价\n3. 家园评价\n4. 总结性评价',
introNotes: '1. 尊重幼儿个体差异\n2. 严格控制各环节课时时长\n3. 注重安全保障',
// 排课参考
totalLessons: 5,
lessonDuration: 25,
scheduleAdvice: '建议每周 1-2 课时,按导入课→集体课→五大领域主题课顺序推进',
// 导入课
introLessonName: '导入课——认识奇奇,发现我的特别之处',
introLessonDuration: 10,
introLessonObjectives: '1. 认知目标:认识绘本主角折耳兔奇奇,能准确说出奇奇最明显的外形特点(折耳朵)\n2. 能力目标:能大胆、主动地说出自己的一个特别之处\n3. 情感目标:乐于参与集体互动,愿意分享自己的特点',
introLessonPreparation: '1. 物质准备:折耳兔奇奇毛绒玩具 1 个、绘本封面放大图 1 张、轻音乐\n2. 经验准备:幼儿有观察自己和同伴外貌、爱好的经验',
// 集体课
collectiveLessonName: '集体课——折耳兔奇奇绘本阅读',
collectiveLessonDuration: 25,
collectiveLessonObjectives: '1. 认知:完整观看绘本动画,熟悉绘本主要情节和角色\n2. 能力:能跟随教师朗读简单的绘本对话\n3. 情感:感受绘本的趣味性,初步体会奇奇的烦恼',
// 领域课 - 健康领域
healthLessonName: '健康领域——保护我的"小耳朵"',
healthLessonDuration: 25,
healthLessonObjectives: '1. 认知:知道耳朵是我们的重要器官,了解耳朵的作用\n2. 能力:学习保护耳朵的正确方法\n3. 情感:愿意主动保护自己的身体器官',
// 领域课 - 科学领域
scienceLessonName: '科学领域——兔子的小秘密',
scienceLessonDuration: 25,
scienceLessonObjectives: '1. 认知:了解兔子的基本特征和生活习性\n2. 能力:能通过观察、对比发现不同兔子的外形区别\n3. 情感:对兔子产生探究兴趣,爱护小动物',
// 环创建设
environmentConstruction: '1. 夸夸卡展示区:展示幼儿制作的夸夸卡\n2. "我的特别之处"展示墙:张贴幼儿分享的特别之处作品\n3. 兔子探秘墙:张贴兔子图片和观察记录\n4. 音乐角环创:张贴儿歌歌词图谱、兔子头饰\n5. 健康小卫士展示区:张贴保护耳朵方法海报',
};
test.describe('课程包创建 - 折耳兔奇奇测试课程 01', () => {
test('完整流程:创建课程包并验证', async ({ page }) => {
test.setTimeout(300000); // 5 分钟超时
// 监听浏览器控制台日志
page.on('console', msg => {
console.log(`[浏览器日志] ${msg.type()}: ${msg.text()}`);
});
// 监听页面错误
page.on('pageerror', error => {
console.error(`[页面错误] ${error.message}`);
});
// ==================== 步骤 1: 登录 ====================
console.log('\n========== 开始登录 ==========');
await loginAsAdmin(page);
await page.waitForURL('**/admin/**', { timeout: 15000 }).catch(() => {
console.log('警告URL 等待超时,但继续执行');
});
await page.waitForTimeout(2000); // 增加等待时间确保页面完全加载
console.log('✅ 登录成功');
// ==================== 步骤 2: 进入课程管理页面 ====================
console.log('\n========== 进入课程管理页面 ==========');
// 直接导航到课程列表页
await page.goto('/admin/courses', { timeout: 30000, waitUntil: 'networkidle' });
await page.waitForTimeout(3000); // 等待数据加载
// 验证页面元素(不强制要求表格存在)
const pageContainer = page.locator('.package-list-page, .course-list-page, [class*="course"], [class*="package"]').first();
if (await pageContainer.isVisible({ timeout: 5000 })) {
console.log('✅ 课程管理页面加载完成');
} else {
console.log('⚠️ 未找到预期的页面容器,但继续执行');
}
// ==================== 步骤 3: 点击新建课程包按钮 ====================
console.log('\n========== 点击新建课程包 ==========');
// 使用更精确的选择器 - 按钮可能是一个 a 标签或带有 click 事件的元素
const createButton = page.locator('button:has-text("新建课程包"), .ant-btn:has-text("新建课程包"), a:has-text("新建课程包")').first();
await createButton.click();
await page.waitForTimeout(1000);
console.log('✅ 点击新建课程包');
// 验证进入创建页面
await expect(page.getByText('创建课程包')).toBeVisible({ timeout: 5000 });
await expect(page.getByText('基本信息')).toBeVisible();
console.log('✅ 进入课程创建页面');
// ==================== 步骤 1: 基本信息 ====================
console.log('\n========== 步骤 1: 基本信息 ==========');
// 填写课程包名称
const nameInput = page.getByPlaceholder('请输入课程包名称');
await expect(nameInput).toBeVisible({ timeout: 3000 });
await nameInput.fill(TEST_COURSE.name);
console.log(` - 填写课程名称:${TEST_COURSE.name}`);
// 选择关联主题
await page.locator('.ant-select-selector').first().click();
await page.waitForTimeout(500);
await page.getByText(TEST_COURSE.theme, { exact: true }).first().click();
await page.waitForTimeout(300);
console.log(` - 选择主题:${TEST_COURSE.theme}`);
// 选择适用年级
await page.getByRole('checkbox', { name: TEST_COURSE.grades[0] }).click();
await page.waitForTimeout(300);
console.log(` - 选择年级:${TEST_COURSE.grades[0]}`);
// 填写核心内容
const coreContentInput = page.getByPlaceholder('请输入课程包核心内容');
await expect(coreContentInput).toBeVisible({ timeout: 3000 });
await coreContentInput.fill(TEST_COURSE.coreContent);
console.log(` - 填写核心内容:${TEST_COURSE.coreContent}`);
// 填写绘本名称
const bookNameInput = page.getByPlaceholder('请输入关联绘本名称(可选)');
await expect(bookNameInput).toBeVisible({ timeout: 3000 });
await bookNameInput.fill(TEST_COURSE.pictureBookName);
console.log(` - 填写绘本名称:${TEST_COURSE.pictureBookName}`);
// 选择领域标签
const domainSelector = page.locator('.ant-select-selector').last();
await domainSelector.click();
await page.waitForTimeout(800);
await page.getByText(TEST_COURSE.domainTags[0], { exact: true }).first().click({ force: true });
await page.waitForTimeout(300);
await page.keyboard.press('Escape');
console.log(` - 选择领域标签:${TEST_COURSE.domainTags[0]}`);
// 点击下一步
await page.getByRole('button', { name: '下一步' }).click();
await page.waitForTimeout(1000);
console.log('✅ 步骤 1 完成 - 基本信息');
// ==================== 步骤 2: 课程介绍 ====================
console.log('\n========== 步骤 2: 课程介绍 ==========');
await expect(page.locator('.intro-header .title:has-text("课程介绍")')).toBeVisible({ timeout: 3000 });
// 填写课程简介 - 使用更精确的定位
await page.getByRole('tab', { name: '课程简介' }).click();
await page.waitForTimeout(1000);
// 使用 visible 选择器找到可见的 textarea
const summaryTextarea = page.locator('.tab-content textarea:visible').first();
await summaryTextarea.waitFor({ state: 'visible', timeout: 10000 });
await summaryTextarea.fill(TEST_COURSE.introSummary);
console.log(' - 填写课程简介');
// 填写课程亮点
await page.getByRole('tab', { name: '课程亮点' }).click();
await page.waitForTimeout(500);
await page.locator('.tab-content textarea:visible').first().fill(TEST_COURSE.introHighlights);
console.log(' - 填写课程亮点');
// 填写课程总目标
await page.getByRole('tab', { name: '课程总目标' }).click();
await page.waitForTimeout(500);
await page.locator('.tab-content textarea:visible').first().fill(TEST_COURSE.introGoals);
console.log(' - 填写课程目标');
// 填写内容安排
await page.getByRole('tab', { name: '内容安排' }).click();
await page.waitForTimeout(500);
await page.locator('.tab-content textarea:visible').first().fill(TEST_COURSE.introSchedule);
console.log(' - 填写内容安排');
// 填写重难点
await page.getByRole('tab', { name: '重难点' }).click();
await page.waitForTimeout(500);
await page.locator('.tab-content textarea:visible').first().fill(TEST_COURSE.introKeyPoints);
console.log(' - 填写重难点');
// 填写教学方法
await page.getByRole('tab', { name: '教学方法' }).click();
await page.waitForTimeout(500);
await page.locator('.tab-content textarea:visible').first().fill(TEST_COURSE.introMethods);
console.log(' - 填写教学方法');
// 填写评价方式
await page.getByRole('tab', { name: '评价方式' }).click();
await page.waitForTimeout(500);
await page.locator('.tab-content textarea:visible').first().fill(TEST_COURSE.introEvaluation);
console.log(' - 填写评价方式');
// 填写注意事项
await page.getByRole('tab', { name: '注意事项' }).click();
await page.waitForTimeout(500);
await page.locator('.tab-content textarea:visible').first().fill(TEST_COURSE.introNotes);
console.log(' - 填写注意事项');
// 点击下一步
await page.getByRole('button', { name: '下一步' }).click();
await page.waitForTimeout(1000);
console.log('✅ 步骤 2 完成 - 课程介绍');
// ==================== 步骤 3: 排课参考 ====================
console.log('\n========== 步骤 3: 排课参考 ==========');
await expect(page.locator('.step3-schedule-ref .title:has-text("排课计划参考")')).toBeVisible({ timeout: 3000 });
// 使用快速填充模板(可选步骤,跳过详细填写)
const fillWeekButton = page.getByText('填充一周模板');
if (await fillWeekButton.isVisible({ timeout: 5000 })) {
await fillWeekButton.click();
await page.waitForTimeout(500);
console.log(' - 使用快速填充模板');
}
// 点击下一步
await page.getByRole('button', { name: '下一步' }).click();
await page.waitForTimeout(1000);
console.log('✅ 步骤 3 完成 - 排课参考');
// ==================== 步骤 4: 导入课 ====================
console.log('\n========== 步骤 4: 导入课 ==========');
await expect(page.locator('.step4-intro-lesson .title:has-text("导入课")')).toBeVisible({ timeout: 3000 });
// 点击创建导入课按钮(如果需要)
const createIntroButton = page.getByText('创建导入课');
if (await createIntroButton.isVisible({ timeout: 3000 })) {
await createIntroButton.click();
await page.waitForTimeout(1500); // 增加等待时间让组件渲染
console.log(' - 点击创建导入课');
}
// 等待输入框加载完成
await page.waitForTimeout(500);
// 填写导入课名称 - 使用更精确的选择器
const introLessonNameInput = page.locator('input[placeholder="请输入课程名称"]').first();
if (await introLessonNameInput.isVisible({ timeout: 5000 })) {
await introLessonNameInput.fill(TEST_COURSE.introLessonName);
console.log(` - 填写导入课名称:${TEST_COURSE.introLessonName}`);
} else {
console.log(' ⚠️ 未找到导入课名称输入框');
}
// 填写课时时长 - 使用 aria-label 或 class 选择器
const introLessonDurationInput = page.locator('.ant-input-number-input').first();
if (await introLessonDurationInput.isVisible({ timeout: 5000 })) {
await introLessonDurationInput.fill(String(TEST_COURSE.introLessonDuration));
console.log(` - 填写导入课时长:${TEST_COURSE.introLessonDuration}分钟`);
} else {
console.log(' ⚠️ 未找到导入课时长输入框');
}
// 填写教学目标
const introLessonObjectivesTextarea = page.locator('textarea[placeholder*="教学目标"]').first();
if (await introLessonObjectivesTextarea.isVisible({ timeout: 3000 })) {
await introLessonObjectivesTextarea.fill(TEST_COURSE.introLessonObjectives);
console.log(' - 填写导入课教学目标');
}
// 填写教学准备
const introLessonPreparationTextarea = page.locator('textarea[placeholder*="教学准备"]').first();
if (await introLessonPreparationTextarea.isVisible({ timeout: 3000 })) {
await introLessonPreparationTextarea.fill(TEST_COURSE.introLessonPreparation);
console.log(' - 填写导入课教学准备');
}
// 点击下一步
await page.getByRole('button', { name: '下一步' }).click();
await page.waitForTimeout(1000);
console.log('✅ 步骤 4 完成 - 导入课');
// ==================== 步骤 5: 集体课 ====================
console.log('\n========== 步骤 5: 集体课 ==========');
await expect(page.locator('.step5-collective-lesson .title:has-text("集体课")')).toBeVisible({ timeout: 3000 });
// 点击创建集体课按钮(如果需要)
const createCollectiveButton = page.getByText('创建集体课');
if (await createCollectiveButton.isVisible({ timeout: 3000 })) {
await createCollectiveButton.click();
await page.waitForTimeout(1500); // 增加等待时间让组件渲染
console.log(' - 点击创建集体课');
}
// 等待输入框加载完成
await page.waitForTimeout(500);
// 填写集体课名称 - 使用更精确的选择器
const collectiveLessonNameInput = page.locator('input[placeholder="请输入课程名称"]').first();
if (await collectiveLessonNameInput.isVisible({ timeout: 5000 })) {
await collectiveLessonNameInput.fill(TEST_COURSE.collectiveLessonName);
console.log(` - 填写集体课名称:${TEST_COURSE.collectiveLessonName}`);
} else {
console.log(' ⚠️ 未找到集体课名称输入框');
}
// 填写课时时长 - 使用 aria-label 或 class 选择器
const collectiveLessonDurationInput = page.locator('.ant-input-number-input').nth(1);
if (await collectiveLessonDurationInput.isVisible({ timeout: 5000 })) {
await collectiveLessonDurationInput.fill(String(TEST_COURSE.collectiveLessonDuration));
console.log(` - 填写集体课时长:${TEST_COURSE.collectiveLessonDuration}分钟`);
} else {
console.log(' ⚠️ 未找到集体课时长输入框');
}
// 填写教学目标
const collectiveLessonObjectivesTextarea = page.locator('textarea[placeholder*="教学目标"]').first();
if (await collectiveLessonObjectivesTextarea.isVisible({ timeout: 3000 })) {
await collectiveLessonObjectivesTextarea.fill(TEST_COURSE.collectiveLessonObjectives);
console.log(' - 填写集体课教学目标');
}
// 填写教学准备
const collectiveLessonPreparationTextarea = page.locator('textarea[placeholder*="教学准备"]').first();
if (await collectiveLessonPreparationTextarea.isVisible({ timeout: 3000 })) {
await collectiveLessonPreparationTextarea.fill(TEST_COURSE.collectiveLessonObjectives);
console.log(' - 填写集体课教学准备');
}
// 点击下一步
await page.getByRole('button', { name: '下一步' }).click();
await page.waitForTimeout(1000);
console.log('✅ 步骤 5 完成 - 集体课');
// ==================== 步骤 6: 领域课 ====================
console.log('\n========== 步骤 6: 领域课 ==========');
await expect(page.locator('.step6-domain-lessons .title:has-text("五大领域课")')).toBeVisible({ timeout: 3000 });
// 填写健康领域课程
console.log(' - 填写健康领域课程');
// 展开健康领域卡片
const healthDomainCard = page.locator('.domain-card').filter({ hasText: /健康/ }).first();
const healthSwitch = healthDomainCard.locator('.ant-switch').first();
if (await healthSwitch.isVisible({ timeout: 3000 })) {
await healthSwitch.click();
await page.waitForTimeout(1000); // 增加等待时间让面板展开
}
// 等待输入框加载完成
await page.waitForTimeout(500);
// 填写健康领域课程名称 - 在 domain-card 内查找
const healthLessonNameInput = healthDomainCard.locator('input[placeholder="请输入课程名称"]').first();
if (await healthLessonNameInput.isVisible({ timeout: 5000 })) {
await healthLessonNameInput.fill(TEST_COURSE.healthLessonName);
console.log(` 课程名称:${TEST_COURSE.healthLessonName}`);
} else {
console.log(' ⚠️ 未找到健康领域课程名称输入框');
}
// 填写课时时长 - 在 domain-card 内查找第一个 input-number
const healthLessonDurationInput = healthDomainCard.locator('.ant-input-number-input').first();
if (await healthLessonDurationInput.isVisible({ timeout: 5000 })) {
await healthLessonDurationInput.fill(String(TEST_COURSE.healthLessonDuration));
console.log(` 课时时长:${TEST_COURSE.healthLessonDuration}分钟`);
} else {
console.log(' ⚠️ 未找到健康领域课程时长输入框');
}
// 填写教学目标
const healthLessonObjectivesTextarea = healthDomainCard.locator('textarea[placeholder*="教学目标"]').first();
if (await healthLessonObjectivesTextarea.isVisible({ timeout: 3000 })) {
await healthLessonObjectivesTextarea.fill(TEST_COURSE.healthLessonObjectives);
console.log(' 教学目标:已填写');
}
// 填写科学领域课程
console.log(' - 填写科学领域课程');
// 展开科学领域卡片
const scienceDomainCard = page.locator('.domain-card').filter({ hasText: /科学/ }).first();
const scienceSwitch = scienceDomainCard.locator('.ant-switch').first();
if (await scienceSwitch.isVisible({ timeout: 3000 })) {
await scienceSwitch.click();
await page.waitForTimeout(1000); // 增加等待时间让面板展开
}
// 等待输入框加载完成
await page.waitForTimeout(500);
// 填写科学领域课程名称 - 在 domain-card 内查找
const scienceLessonNameInput = scienceDomainCard.locator('input[placeholder="请输入课程名称"]').first();
if (await scienceLessonNameInput.isVisible({ timeout: 5000 })) {
await scienceLessonNameInput.fill(TEST_COURSE.scienceLessonName);
console.log(` 课程名称:${TEST_COURSE.scienceLessonName}`);
} else {
console.log(' ⚠️ 未找到科学领域课程名称输入框');
}
// 填写课时时长 - 在 domain-card 内查找 input-number
const scienceLessonDurationInput = scienceDomainCard.locator('.ant-input-number-input').first();
if (await scienceLessonDurationInput.isVisible({ timeout: 5000 })) {
await scienceLessonDurationInput.fill(String(TEST_COURSE.scienceLessonDuration));
console.log(` 课时时长:${TEST_COURSE.scienceLessonDuration}分钟`);
} else {
console.log(' ⚠️ 未找到科学领域课程时长输入框');
}
// 填写教学目标
const scienceLessonObjectivesTextarea = scienceDomainCard.locator('textarea[placeholder*="教学目标"]').first();
if (await scienceLessonObjectivesTextarea.isVisible({ timeout: 3000 })) {
await scienceLessonObjectivesTextarea.fill(TEST_COURSE.scienceLessonObjectives);
console.log(' 教学目标:已填写');
}
// 点击下一步
await page.getByRole('button', { name: '下一步' }).click();
await page.waitForTimeout(1000);
console.log('✅ 步骤 6 完成 - 领域课');
// ==================== 步骤 7: 环创建设 ====================
console.log('\n========== 步骤 7: 环创建设 ==========');
await expect(page.locator('.step7-environment .title:has-text("环创建设")')).toBeVisible({ timeout: 3000 });
// 填写环创建设内容
const envTextarea = page.locator('.step7-environment textarea').first();
await expect(envTextarea).toBeVisible({ timeout: 3000 });
await envTextarea.fill(TEST_COURSE.environmentConstruction);
console.log(' - 填写环创建设内容');
// 点击提交/创建按钮 - 使用 CSS 选择器定位
const submitButton = page.locator('.step-actions button.ant-btn-primary').last();
await submitButton.waitFor({ state: 'visible', timeout: 10000 });
// 监听网络请求
console.log('⏳ 开始监听网络请求...');
const [response] = await Promise.all([
page.waitForResponse(res =>
res.url().includes('/api/v1/admin/courses') &&
res.request().method() === 'POST'
).catch(() => null),
submitButton.click()
]);
console.log(' - 点击创建按钮');
console.log(' - 课程创建请求:', response ? response.status() : '未发送');
console.log('✅ 步骤 7 完成 - 环创建设');
// 等待一段时间让保存操作完成
await page.waitForTimeout(5000);
// ==================== 验证创建成功 ====================
console.log('\n========== 验证创建结果 ==========');
// 检查浏览器控制台日志
console.log('📋 准备检查页面状态...');
// 等待成功提示
try {
await page.waitForSelector('.ant-message-success', { timeout: 10000 });
console.log('✅ 成功提示显示');
} catch (e) {
console.log('⚠️ 未找到成功提示,检查是否有错误提示');
const errorMsg = await page.locator('.ant-message-error').textContent().catch(() => '');
if (errorMsg) {
console.error('❌ 错误信息:', errorMsg);
}
}
// 给页面一些时间执行跳转逻辑
await page.waitForTimeout(2000);
// 等待跳转到列表页 - 使用精确匹配(排除 edit 页面)
console.log('⏳ 等待页面跳转到课程列表...');
await page.waitForURL((url) => {
const urlStr = url.toString();
if (urlStr.includes('/edit')) {
console.log(' - 仍在编辑页面URL:', urlStr);
return false;
}
if (urlStr.includes('/admin/courses')) {
console.log(' - 已跳转到课程列表页URL:', urlStr);
return true;
}
return false;
}, { timeout: 15000 });
console.log('✅ 页面跳转到课程列表');
// 等待表格加载完成
await page.waitForTimeout(3000);
// 检查当前 URL
const currentUrl = page.url();
console.log('📍 当前 URL:', currentUrl);
// 使用更宽松的等待策略
const table = page.locator('.ant-table').first();
await table.waitFor({ state: 'attached', timeout: 10000 });
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
await page.waitForTimeout(2000);
// 检查表格是否为空
const isEmpty = await table.locator('.ant-empty').isVisible().catch(() => false);
console.log('📊 表格是否为空:', isEmpty);
// 获取表格行数
const rowCount = await table.locator('.ant-table-tbody tr').count();
console.log('📊 表格行数:', rowCount);
// 获取所有课程包名称
const courseNames = await page.locator('.ant-table-tbody tr td:first-child').allTextContents();
console.log('📊 当前课程包列表:', courseNames);
// 查找新课程包
const courseRow = table.getByText(TEST_COURSE.name);
try {
await expect(courseRow).toBeVisible({ timeout: 10000 });
console.log(`✅ 新课程包 "${TEST_COURSE.name}" 在列表中显示`);
} catch {
// 如果找不到,刷新页面后再试一次
console.log(' - 第一次尝试未找到,刷新页面...');
await page.reload({ waitUntil: 'networkidle' });
await page.waitForTimeout(2000);
// 再次检查课程包列表
const courseNamesAfterRefresh = await page.locator('.ant-table-tbody tr td:first-child').allTextContents();
console.log('📊 刷新后课程包列表:', courseNamesAfterRefresh);
await expect(table.getByText(TEST_COURSE.name)).toBeVisible({ timeout: 10000 });
console.log(`✅ 新课程包 "${TEST_COURSE.name}" 在列表中显示(刷新后)`);
}
console.log('\n🎉 课程包创建测试全部通过!');
});
});