Files
bilin/tests/main/achievement.test.ts
bing d4122c8f95 feat: ship v0.9.0 with pomodoro, achievements, and injection history
Add pomodoro timer with goal notifications, writing streak milestones, and knowledge injection logging with UI previews across AI writing flows.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 19:15:52 +08:00

92 lines
3.3 KiB
TypeScript

import { describe, it, expect, afterEach, vi } from 'vitest'
vi.mock('electron', () => ({
BrowserWindow: {
getAllWindows: () => []
},
Notification: {
isSupported: () => false
}
}))
import { mkdtempSync, rmSync } from 'fs'
import { join } from 'path'
import { tmpdir } from 'os'
import { WritingLogRepository } from '../../src/main/db/repositories/writing-log.repo'
import { WritingMilestoneRepository } from '../../src/main/db/repositories/writing-milestone.repo'
import { GlobalSettingsService } from '../../src/main/services/global-settings'
import { WritingLogService } from '../../src/main/services/writing-log.service'
import { GoalNotificationService } from '../../src/main/services/goal-notification.service'
import { AchievementService } from '../../src/main/services/achievement.service'
import { addDays, localDateString } from '../../src/main/services/writing-date.util'
describe('WritingMilestoneRepository', () => {
let userDir: string
let repo: WritingLogRepository
let milestoneRepo: WritingMilestoneRepository
afterEach(() => {
repo?.close()
if (userDir) rmSync(userDir, { recursive: true, force: true })
})
it('UT-ACH-01: unlock streak_7 once', () => {
userDir = mkdtempSync(join(tmpdir(), 'bilin-ach-'))
repo = new WritingLogRepository(userDir)
milestoneRepo = new WritingMilestoneRepository(repo.getDb())
milestoneRepo.unlock('b1', 'streak_7')
expect(milestoneRepo.has('b1', 'streak_7')).toBe(true)
expect(milestoneRepo.unlock('b1', 'streak_7')).toBeNull()
})
})
describe('AchievementService', () => {
let userDir: string
let settingsDir: string
let settings: GlobalSettingsService
let writingRepo: WritingLogRepository
let writingLogs: WritingLogService
let milestoneRepo: WritingMilestoneRepository
let notify: GoalNotificationService
let achievement: AchievementService
afterEach(() => {
writingRepo?.close()
if (userDir) rmSync(userDir, { recursive: true, force: true })
if (settingsDir) rmSync(settingsDir, { recursive: true, force: true })
})
function setup(goal = 100): void {
userDir = mkdtempSync(join(tmpdir(), 'bilin-ach-svc-'))
settingsDir = mkdtempSync(join(tmpdir(), 'bilin-ach-settings-'))
settings = new GlobalSettingsService(settingsDir)
settings.update({
...settings.get(),
dailyWordGoal: goal,
enableGoalNotifications: false
})
writingRepo = new WritingLogRepository(userDir)
writingLogs = new WritingLogService(writingRepo, settings)
milestoneRepo = new WritingMilestoneRepository(writingRepo.getDb())
notify = new GoalNotificationService(settings)
achievement = new AchievementService(milestoneRepo, writingLogs, settings, notify)
writingLogs.setGoalHooks(achievement, notify)
}
it('UT-ACH-02: streakDays=7 unlocks milestone and notifies once', () => {
setup(100)
const bookId = 'book-1'
const today = localDateString()
for (let i = 1; i <= 6; i++) {
writingRepo.addToday(bookId, 150, addDays(today, -i))
}
writingRepo.addToday(bookId, 120, today)
vi.spyOn(notify, 'notifyMilestone')
writingLogs.addToday(bookId, 1)
expect(milestoneRepo.has(bookId, 'streak_7')).toBe(true)
expect(notify.notifyMilestone).toHaveBeenCalledTimes(1)
writingLogs.addToday(bookId, 1)
expect(notify.notifyMilestone).toHaveBeenCalledTimes(1)
})
})