From 7a550631741a36b51435746c30aa7ed0bec2217d Mon Sep 17 00:00:00 2001 From: cat_shark <1716967236@qq.com> Date: Sat, 30 May 2026 17:38:25 +0800 Subject: [PATCH] =?UTF-8?q?test:=20=E6=96=B0=E5=A2=9E=20StartTask=20?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=20(11=20?= =?UTF-8?q?cases)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 覆盖场景:暂停调用 API 并更新状态、继续调用 continueSession API、 ONGOING 状态不误触发 continue、结束会话 API、多次暂停/继续完整流程 --- src/__tests__/components/StartTask.spec.ts | 276 +++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 src/__tests__/components/StartTask.spec.ts diff --git a/src/__tests__/components/StartTask.spec.ts b/src/__tests__/components/StartTask.spec.ts new file mode 100644 index 0000000..d42c5f3 --- /dev/null +++ b/src/__tests__/components/StartTask.spec.ts @@ -0,0 +1,276 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { ref, reactive } from 'vue' + +// Mock API +vi.mock('@/api/studySessions', () => ({ + continueSession: vi.fn(), + pauseSession: vi.fn(), + endSession: vi.fn(), + startOrContinueStudySession: vi.fn(), + getSessionDetail: vi.fn(), +})) + +vi.mock('@/api/reportFragments', () => ({ + getFragmentsBySession: vi.fn(), + updateFragments: vi.fn(), +})) + +import { + continueSession, + pauseSession, + endSession, + startOrContinueStudySession, +} from '@/api/studySessions' + +const mockedContinueSession = vi.mocked(continueSession) +const mockedPauseSession = vi.mocked(pauseSession) +const mockedEndSession = vi.mocked(endSession) +const mockedStartOrContinue = vi.mocked(startOrContinueStudySession) + +// 模拟 StartTask.vue 中的核心状态和方法 +function createSessionSimulator() { + const taskInfo = reactive({ + sessionNum: 'SESSION_001', + sessionState: 'ONGOING' as string, + taskName: '测试任务', + taskNum: 'T001', + startTime: '', + endTime: '', + lastStartTime: '', + actualTime: 0, + effectiveTime: 0, + effectivenessRatio: '--', + pointerPosition: 1500000, + systemMessage: '', + }) + + const timerRunning = ref(true) + + const clear = () => { + timerRunning.value = false + } + + const runCountdown = (duration: number) => { + timerRunning.value = true + } + + // 从 StartTask.vue 提取的 stopTimer 逻辑 + const stopTimer = async () => { + const res = await pauseSession(taskInfo.sessionNum) + if (res.code === 200) { + taskInfo.sessionState = 'PAUSED' + } + clear() + } + + // 从 StartTask.vue 提取的 startTimer 逻辑 + const startTimer = async () => { + if (taskInfo.sessionState === 'PAUSED') { + const res = await continueSession(taskInfo.sessionNum) + if (res.code === 200) { + // ElMessage.success("任务继续") + } + // loadTaskSession 模拟 + const sessionRes = await startOrContinueStudySession(taskInfo.taskNum) + Object.assign(taskInfo, sessionRes.data) + } + const duration = taskInfo.pointerPosition || 25 * 60 * 1000 + runCountdown(duration) + } + + // 从 StartTask.vue 提取的 endTimer 逻辑(简化版,跳过 confirm) + const endTimer = async (content: string) => { + if (!content) return + const res = await endSession(taskInfo.sessionNum, content) + if (res.code === 200) { + if (res.message && res.message !== '请求成功') { + // ElMessage.warning(res.message) + } + } + clear() + } + + return { taskInfo, timerRunning, stopTimer, startTimer, endTimer, clear } +} + +describe('StartTask.vue 暂停/继续逻辑', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + describe('stopTimer - 暂停', () => { + it('调用 pauseSession API', async () => { + mockedPauseSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + const { stopTimer } = createSessionSimulator() + + await stopTimer() + + expect(mockedPauseSession).toHaveBeenCalledWith('SESSION_001') + }) + + it('暂停成功后 sessionState 应更新为 PAUSED', async () => { + mockedPauseSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + const { taskInfo, stopTimer } = createSessionSimulator() + + expect(taskInfo.sessionState).toBe('ONGOING') + await stopTimer() + expect(taskInfo.sessionState).toBe('PAUSED') + }) + + it('暂停后 timerRunning 应为 false', async () => { + mockedPauseSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + const { timerRunning, stopTimer } = createSessionSimulator() + + expect(timerRunning.value).toBe(true) + await stopTimer() + expect(timerRunning.value).toBe(false) + }) + }) + + describe('startTimer - 继续', () => { + it('PAUSED 状态下点击开始,应调用 continueSession API', async () => { + mockedPauseSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + mockedContinueSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + mockedStartOrContinue.mockResolvedValue({ + code: 200, + data: { + sessionNum: 'SESSION_001', + sessionState: 'ONGOING', + pointerPosition: 1500000, + }, + } as any) + + const { taskInfo, stopTimer, startTimer } = createSessionSimulator() + + // 先暂停 + await stopTimer() + expect(taskInfo.sessionState).toBe('PAUSED') + + // 再开始 + await startTimer() + + expect(mockedContinueSession).toHaveBeenCalledWith('SESSION_001') + }) + + it('PAUSED 状态下点击开始,应调用 loadTaskSession 刷新数据', async () => { + mockedPauseSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + mockedContinueSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + mockedStartOrContinue.mockResolvedValue({ + code: 200, + data: { + sessionNum: 'SESSION_001', + sessionState: 'ONGOING', + pointerPosition: 1200000, + }, + } as any) + + const { taskInfo, stopTimer, startTimer } = createSessionSimulator() + + await stopTimer() + await startTimer() + + expect(mockedStartOrContinue).toHaveBeenCalledWith('T001') + expect(taskInfo.sessionState).toBe('ONGOING') + }) + + it('ONGOING 状态下点击开始,不应调用 continueSession API', async () => { + mockedStartOrContinue.mockResolvedValue({ + code: 200, + data: { sessionState: 'ONGOING', pointerPosition: 1500000 }, + } as any) + + const { taskInfo, startTimer } = createSessionSimulator() + + // 直接在 ONGOING 状态调用 startTimer + expect(taskInfo.sessionState).toBe('ONGOING') + await startTimer() + + expect(mockedContinueSession).not.toHaveBeenCalled() + }) + + it('开始后 timerRunning 应为 true', async () => { + mockedPauseSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + mockedContinueSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + mockedStartOrContinue.mockResolvedValue({ + code: 200, + data: { sessionState: 'ONGOING', pointerPosition: 1500000 }, + } as any) + + const { timerRunning, stopTimer, startTimer } = createSessionSimulator() + + await stopTimer() + expect(timerRunning.value).toBe(false) + + await startTimer() + expect(timerRunning.value).toBe(true) + }) + }) + + describe('endTimer - 结束会话', () => { + it('调用 endSession API 并传递 content', async () => { + mockedEndSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + const { endTimer } = createSessionSimulator() + + await endTimer('学习总结内容') + + expect(mockedEndSession).toHaveBeenCalledWith('SESSION_001', '学习总结内容') + }) + + it('后端返回 warning 消息时,message 应包含提示信息', async () => { + mockedEndSession.mockResolvedValue({ + code: 200, + message: '本次有效学习时间不足10分钟,不计入总学习时间', + } as any) + + const { endTimer } = createSessionSimulator() + const res = await endSession('SESSION_001', '内容') + + expect(res.message).toBe('本次有效学习时间不足10分钟,不计入总学习时间') + expect(res.message).not.toBe('请求成功') + }) + + it('content 为空时不调用 API', async () => { + const { endTimer } = createSessionSimulator() + + await endTimer('') + + expect(mockedEndSession).not.toHaveBeenCalled() + }) + }) + + describe('完整暂停→继续→暂停流程', () => { + it('多次暂停/继续应正确更新状态和调用 API', async () => { + mockedPauseSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + mockedContinueSession.mockResolvedValue({ code: 200, message: '请求成功' } as any) + mockedStartOrContinue.mockResolvedValue({ + code: 200, + data: { sessionState: 'ONGOING', pointerPosition: 1500000 }, + } as any) + + const { taskInfo, stopTimer, startTimer } = createSessionSimulator() + + // 初始状态 + expect(taskInfo.sessionState).toBe('ONGOING') + + // 第一次暂停 + await stopTimer() + expect(taskInfo.sessionState).toBe('PAUSED') + expect(mockedPauseSession).toHaveBeenCalledTimes(1) + + // 继续 + await startTimer() + expect(taskInfo.sessionState).toBe('ONGOING') + expect(mockedContinueSession).toHaveBeenCalledTimes(1) + + // 第二次暂停 + await stopTimer() + expect(taskInfo.sessionState).toBe('PAUSED') + expect(mockedPauseSession).toHaveBeenCalledTimes(2) + + // 再次继续 + await startTimer() + expect(taskInfo.sessionState).toBe('ONGOING') + expect(mockedContinueSession).toHaveBeenCalledTimes(2) + }) + }) +})