kindergarten_java/lesingle-edu-reading-platform-frontend/tests/e2e/prepare-mode-flow/prepare-mode.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

531 lines
18 KiB
TypeScript
Raw 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.

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 }) => {
// 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();
await firstCourseCard.click();
await page.waitForTimeout(2000);
// 3. 点击开始备课
const prepareButton = page.locator('button:has-text("开始备课")');
await prepareButton.click();
// 4. 验证跳转
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 5. 验证备课模式结构
await expect(page.locator('aside, [class*="navigation"], [class*="sidebar"]').first()).toBeVisible();
await expect(page.locator('[class*="preview"], [class*="content"]').first()).toBeVisible();
test.info().annotations.push({
type: 'success',
description: '成功进入备课模式',
});
await page.screenshot({ path: 'test-results/prepare-mode-layout.png' });
});
test('测试2: 左侧导航 - 课程包概览', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 点击课程包概览
const overviewNav = page.locator('text=课程包概览').or(page.locator('[class*="overview"]'));
if (await overviewNav.count() > 0) {
await overviewNav.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证基本信息展示
const basicInfo = page.locator('[class*="basic"], [class*="info"]');
if (await basicInfo.count() > 0) {
await expect(basicInfo.first()).toBeVisible();
}
// 3. 验证统计数据
const stats = page.locator('[class*="stat"], [class*="count"]');
const statCount = await stats.count();
test.info().annotations.push({
type: 'info',
description: `统计项数量: ${statCount}`,
});
await page.screenshot({ path: 'test-results/prepare-overview.png' });
});
test('测试3: 左侧导航 - 包含课程', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 点击包含课程
const lessonsNav = page.locator('text=包含课程').or(page.locator('[class*="lessons"]'));
if (await lessonsNav.count() > 0) {
await lessonsNav.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证课程列表
const lessonList = page.locator('[class*="lesson"], [class*="course-item"]');
const lessonCount = await lessonList.count();
test.info().annotations.push({
type: 'info',
description: `课程数量: ${lessonCount}`,
});
expect(lessonCount).toBeGreaterThan(0);
// 3. 点击第一个课程
if (lessonCount > 0) {
await lessonList.first().click();
await page.waitForTimeout(1000);
}
await page.screenshot({ path: 'test-results/prepare-lessons.png' });
});
test('测试4: 右侧内容预览 - 课程介绍', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 点击课程介绍Tab
const introTab = page.locator('text=课程介绍').or(page.locator('[class*="intro"]'));
if (await introTab.count() > 0) {
await introTab.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证介绍内容展示
const introContent = page.locator('[class*="intro"], [class*="content"]');
expect(await introContent.count()).toBeGreaterThan(0);
// 3. 验证8个介绍字段
const introFields = ['简介', '亮点', '目标', '安排', '重难点', '方法', '评价', '注意事项'];
let visibleFieldCount = 0;
for (const field of introFields) {
const fieldLocator = page.locator(`text=${field}`);
if (await fieldLocator.count() > 0) {
visibleFieldCount++;
}
}
test.info().annotations.push({
type: 'info',
description: `介绍字段: ${visibleFieldCount}/${introFields.length}`,
});
await page.screenshot({ path: 'test-results/prepare-intro-content.png', fullPage: true });
});
test('测试5: 右侧内容预览 - 排课参考', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 点击排课参考Tab
const scheduleTab = page.locator('text=排课参考').or(page.locator('[class*="schedule"]'));
if (await scheduleTab.count() > 0) {
await scheduleTab.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证排课表格或内容
const scheduleTable = page.locator('table').or(page.locator('[class*="table"]'));
const scheduleContent = page.locator('[class*="schedule-content"]');
const hasTable = await scheduleTable.count() > 0;
const hasContent = await scheduleContent.count() > 0;
test.info().annotations.push({
type: 'info',
description: hasTable ? '显示排课表格' : (hasContent ? '显示排课内容' : '未找到排课参考'),
});
await page.screenshot({ path: 'test-results/prepare-schedule.png' });
});
test('测试6: 右侧内容预览 - 环创建设', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 点击环创建设Tab
const envTab = page.locator('text=环创建设').or(page.locator('[class*="environment"]'));
if (await envTab.count() > 0) {
await envTab.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证环创建设内容
const envContent = page.locator('text=主题环境').or(page.locator('text=区域活动')).or(page.locator('[class*="environment"]'));
const hasContent = await envContent.count() > 0;
test.info().annotations.push({
type: 'info',
description: hasContent ? '显示环创建设内容' : '未找到环创建设',
});
await page.screenshot({ path: 'test-results/prepare-environment.png' });
});
test('测试7: 教学目标展示', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 选择导入课
const introLesson = page.locator('text=导入课').or(page.locator('[class*="introduction"]'));
if (await introLesson.count() > 0) {
await introLesson.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证教学目标展示
const objectives = page.locator('text=教学目标').or(page.locator('[class*="objective"]'));
if (await objectives.count() > 0) {
await expect(objectives.first()).toBeVisible();
}
// 3. 验证教学准备展示
const preparation = page.locator('text=教学准备').or(page.locator('[class*="preparation"]'));
if (await preparation.count() > 0) {
await expect(preparation.first()).toBeVisible();
}
await page.screenshot({ path: 'test-results/prepare-objectives.png' });
});
test('测试8: 教学过程展示', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 选择导入课
const introLesson = page.locator('text=导入课').or(page.locator('[class*="introduction"]'));
if (await introLesson.count() > 0) {
await introLesson.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证教学过程展示
const process = page.locator('text=教学过程').or(page.locator('[class*="process"], [class*="steps"]'));
if (await process.count() > 0) {
await expect(process.first()).toBeVisible();
}
// 3. 验证环节列表
const steps = page.locator('[class*="step"], [class*="stage"]');
const stepCount = await steps.count();
test.info().annotations.push({
type: 'info',
description: `教学环节数量: ${stepCount}`,
});
// 4. 展开第一个环节查看详情
if (stepCount > 0) {
await steps.first().click();
await page.waitForTimeout(500);
}
await page.screenshot({ path: 'test-results/prepare-process.png', fullPage: true });
});
test('测试9: 核心资源展示', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 选择导入课
const introLesson = page.locator('text=导入课').or(page.locator('[class*="introduction"]'));
if (await introLesson.count() > 0) {
await introLesson.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证核心资源展示
const resources = page.locator('text=核心资源').or(page.locator('[class*="resource"]'));
const resourceCount = await resources.count();
test.info().annotations.push({
type: 'info',
description: resourceCount > 0 ? `找到 ${resourceCount} 个资源区域` : '未找到核心资源区域',
});
// 3. 验证资源类型视频、PPT、PDF等
const resourceTypes = ['视频', 'PPT', 'PDF', '音频', '图片'];
const foundTypes: string[] = [];
for (const type of resourceTypes) {
const typeLocator = page.locator(`text=${type}`);
if (await typeLocator.count() > 0) {
foundTypes.push(type);
}
}
test.info().annotations.push({
type: 'info',
description: `资源类型: ${foundTypes.join(', ') || '无'}`,
});
await page.screenshot({ path: 'test-results/prepare-resources.png' });
});
test('测试10: 教学延伸和反思', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 选择导入课
const introLesson = page.locator('text=导入课').or(page.locator('[class*="introduction"]'));
if (await introLesson.count() > 0) {
await introLesson.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证教学延伸
const extension = page.locator('text=教学延伸').or(page.locator('[class*="extension"]'));
if (await extension.count() > 0) {
await expect(extension.first()).toBeVisible();
}
// 3. 验证教学反思
const reflection = page.locator('text=教学反思').or(page.locator('[class*="reflection"]'));
if (await reflection.count() > 0) {
await expect(reflection.first()).toBeVisible();
}
await page.screenshot({ path: 'test-results/prepare-extension.png' });
});
test('测试11: 备课笔记功能', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 点击备课笔记Tab
const notesTab = page.locator('text=备课笔记').or(page.locator('[class*="notes"]'));
if (await notesTab.count() > 0) {
await notesTab.first().click();
await page.waitForTimeout(1000);
}
// 2. 验证笔记编辑器
const editor = page.locator('[contenteditable="true"], .ant-input, textarea');
const hasEditor = await editor.count() > 0;
if (hasEditor) {
// 3. 尝试输入笔记内容
await editor.first().fill('这是测试笔记内容');
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/prepare-notes.png' });
});
test('测试12: 从备课模式进入上课', async ({ page }) => {
test.slow();
// 进入备课模式
await page.click('text=课程中心');
await page.waitForURL('**/courses', { timeout: 10000 });
await page.waitForTimeout(1000);
const firstCourseCard = page.locator('.course-card').or(page.locator('[class*="course-card"]')).first();
await firstCourseCard.click();
await page.waitForTimeout(2000);
await page.click('button:has-text("开始备课")');
await page.waitForURL('**/prepare', { timeout: 10000 });
await page.waitForTimeout(2000);
// 1. 查找开始上课按钮
const startClassButton = page.locator('button:has-text("开始上课")').or(page.locator('button:has-text("进入上课")'));
const buttonExists = await startClassButton.count() > 0;
if (buttonExists) {
await startClassButton.first().click();
await page.waitForTimeout(2000);
// 2. 验证跳转到上课模式或课程选择弹窗
const url = page.url();
test.info().annotations.push({
type: 'info',
description: `点击后URL: ${url}`,
});
// 3. 如果显示课程选择弹窗,选择所有课程
const selectModal = page.locator('[class*="modal"], [class*="select"]');
if (await selectModal.count() > 0) {
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);
}
}
} else {
test.info().annotations.push({
type: 'warning',
description: '未找到"开始上课"按钮',
});
}
await page.screenshot({ path: 'test-results/prepare-to-class.png' });
});
});