aboutsummaryrefslogtreecommitdiff
path: root/src/lib/server/services/routines.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/server/services/routines.test.ts')
-rw-r--r--src/lib/server/services/routines.test.ts93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/lib/server/services/routines.test.ts b/src/lib/server/services/routines.test.ts
new file mode 100644
index 0000000..9e1f429
--- /dev/null
+++ b/src/lib/server/services/routines.test.ts
@@ -0,0 +1,93 @@
+import { describe, it, expect, beforeEach } from 'vitest';
+import { createTestDb } from '$lib/server/db/test-helper';
+import { add as addProject } from './projects';
+import {
+ add,
+ edit,
+ archive,
+ complete,
+ loadAllVersions,
+ loadProjectDashboard,
+ loadOverview,
+} from './routines';
+
+const DAY_MS = 24 * 60 * 60 * 1000;
+
+describe('routines service', () => {
+ let db: Awaited<ReturnType<typeof createTestDb>>['db'];
+ let projectId: number;
+
+ beforeEach(async () => {
+ const testDb = await createTestDb();
+ db = testDb.db;
+ const project = await addProject('Household', db);
+ projectId = project.id;
+ });
+
+ it('creates a routine with version 1', async () => {
+ const r = await add(projectId, 'clean kitchen', 7, db);
+ expect(r.id).toBe(1);
+ expect(r.version).toBe(1);
+ expect(r.frequencyDays).toBe(7);
+ });
+
+ it('edit inserts a new snapshot version and keeps history', async () => {
+ const r = await add(projectId, 'clean kitchen', 7, db);
+ const updated = await edit(r.id, 'clean kitchen deeply', 3, db);
+ expect(updated.version).toBe(2);
+ expect(updated.frequencyDays).toBe(3);
+
+ const versions = await loadAllVersions(r.id, db);
+ expect(versions).toHaveLength(2);
+ expect(versions[0].frequencyDays).toBe(7);
+ expect(versions[1].frequencyDays).toBe(3);
+ });
+
+ it('archive inserts an archived snapshot without removing history', async () => {
+ const r = await add(projectId, 'clean kitchen', 7, db);
+ await archive(r.id, db);
+ const versions = await loadAllVersions(r.id, db);
+ expect(versions).toHaveLength(2);
+ expect(versions[0].archived).toBe(false);
+ expect(versions[1].archived).toBe(true);
+
+ const dashboard = await loadProjectDashboard(projectId, Date.now(), db);
+ expect(dashboard.routines).toHaveLength(0);
+ expect(dashboard.healthScore).toBe(100);
+ });
+
+ it('complete records the snapshot version it was made against', async () => {
+ const r = await add(projectId, 'clean kitchen', 7, db);
+ await edit(r.id, 'clean kitchen', 5, db);
+ const doneAt = new Date().toISOString();
+ const completion = await complete(r.id, 'with vinegar', doneAt, db);
+ expect(completion.routineVersion).toBe(2);
+ expect(completion.note).toBe('with vinegar');
+ });
+
+ it('dashboard computes urgency and health from completions', async () => {
+ const r = await add(projectId, 'clean kitchen', 7, db);
+ const createdAt = Date.parse(r.createdAt);
+ await complete(r.id, null, new Date(createdAt).toISOString(), db);
+
+ // 15 days after completion with a 7-day routine => very late
+ const now = createdAt + 15 * DAY_MS;
+ const dashboard = await loadProjectDashboard(projectId, now, db);
+ expect(dashboard.routines).toHaveLength(1);
+ expect(dashboard.routines[0].status).toBe('veryLate');
+ expect(dashboard.healthScore).toBe(0);
+ });
+
+ it('overview aggregates per-project health and a global score', async () => {
+ await add(projectId, 'clean kitchen', 7, db);
+ const growth = await addProject('Personal growth', db);
+ await add(growth.id, 'read 30 minutes', 1, db);
+
+ const now = Date.now();
+ const overview = await loadOverview(now, db);
+ expect(overview.projects).toHaveLength(2);
+ expect(overview.globalScore).toBe(
+ Math.round(overview.projects.reduce((s, p) => s + p.healthScore, 0) / 2),
+ );
+ });
+});