diff --git a/docs/gamification-server-plan.md b/docs/gamification-server-plan.md index b2c4bfd..cd0f687 100644 --- a/docs/gamification-server-plan.md +++ b/docs/gamification-server-plan.md @@ -59,13 +59,14 @@ | G2-4 | 将连续学习改为按挑战组完成计算 | [x] | 每天至少完成 1 组挑战才更新 streak,不再依赖当天正确题数阈值 | | G2-5 | 实现连续学习里程碑奖励 | [x] | 3/7/14/30/100 天奖励可发放且不可重复领取 | | G2-6 | 实现每日首次进入送红心 | [x] | 每日首次 bootstrap 或专用 check-in 最多补 1 颗,不超过上限 | -| G2-7 | 添加 XP/streak 测试 | [ ] | 覆盖等级边界、首次知识卡、完成组奖励、全对奖励、看解析奖励、连续学习保护 | +| G2-7 | 添加 XP/streak 测试 | [x] | 覆盖等级边界、首次知识卡、完成组奖励、全对奖励、看解析奖励、连续学习保护 | 验证记录(2026-05-13):G2-2 已通过 `./node_modules/.bin/tsc --noEmit` 和 `./node_modules/.bin/eslint .`;`bun` 当前 shell 不在 PATH,`./node_modules/.bin/vitest run` 启动阶段被 macOS 拒绝加载未签名的 `@rolldown/binding-darwin-x64` 原生 binding,需修复本地依赖安装或签名后复跑。 验证记录(2026-05-13):G2-3 已通过 `./node_modules/.bin/tsc --noEmit` 和 `./node_modules/.bin/eslint .`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/progress/xp-service.test.ts src/__tests__/services/learning/challenge-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 签名问题阻塞。 验证记录(2026-05-13):G2-4 已通过 `./node_modules/.bin/tsc --noEmit` 和 `./node_modules/.bin/eslint .`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/progress/streak-service.test.ts src/__tests__/services/learning/challenge-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 签名问题阻塞。 验证记录(2026-05-13):G2-5 已通过 `./node_modules/.bin/tsc --noEmit` 和 `./node_modules/.bin/eslint .`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/progress/streak-service.test.ts src/__tests__/services/learning/challenge-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 签名问题阻塞。 验证记录(2026-05-13):G2-6 已通过 `./node_modules/.bin/tsc --noEmit` 和 `./node_modules/.bin/eslint .`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/learning/progress-summary-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 签名问题阻塞。 +验证记录(2026-05-13):G2-7 已通过 `./node_modules/.bin/tsc --noEmit` 和 `./node_modules/.bin/eslint .`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/progress/xp-service.test.ts src/__tests__/services/progress/streak-service.test.ts src/__tests__/services/learning/challenge-service.test.ts src/__tests__/services/learning/progress-summary-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 签名问题阻塞。 ## Phase G3:金币、商店和道具 diff --git a/src/__tests__/services/progress/streak-service.test.ts b/src/__tests__/services/progress/streak-service.test.ts index b42b5fe..acc58e0 100644 --- a/src/__tests__/services/progress/streak-service.test.ts +++ b/src/__tests__/services/progress/streak-service.test.ts @@ -1,6 +1,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { db } from '../../../db/client.js'; import { + freezeStreak, getStreakMilestoneReward, grantStreakMilestoneReward, updateStreakForCompletedChallenge, @@ -143,4 +144,22 @@ describe('Streak service — completed challenge updates', () => { expect(rewards).toEqual([]); expect(db.insert).not.toHaveBeenCalled(); }); + + it('freezes streak protection for today without incrementing streak days', async () => { + selectQueue([ + [{ streakDays: 12 }], + ]); + const update = mockUpdate(); + + const result = await freezeStreak('user-1'); + + expect(result).toEqual({ + days: 12, + lastDate: new Date().toISOString().slice(0, 10), + frozen: true, + }); + expect(update.set).toHaveBeenCalledWith(expect.objectContaining({ + streakLastDate: expect.any(Object), + })); + }); }); diff --git a/src/__tests__/services/progress/xp-service.test.ts b/src/__tests__/services/progress/xp-service.test.ts index faa30f9..5f8758e 100644 --- a/src/__tests__/services/progress/xp-service.test.ts +++ b/src/__tests__/services/progress/xp-service.test.ts @@ -90,6 +90,12 @@ describe('XP service', () => { amount: 15, title: '首次知识卡 +15 XP', }); + expect(createXpReward('review_explanation')).toEqual({ + type: 'xp', + source: 'review_explanation', + amount: 3, + title: '查看解析 +3 XP', + }); }); }); });