kindergarten_java/lesingle-edu-reading-platform-frontend/tests/e2e/reading-task-flow/reading-task-test.spec.ts

371 lines
13 KiB
TypeScript
Raw Permalink Normal View History

/**
* -
*
* :
* - 教师端: 任务创建
* - 家长端: 任务查看
* - 学校端: 只读列表
*/
import { test, expect, Page } from '@playwright/test';
// 测试账号
const TEST_ACCOUNTS = {
teacher: { username: 'teacher1', password: '123456', name: '李老师' },
parent: { username: 'parent1', password: '123456', name: '张妈妈' },
school: { username: 'school1', password: '123456', name: '阳光幼儿园' }
};
// 基础URL
const BASE_URL = 'http://localhost:5173';
// 生成唯一任务标题
const generateTaskTitle = () => `【E2E测试】亲子阅读任务_${Date.now()}`;
/**
*
*/
async function login(page: Page, role: 'teacher' | 'parent' | 'school') {
const account = TEST_ACCOUNTS[role];
await page.goto(`${BASE_URL}/login`);
await page.waitForLoadState('networkidle');
// 等待页面加载完成
await page.waitForSelector('.login-card', { timeout: 10000 });
// 选择角色
const roleMap: Record<string, string> = {
teacher: '教师',
parent: '家长',
school: '学校'
};
const roleBtn = page.locator(`.role-btn:has-text("${roleMap[role]}")`);
await roleBtn.click();
await page.waitForTimeout(300);
// 填写账号
const accountInput = page.locator('input[placeholder*="账号"]').first();
await accountInput.clear();
await accountInput.fill(account.username);
// 填写密码
const passwordInput = page.locator('input[placeholder*="密码"]').first();
await passwordInput.clear();
await passwordInput.fill(account.password);
// 点击登录按钮
const loginBtn = page.locator('button.login-btn, button:has-text("登录")').first();
await loginBtn.click();
// 等待跳转
await page.waitForURL(/\/(teacher|parent|school)/, { timeout: 15000 });
// 验证登录成功
await expect(page).toHaveURL(new RegExp(`/${role}`));
}
// ==================== 教师端测试 ====================
test.describe('教师端 - 阅读任务管理', () => {
let teacherPage: Page;
const taskTitle = generateTaskTitle();
test.beforeAll(async ({ browser }) => {
teacherPage = await browser.newPage();
await login(teacherPage, 'teacher');
});
test.afterAll(async () => {
await teacherPage.close();
});
test('T-LIST-01: 任务列表加载', async () => {
// 导航到任务列表
await teacherPage.goto(`${BASE_URL}/teacher/tasks`);
await teacherPage.waitForLoadState('networkidle');
// 验证页面标题
await expect(teacherPage.locator('h2, .ant-page-header-heading-title')).toContainText(/任务/);
// 验证任务卡片或列表存在
const taskCards = teacherPage.locator('.ant-card, .task-card, [class*="task-item"]');
await expect(taskCards.first()).toBeVisible({ timeout: 5000 });
console.log('✅ T-LIST-01 通过: 任务列表正常加载');
});
test('T-CREATE-01~11: 创建任务(含关联绘本字段)', async () => {
// 点击新建任务按钮
await teacherPage.goto(`${BASE_URL}/teacher/tasks`);
await teacherPage.waitForLoadState('networkidle');
const createBtn = teacherPage.locator('button:has-text("新建"), button:has-text("创建"), .ant-btn-primary:has-text("任务")');
await createBtn.first().click();
// 等待弹窗出现
await teacherPage.waitForSelector('.ant-modal', { timeout: 5000 });
// 填写任务标题
await teacherPage.fill('input[placeholder*="标题"], #title', taskTitle);
// 填写任务描述
await teacherPage.fill('textarea[placeholder*="描述"], #description', 'E2E自动化测试任务请勿删除');
// 选择任务类型
const typeSelect = teacherPage.locator('.ant-select:has-text("类型"), #type');
if (await typeSelect.isVisible()) {
await typeSelect.click();
await teacherPage.click('.ant-select-dropdown:visible li:has-text("阅读")');
}
// 填写关联绘本名称(核心验证点)
const bookNameInput = teacherPage.locator('input[placeholder*="绘本"], #relatedBookName, input[placeholder*="关联"]');
if (await bookNameInput.isVisible()) {
await bookNameInput.fill('好饿的毛毛虫');
console.log('✅ 关联绘本名称字段存在且可填写');
} else {
console.log('❌ 关联绘本名称字段不存在!');
}
// 选择目标班级
const targetSelect = teacherPage.locator('.ant-select:has-text("班级"), .ant-select:has-text("目标")');
if (await targetSelect.isVisible()) {
await targetSelect.click();
await teacherPage.waitForTimeout(300);
const firstOption = teacherPage.locator('.ant-select-dropdown:visible li').first();
if (await firstOption.isVisible()) {
await firstOption.click();
}
}
// 设置时间
const today = new Date().toISOString().split('T')[0];
const nextWeek = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
const startDateInput = teacherPage.locator('input[placeholder*="开始"], #startDate');
if (await startDateInput.isVisible()) {
await startDateInput.fill(today);
}
const endDateInput = teacherPage.locator('input[placeholder*="截止"], input[placeholder*="结束"], #endDate, #dueDate');
if (await endDateInput.isVisible()) {
await endDateInput.fill(nextWeek);
}
// 点击保存
await teacherPage.click('.ant-modal button:has-text("保存"), .ant-modal button:has-text("确定")');
// 等待保存成功
await teacherPage.waitForTimeout(2000);
// 验证保存成功
const successMsg = teacherPage.locator('.ant-message-success, .ant-notification-success');
const saved = await successMsg.isVisible().catch(() => false);
if (saved) {
console.log('✅ T-CREATE 通过: 任务创建成功');
} else {
// 检查列表中是否有新任务
await teacherPage.goto(`${BASE_URL}/teacher/tasks`);
await teacherPage.waitForLoadState('networkidle');
const newTask = teacherPage.locator(`text="${taskTitle}"`);
await expect(newTask).toBeVisible({ timeout: 5000 });
console.log('✅ T-CREATE 通过: 任务创建成功并在列表显示');
}
});
});
// ==================== 学校端只读测试 ====================
test.describe('学校端 - 阅读任务只读查看', () => {
let schoolPage: Page;
test.beforeAll(async ({ browser }) => {
schoolPage = await browser.newPage();
await login(schoolPage, 'school');
});
test.afterAll(async () => {
await schoolPage.close();
});
test('S-READONLY-01~05: 验证只读模式', async () => {
await schoolPage.goto(`${BASE_URL}/school/reading-tasks`);
await schoolPage.waitForLoadState('networkidle');
// 验证没有创建按钮
const createBtn = schoolPage.locator('button:has-text("新建"), button:has-text("创建任务")');
const hasCreateBtn = await createBtn.count();
expect(hasCreateBtn).toBe(0);
console.log('✅ S-READONLY-01 通过: 无创建按钮');
// 验证任务卡片没有编辑/删除按钮
const editBtn = schoolPage.locator('button:has-text("编辑")');
const hasEditBtn = await editBtn.count();
expect(hasEditBtn).toBe(0);
console.log('✅ S-READONLY-02 通过: 无编辑按钮');
const deleteBtn = schoolPage.locator('button:has-text("删除")');
const hasDeleteBtn = await deleteBtn.count();
expect(hasDeleteBtn).toBe(0);
console.log('✅ S-READONLY-03 通过: 无删除按钮');
});
test('S-LIST-01: 任务列表展示', async () => {
await schoolPage.goto(`${BASE_URL}/school/reading-tasks`);
await schoolPage.waitForLoadState('networkidle');
// 验证任务卡片存在
const taskCards = schoolPage.locator('.ant-card, [class*="task"]');
const count = await taskCards.count();
expect(count).toBeGreaterThan(0);
console.log(`✅ S-LIST-01 通过: 任务列表显示 ${count} 个任务`);
});
test('S-FILTER-01: 多维度筛选功能', async () => {
await schoolPage.goto(`${BASE_URL}/school/reading-tasks`);
await schoolPage.waitForLoadState('networkidle');
// 测试关键字搜索
const searchInput = schoolPage.locator('input[placeholder*="搜索"], input[placeholder*="关键字"]');
if (await searchInput.isVisible()) {
await searchInput.fill('阅读');
await schoolPage.waitForTimeout(500);
// 验证搜索结果
const searchResults = schoolPage.locator('.ant-card, [class*="task"]');
const count = await searchResults.count();
console.log(`✅ S-FILTER-01: 关键字搜索返回 ${count} 个结果`);
}
// 测试类型筛选
const typeFilter = schoolPage.locator('.ant-select:has-text("类型"), #type');
if (await typeFilter.isVisible()) {
await typeFilter.click();
await schoolPage.waitForTimeout(300);
const readingOption = schoolPage.locator('.ant-select-dropdown:visible li:has-text("阅读")');
if (await readingOption.isVisible()) {
await readingOption.click();
await schoolPage.waitForTimeout(500);
console.log('✅ S-FILTER-02: 类型筛选可用');
}
}
});
test('S-DETAIL-01: 任务详情查看', async () => {
await schoolPage.goto(`${BASE_URL}/school/reading-tasks`);
await schoolPage.waitForLoadState('networkidle');
// 点击第一个任务卡片
const firstTask = schoolPage.locator('.ant-card, [class*="task"]').first();
await firstTask.click();
// 等待详情弹窗或页面
await schoolPage.waitForTimeout(1000);
// 验证详情内容
const modal = schoolPage.locator('.ant-modal, .ant-drawer');
const detailPage = schoolPage.locator('[class*="detail"]');
if (await modal.isVisible() || await detailPage.isVisible()) {
console.log('✅ S-DETAIL-01 通过: 任务详情可以查看');
// 验证关联绘本字段是否显示
const bookNameElement = schoolPage.locator('text=/绘本|relatedBookName/');
if (await bookNameElement.isVisible()) {
console.log('✅ S-DETAIL-02 通过: 关联绘本字段显示');
}
} else {
console.log('⚠️ S-DETAIL-01: 任务详情未显示');
}
});
});
// ==================== 家长端测试 ====================
test.describe('家长端 - 任务查看与提交', () => {
let parentPage: Page;
test.beforeAll(async ({ browser }) => {
parentPage = await browser.newPage();
await login(parentPage, 'parent');
});
test.afterAll(async () => {
await parentPage.close();
});
test('P-LIST-01: 任务列表加载', async () => {
await parentPage.goto(`${BASE_URL}/parent/tasks`);
await parentPage.waitForLoadState('networkidle');
// 验证页面加载
const pageTitle = parentPage.locator('h2, .ant-page-header-heading-title, text=/任务/');
await expect(pageTitle.first()).toBeVisible({ timeout: 5000 });
console.log('✅ P-LIST-01 通过: 家长端任务列表加载');
});
test('P-LIST-02: 状态标签显示', async () => {
await parentPage.goto(`${BASE_URL}/parent/tasks`);
await parentPage.waitForLoadState('networkidle');
// 检查状态标签
const statusTags = parentPage.locator('.ant-tag');
const count = await statusTags.count();
if (count > 0) {
// 验证状态标签文本
const validStatuses = ['待提交', '已提交', '已评价', '待完成', '已完成'];
let hasValidStatus = false;
for (let i = 0; i < count; i++) {
const text = await statusTags.nth(i).textContent();
if (text && validStatuses.some(s => text.includes(s))) {
hasValidStatus = true;
break;
}
}
expect(hasValidStatus).toBe(true);
console.log('✅ P-LIST-02 通过: 状态标签显示正确');
} else {
console.log('⚠️ P-LIST-02: 暂无任务数据');
}
});
});
// ==================== 跨端流程测试 ====================
test.describe('跨端业务流程验证', () => {
test('X-FLOW-01: 验证三端数据一致性', async ({ browser }) => {
// 创建三个页面
const teacherPage = await browser.newPage();
const schoolPage = await browser.newPage();
const parentPage = await browser.newPage();
try {
// 三端分别登录
await login(teacherPage, 'teacher');
await login(schoolPage, 'school');
await login(parentPage, 'parent');
// 教师端查看任务数量
await teacherPage.goto(`${BASE_URL}/teacher/tasks`);
await teacherPage.waitForLoadState('networkidle');
const teacherTaskCount = await teacherPage.locator('.ant-card, [class*="task"]').count();
// 学校端查看任务数量
await schoolPage.goto(`${BASE_URL}/school/reading-tasks`);
await schoolPage.waitForLoadState('networkidle');
const schoolTaskCount = await schoolPage.locator('.ant-card, [class*="task"]').count();
// 验证学校端任务数量 >= 教师端(学校可以看到所有教师的任务)
expect(schoolTaskCount).toBeGreaterThanOrEqual(teacherTaskCount);
console.log(`✅ X-FLOW-01 通过: 教师端 ${teacherTaskCount} 个任务,学校端 ${schoolTaskCount} 个任务`);
} finally {
await teacherPage.close();
await schoolPage.close();
await parentPage.close();
}
});
});