前后端目录重命名: - 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 文档中的路径引用
387 lines
13 KiB
TypeScript
387 lines
13 KiB
TypeScript
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(2000);
|
|
|
|
// 2. 验证页面标题
|
|
await expect(page.locator('text=课程中心').or(page.locator('.page-title'))).toBeVisible();
|
|
|
|
// 3. 验证筛选栏存在
|
|
const filterBar = page.locator('.filter-bar').or(page.locator('[class*="filter"]'));
|
|
await expect(filterBar.first()).toBeVisible();
|
|
|
|
// 4. 验证课程卡片加载
|
|
const courseCards = page.locator('.course-card').or(page.locator('[class*="course-card"]'));
|
|
const cardCount = await courseCards.count();
|
|
|
|
test.info().annotations.push({
|
|
type: 'info',
|
|
description: `课程卡片数量: ${cardCount}`,
|
|
});
|
|
|
|
// 5. 验证至少有一个课程
|
|
expect(cardCount).toBeGreaterThan(0);
|
|
|
|
// 6. 验证课程卡片元素
|
|
const firstCard = courseCards.first();
|
|
await expect(firstCard.locator('.course-title').or(page.locator('h3'))).toBeVisible();
|
|
|
|
// 截图
|
|
await page.screenshot({ path: 'test-results/course-list.png' });
|
|
});
|
|
|
|
test('测试2: 筛选功能', async ({ page }) => {
|
|
test.slow();
|
|
|
|
// 1. 进入课程中心
|
|
await page.click('text=课程中心');
|
|
await page.waitForURL('**/courses', { timeout: 10000 });
|
|
await page.waitForTimeout(2000);
|
|
|
|
// 2. 测试年级筛选
|
|
const gradeFilter = page.locator('.filter-item').filter({ hasText: '年级' }).locator('.ant-select');
|
|
if (await gradeFilter.count() > 0) {
|
|
await gradeFilter.first().click();
|
|
await page.waitForTimeout(500);
|
|
await page.click('text=小班');
|
|
await page.waitForTimeout(1500);
|
|
}
|
|
|
|
// 3. 测试领域筛选
|
|
const domainFilter = page.locator('.filter-item').filter({ hasText: '领域' }).locator('.ant-select');
|
|
if (await domainFilter.count() > 0) {
|
|
await domainFilter.first().click();
|
|
await page.waitForTimeout(500);
|
|
await page.click('text=语言');
|
|
await page.waitForTimeout(1500);
|
|
}
|
|
|
|
// 4. 测试搜索功能
|
|
const searchInput = page.locator('input[placeholder*="搜索"]');
|
|
if (await searchInput.count() > 0) {
|
|
await searchInput.first().fill('测试');
|
|
await page.waitForTimeout(2000);
|
|
}
|
|
|
|
// 截图
|
|
await page.screenshot({ path: 'test-results/course-filter.png' });
|
|
|
|
test.info().annotations.push({
|
|
type: 'success',
|
|
description: '筛选功能测试完成',
|
|
});
|
|
});
|
|
|
|
test('测试3: 课程详情页完整信息', 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();
|
|
await firstCourseCard.click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// 3. 验证课程详情页URL
|
|
const url = page.url();
|
|
expect(url).toContain('/courses/');
|
|
|
|
// 4. 验证课程基本信息
|
|
await expect(page.locator('.course-title, h1').first()).toBeVisible();
|
|
await expect(page.locator('text=开始备课')).toBeVisible();
|
|
await expect(page.locator('text=选择课程上课')).toBeVisible();
|
|
|
|
// 5. 验证Tab导航存在
|
|
const tabs = page.locator('.ant-tabs-tab');
|
|
const tabCount = await tabs.count();
|
|
|
|
test.info().annotations.push({
|
|
type: 'info',
|
|
description: `Tab数量: ${tabCount}`,
|
|
});
|
|
|
|
// 6. 验证核心内容Tab
|
|
const introTab = page.locator('text=课程介绍').or(page.locator('[class*="intro"]'));
|
|
if (await introTab.count() > 0) {
|
|
await introTab.first().click();
|
|
await page.waitForTimeout(1000);
|
|
}
|
|
|
|
// 7. 验证课程配置Tab
|
|
const lessonsTab = page.locator('text=课程配置').or(page.locator('[class*="lesson"]'));
|
|
if (await lessonsTab.count() > 0) {
|
|
await lessonsTab.first().click();
|
|
await page.waitForTimeout(1000);
|
|
}
|
|
|
|
// 8. 验证数字资源Tab
|
|
const resourcesTab = page.locator('text=数字资源').or(page.locator('[class*="resource"]'));
|
|
if (await resourcesTab.count() > 0) {
|
|
await resourcesTab.first().click();
|
|
await page.waitForTimeout(1000);
|
|
}
|
|
|
|
// 截图
|
|
await page.screenshot({ path: 'test-results/course-detail.png', fullPage: true });
|
|
});
|
|
|
|
test('测试4: 课程介绍内容验证', async ({ page }) => {
|
|
test.slow();
|
|
|
|
// 1. 进入课程中心并选择课程
|
|
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);
|
|
|
|
// 2. 点击课程介绍Tab
|
|
const introTab = page.locator('text=课程介绍');
|
|
if (await introTab.count() > 0) {
|
|
await introTab.first().click();
|
|
await page.waitForTimeout(1000);
|
|
}
|
|
|
|
// 3. 验证核心内容
|
|
const coreContent = page.locator('text=核心内容').or(page.locator('[class*="core"]'));
|
|
if (await coreContent.count() > 0) {
|
|
await expect(coreContent.first()).toBeVisible();
|
|
}
|
|
|
|
// 4. 验证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/course-intro.png', fullPage: true });
|
|
});
|
|
|
|
test('测试5: 课程配置验证', async ({ page }) => {
|
|
test.slow();
|
|
|
|
// 1. 进入课程中心并选择课程
|
|
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);
|
|
|
|
// 2. 点击课程配置Tab
|
|
const lessonsTab = page.locator('text=课程配置');
|
|
if (await lessonsTab.count() > 0) {
|
|
await lessonsTab.first().click();
|
|
await page.waitForTimeout(1000);
|
|
}
|
|
|
|
// 3. 验证导入课存在
|
|
const introLesson = page.locator('text=导入课').or(page.locator('[class*="introduction"]'));
|
|
const introCount = await introLesson.count();
|
|
|
|
// 4. 验证集体课存在
|
|
const collectiveLesson = page.locator('text=集体课').or(page.locator('[class*="collective"]'));
|
|
const collectiveCount = await collectiveLesson.count();
|
|
|
|
// 5. 验证五大领域课
|
|
const domainLessons = ['健康', '语言', '社会', '科学', '艺术'];
|
|
let visibleDomainCount = 0;
|
|
for (const domain of domainLessons) {
|
|
const domainLocator = page.locator(`text=${domain}领域`);
|
|
if (await domainLocator.count() > 0) {
|
|
visibleDomainCount++;
|
|
}
|
|
}
|
|
|
|
test.info().annotations.push({
|
|
type: 'info',
|
|
description: `导入课: ${introCount > 0 ? '✓' : '✗'}, 集体课: ${collectiveCount > 0 ? '✓' : '✗'}, 领域课: ${visibleDomainCount}/5`,
|
|
});
|
|
|
|
// 6. 验证教学环节展开
|
|
const stepContent = page.locator('[class*="step"]').or(page.locator('[class*="process"]'));
|
|
if (await stepContent.count() > 0) {
|
|
await expect(stepContent.first()).toBeVisible();
|
|
}
|
|
|
|
// 截图
|
|
await page.screenshot({ path: 'test-results/course-lessons.png', fullPage: true });
|
|
});
|
|
|
|
test('测试6: 数字资源验证', async ({ page }) => {
|
|
test.slow();
|
|
|
|
// 1. 进入课程中心并选择课程
|
|
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);
|
|
|
|
// 2. 点击数字资源Tab
|
|
const resourcesTab = page.locator('text=数字资源');
|
|
if (await resourcesTab.count() > 0) {
|
|
await resourcesTab.first().click();
|
|
await page.waitForTimeout(1000);
|
|
}
|
|
|
|
// 3. 验证资源分类
|
|
const resourceTypes = ['图片', '视频', '音频', 'PPT', 'PDF'];
|
|
const resourceResults: Record<string, boolean> = {};
|
|
|
|
for (const type of resourceTypes) {
|
|
const typeLocator = page.locator(`text=${type}`);
|
|
resourceResults[type] = await typeLocator.count() > 0;
|
|
}
|
|
|
|
test.info().annotations.push({
|
|
type: 'info',
|
|
description: `资源类型: ${JSON.stringify(resourceResults)}`,
|
|
});
|
|
|
|
// 4. 验证资源列表或空状态
|
|
const resourceList = page.locator('[class*="resource"]').or(page.locator('[class*="file"]'));
|
|
const emptyState = page.locator('text=暂无资源').or(page.locator('[class*="empty"]'));
|
|
|
|
const hasResources = await resourceList.count() > 0;
|
|
const hasEmptyState = await emptyState.count() > 0;
|
|
|
|
test.info().annotations.push({
|
|
type: 'info',
|
|
description: hasResources ? '有资源文件' : (hasEmptyState ? '显示空状态' : '未找到资源区域'),
|
|
});
|
|
|
|
// 截图
|
|
await page.screenshot({ path: 'test-results/course-resources.png', fullPage: true });
|
|
});
|
|
|
|
test('测试7: 收藏功能', async ({ page }) => {
|
|
// 1. 进入课程中心并选择课程
|
|
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);
|
|
|
|
// 2. 查找收藏按钮
|
|
const favoriteButton = page.locator('text=收藏').or(page.locator('[class*="favorite"]'));
|
|
const favoriteExists = await favoriteButton.count() > 0;
|
|
|
|
if (favoriteExists) {
|
|
// 3. 点击收藏
|
|
await favoriteButton.first().click();
|
|
await page.waitForTimeout(1000);
|
|
|
|
// 4. 验证收藏状态变化
|
|
test.info().annotations.push({
|
|
type: 'success',
|
|
description: '收藏功能测试完成',
|
|
});
|
|
} else {
|
|
test.info().annotations.push({
|
|
type: 'warning',
|
|
description: '未找到收藏按钮',
|
|
});
|
|
}
|
|
});
|
|
|
|
test('测试8: 从课程详情进入备课', async ({ page }) => {
|
|
// 1. 进入课程中心并选择课程
|
|
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);
|
|
|
|
// 2. 点击"开始备课"按钮
|
|
const prepareButton = page.locator('button:has-text("开始备课")');
|
|
await expect(prepareButton).toBeVisible();
|
|
await prepareButton.click();
|
|
|
|
// 3. 验证跳转到备课模式
|
|
await page.waitForURL('**/prepare', { timeout: 10000 });
|
|
await page.waitForTimeout(2000);
|
|
|
|
// 4. 验证备课模式布局
|
|
await expect(page.locator('aside, [class*="navigation"], [class*="sidebar"]').first()).toBeVisible();
|
|
|
|
// 5. 验证课程列表
|
|
const lessonItems = page.locator('[class*="lesson"], [class*="course"]');
|
|
const lessonCount = await lessonItems.count();
|
|
expect(lessonCount).toBeGreaterThan(0);
|
|
|
|
test.info().annotations.push({
|
|
type: 'success',
|
|
description: `成功进入备课模式,课程数量: ${lessonCount}`,
|
|
});
|
|
|
|
// 截图
|
|
await page.screenshot({ path: 'test-results/enter-prepare-mode.png' });
|
|
});
|
|
});
|