Task 9 of the slice plan. Computes the data behind the Inbox ContinuityBadge and recovery toast (Strategy §5): - KST Mon-Sun grouping via toKstDateKey/kstMondayOf helpers (UTC + 9h shift, then bucket to local Monday). - weekCount + weekTarget=7 + consecutiveCompleteWeeks (walk backward from current week, or previous if current incomplete, counting only weeks with >=7 notes). - showRecoveryToast=true when the latest note lands on today (KST) and the prior note is at least 7 days earlier — this is the "흐름을 다시 이어갑니다" trigger. - now() injected for deterministic tests. Verification: `npx vitest run tests/unit/ContinuityService.test.ts` 6 passed. All 24 unit tests across migrations / NoteRepository / MediaStore / ContinuityService green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
92 lines
3.4 KiB
TypeScript
92 lines
3.4 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import Database from 'better-sqlite3';
|
|
import { runMigrations } from '@main/db/migrations/index.js';
|
|
import { ContinuityService } from '@main/services/ContinuityService.js';
|
|
|
|
function dbWithDates(isoDates: string[]): Database.Database {
|
|
const db = new Database(':memory:');
|
|
runMigrations(db);
|
|
const insert = db.prepare(
|
|
`INSERT INTO notes (id, raw_text, ai_status, created_at, updated_at)
|
|
VALUES (?, ?, 'pending', ?, ?)`
|
|
);
|
|
for (const [i, d] of isoDates.entries()) insert.run(`n${i}`, 'x', d, d);
|
|
return db;
|
|
}
|
|
|
|
describe('ContinuityService', () => {
|
|
it('empty db returns zero counts and no recovery toast', () => {
|
|
const db = new Database(':memory:');
|
|
runMigrations(db);
|
|
const svc = new ContinuityService(db, () => new Date('2026-04-25T10:00:00+09:00'));
|
|
const r = svc.get();
|
|
expect(r.weekCount).toBe(0);
|
|
expect(r.weekTarget).toBe(7);
|
|
expect(r.consecutiveCompleteWeeks).toBe(0);
|
|
expect(r.showRecoveryToast).toBe(false);
|
|
expect(r.lastNoteAt).toBeNull();
|
|
});
|
|
|
|
it('counts notes in current KST week (월~일)', () => {
|
|
const db = dbWithDates([
|
|
'2026-04-20T01:00:00+09:00',
|
|
'2026-04-22T03:00:00+09:00',
|
|
'2026-04-25T22:00:00+09:00'
|
|
]);
|
|
const svc = new ContinuityService(db, () => new Date('2026-04-25T23:00:00+09:00'));
|
|
const r = svc.get();
|
|
expect(r.weekStart).toBe('2026-04-20');
|
|
expect(r.weekCount).toBe(3);
|
|
});
|
|
|
|
function isoKst(year: number, month: number, day: number, hour = 10): string {
|
|
const mm = String(month).padStart(2, '0');
|
|
const dd = String(day).padStart(2, '0');
|
|
const hh = String(hour).padStart(2, '0');
|
|
return `${year}-${mm}-${dd}T${hh}:00:00+09:00`;
|
|
}
|
|
|
|
it('consecutiveCompleteWeeks counts weeks with >=7 notes ending immediately before current week', () => {
|
|
const dates: string[] = [];
|
|
for (let d = 6; d <= 12; d++) dates.push(isoKst(2026, 4, d));
|
|
for (let d = 13; d <= 19; d++) dates.push(isoKst(2026, 4, d));
|
|
dates.push(isoKst(2026, 4, 20));
|
|
dates.push(isoKst(2026, 4, 21));
|
|
const db = dbWithDates(dates);
|
|
const svc = new ContinuityService(db, () => new Date('2026-04-25T12:00:00+09:00'));
|
|
const r = svc.get();
|
|
expect(r.consecutiveCompleteWeeks).toBe(2);
|
|
expect(r.weekCount).toBe(2);
|
|
});
|
|
|
|
it('consecutiveCompleteWeeks includes current week if it already hit 7', () => {
|
|
const dates: string[] = [];
|
|
for (let d = 13; d <= 19; d++) dates.push(isoKst(2026, 4, d));
|
|
for (let d = 20; d <= 26; d++) dates.push(isoKst(2026, 4, d));
|
|
const db = dbWithDates(dates);
|
|
const svc = new ContinuityService(db, () => new Date('2026-04-26T23:00:00+09:00'));
|
|
const r = svc.get();
|
|
expect(r.weekCount).toBe(7);
|
|
expect(r.consecutiveCompleteWeeks).toBe(2);
|
|
});
|
|
|
|
it('showRecoveryToast=true when last note is >=7 days ago AND a fresh note exists today', () => {
|
|
const dates = [
|
|
'2026-04-15T10:00:00+09:00',
|
|
'2026-04-25T11:00:00+09:00'
|
|
];
|
|
const db = dbWithDates(dates);
|
|
const svc = new ContinuityService(db, () => new Date('2026-04-25T12:00:00+09:00'));
|
|
expect(svc.get().showRecoveryToast).toBe(true);
|
|
});
|
|
|
|
it('showRecoveryToast=false when there are notes within last 7 days', () => {
|
|
const db = dbWithDates([
|
|
'2026-04-22T10:00:00+09:00',
|
|
'2026-04-25T11:00:00+09:00'
|
|
]);
|
|
const svc = new ContinuityService(db, () => new Date('2026-04-25T12:00:00+09:00'));
|
|
expect(svc.get().showRecoveryToast).toBe(false);
|
|
});
|
|
});
|