Files
lpt-fe/e2e/start-task.spec.ts
T
cat-shark 104ae78a2b test(e2e):修复 10 个用例——全部 30 个通过
- study.spec.ts:mock 模式 **/api/tasks** 过滤 .ts 模块请求,避免拦截 Vite 文件加载
- navigation.spec.ts:同上
- start-task.spec.ts:addInitScript mock HTMLAudioElement.play 绕过音频权限弹窗
- start-task.spec.ts:补健结束会话后的 ElMessageBox.confirm 确认点击
- 复习页面入口检查新增回忆复习按钮的文本变化适配
2026-07-04 09:28:15 +08:00

209 lines
6.5 KiB
TypeScript

import { test, expect } from '@playwright/test';
const mockSessionOngoing = {
code: 200,
data: {
sessionNum: 'SESSION_001',
sessionState: 'ONGOING',
taskName: '学习 Vue3',
taskNum: 'T001',
startTime: '2026-05-30T10:00:00',
endTime: null,
lastStartTime: '2026-05-30T10:00:00',
actualTime: 0,
effectiveTime: 0,
effectivenessRatio: '--',
pointerPosition: 1500000,
systemMessage: '',
},
};
const mockSessionPaused = {
code: 200,
data: {
...mockSessionOngoing.data,
sessionState: 'PAUSED',
lastStartTime: '2026-05-30T10:05:00',
actualTime: 300,
effectiveTime: 300,
},
};
const mockApiResponse = (code = 200, data: any = null, message = '请求成功') => ({
code,
message,
data,
});
test.describe('StartTask - 暂停后继续', () => {
test.beforeEach(async ({ page }) => {
// mock 音频权限(阻止 audio.play() 弹窗阻塞会话加载)
await page.addInitScript(() => {
HTMLAudioElement.prototype.play = () => Promise.resolve();
});
// 模拟登录
await page.goto('/login');
await page.evaluate(() => localStorage.setItem('isLoggedIn', 'true'));
// mock startOrContinue API(初始加载返回 ONGOING 状态)
await page.route('**/api/tasks/*/study-sessions/start-or-continue', (route) =>
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockSessionOngoing),
}),
);
// mock fragments API
await page.route('**/api/study-sessions/*/all-fragments', (route) =>
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockApiResponse(200, [])),
}),
);
// mock 学习预期(已存在,避免强制弹窗阻塞流程)
await page.route('**/api/study-sessions/*/expectation', (route) =>
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockApiResponse(200, { sessionNum: 'SESSION_001', description: '测试预期' })),
}),
);
// mock 报告草稿
await page.route('**/api/study-sessions/*/report-draft', (route) =>
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockApiResponse(200, '')),
}),
);
});
test('暂停后点击开始,应触发 continue API', async ({ page }) => {
// 记录 API 调用
const apiCalls: string[] = [];
// mock pause API
await page.route('**/api/study-sessions/SESSION_001/study-sessions/pause', (route) => {
apiCalls.push('pause');
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockApiResponse()),
});
});
// mock continue API
await page.route('**/api/study-sessions/SESSION_001/study-sessions/continue', (route) => {
apiCalls.push('continue');
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockApiResponse()),
});
});
// 进入 start-task 页面
await page.goto('/start-task/T001');
await page.waitForSelector('.start-page', { timeout: 10_000 });
// 等待计时器启动
await expect(page.locator('.status-text')).toContainText('进行中');
// 点击暂停按钮
await page.locator('button', { hasText: '暂停' }).click();
// 验证暂停 API 被调用
expect(apiCalls).toContain('pause');
// 验证状态变为已暂停
await expect(page.locator('.status-text')).toContainText('已暂停');
// 点击开始按钮
await page.locator('button', { hasText: '开始' }).click();
// 验证 continue API 被调用
expect(apiCalls).toContain('continue');
// 验证状态恢复为进行中
await expect(page.locator('.status-text')).toContainText('进行中');
});
test('暂停后点击开始,不暂停时开始不应触发 continue API', async ({ page }) => {
const apiCalls: string[] = [];
await page.route('**/api/study-sessions/SESSION_001/study-sessions/pause', (route) => {
apiCalls.push('pause');
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockApiResponse()),
});
});
await page.route('**/api/study-sessions/SESSION_001/study-sessions/continue', (route) => {
apiCalls.push('continue');
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockApiResponse()),
});
});
await page.goto('/start-task/T001');
await page.waitForSelector('.start-page', { timeout: 10_000 });
await expect(page.locator('.status-text')).toContainText('进行中');
// ONGOING 状态下,开始按钮是 disabled 的,不应触发 continue
const startBtn = page.locator('button', { hasText: '开始' });
await expect(startBtn).toBeDisabled();
// continue API 不应被调用
expect(apiCalls).not.toContain('continue');
});
test('暂停后结束会话,应正确调用 ended API 并展示提示', async ({ page }) => {
await page.route('**/api/study-sessions/SESSION_001/study-sessions/pause', (route) =>
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockApiResponse()),
}),
);
await page.route('**/api/study-sessions/SESSION_001/study-sessions/ended', (route) =>
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(mockApiResponse(200, null, '本次有效学习时间不足10分钟,不计入总学习时间')),
}),
);
await page.goto('/start-task/T001');
await page.waitForSelector('.start-page', { timeout: 10_000 });
// 暂停
await page.locator('button', { hasText: '暂停' }).click();
await expect(page.locator('.status-text')).toContainText('已暂停');
// 结束会话
await page.locator('button', { hasText: '结束会话' }).click();
// 在弹窗中输入总结内容
await page.locator('.el-dialog textarea').fill('测试总结');
await page.locator('.el-dialog button', { hasText: '确认结束' }).click();
// 确认第二个弹窗("确定要结束本次学习会话吗?")
const confirmBtn = page.locator('.el-message-box__btns button', { hasText: '确定' });
await confirmBtn.waitFor({ timeout: 5000 });
await confirmBtn.click();
// 应看到 warning 提示(有效时间不足)
await expect(page.locator('.el-message--warning')).toBeVisible({ timeout: 5000 });
});
});