Files
memind/health-baseline-job.test.mjs
T
john 2baf29b3ae feat(health): complete P0 health channel — baseline engine, page-data, MindSpace UI
Deliver encrypted health zone, observation API, baseline maturity pipeline,
page-data bindings, and H5/WeChat channel integration for health P0.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 18:04:57 +08:00

107 lines
3.7 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { createInMemoryHealthObservationStore } from './health-observation-store.mjs';
import { createInMemoryHealthBaselineStore } from './health-baseline-store.mjs';
import { createInMemoryHealthEventStore } from './health-event-store.mjs';
import { recomputeUserHealthBaselines, runHealthBaselineJob } from './health-baseline-job.mjs';
function seedMorningBp(userId, store, { count, startValue = 120, step = 0, now = Date.now() } = {}) {
const rows = [];
for (let i = 0; i < count; i += 1) {
rows.push({
confirmed: true,
observedAt: now - i * 24 * 60 * 60 * 1000,
metricType: 'bp_systolic',
valueNum: startValue + i * step,
context: 'morning',
source: 'manual',
qualityFlag: 'ok',
});
}
return Promise.all(rows.map((row) => store.insert(userId, row)));
}
test('recomputeUserHealthBaselines persists rolling baselines', async () => {
const userId = 'baseline-job-user';
const observationStore = createInMemoryHealthObservationStore();
const baselineStore = createInMemoryHealthBaselineStore();
const eventStore = createInMemoryHealthEventStore();
const now = Date.parse('2026-09-02T08:00:00+08:00');
await seedMorningBp(userId, observationStore, { count: 10, now });
const result = await recomputeUserHealthBaselines(userId, {
observationStore,
baselineStore,
eventStore,
now,
});
assert.equal(result.ok, true);
assert.equal(result.skipped, false);
assert.ok(result.baselineCount >= 24);
const persisted = await baselineStore.list(userId);
const target = persisted.find(
(row) => row.metricType === 'bp_systolic' && row.context === 'morning' && row.windowDays === 30,
);
assert.ok(target);
assert.equal(target.sampleCount, 10);
assert.equal(target.maturity, 'weak');
});
test('runHealthBaselineJob dedups open events on repeat runs', async () => {
const userId = 'baseline-job-events';
const observationStore = createInMemoryHealthObservationStore();
const baselineStore = createInMemoryHealthBaselineStore();
const eventStore = createInMemoryHealthEventStore();
const notifications = [];
const eventNotificationService = {
notifyNewEvent: async (_userId, event, { eventId }) => {
notifications.push({ eventId, severity: event.severity });
return { webCreated: event.severity !== 'info', wechatSent: false };
},
};
const now = Date.parse('2026-09-02T08:00:00+08:00');
await seedMorningBp(userId, observationStore, { count: 1, startValue: 190, now });
const first = await runHealthBaselineJob({
userIds: [userId],
observationStore,
baselineStore,
eventStore,
eventNotificationService,
now,
env: { MEMIND_HEALTH_ENABLED: '1' },
});
assert.ok(first.newEvents >= 1);
assert.ok(first.notificationsSent >= 1);
assert.equal(notifications.length, first.newEvents);
const second = await runHealthBaselineJob({
userIds: [userId],
observationStore,
baselineStore,
eventStore,
eventNotificationService,
now,
env: { MEMIND_HEALTH_ENABLED: '1' },
});
assert.equal(second.newEvents, 0);
assert.equal(second.notificationsSent, 0);
assert.equal(notifications.length, first.newEvents);
const openEvents = await eventStore.list(userId);
assert.equal(openEvents.length, first.newEvents);
});
test('runHealthBaselineJob skips when health feature is disabled', async () => {
const result = await runHealthBaselineJob({
userIds: ['u1'],
observationStore: createInMemoryHealthObservationStore(),
baselineStore: createInMemoryHealthBaselineStore(),
env: { MEMIND_HEALTH_ENABLED: '0' },
});
assert.equal(result.skipped, true);
assert.equal(result.reason, 'health_disabled');
});