diff --git a/e2e/start-task.spec.ts b/e2e/start-task.spec.ts new file mode 100644 index 0000000..f2ea790 --- /dev/null +++ b/e2e/start-task.spec.ts @@ -0,0 +1,180 @@ +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 }) => { + // 模拟登录 + 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, [])), + }), + ); + }); + + 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(); + + // 应看到 warning 提示(有效时间不足) + await expect(page.locator('.el-message--warning')).toBeVisible({ timeout: 5000 }); + }); +});