import { test } from 'node:test' import assert from 'node:assert/strict' import { state } from '../server/state.js' import { hasStudyAccess, isStudyUserCompleted, getAccessibleStudySlugs, markStudyCompletedIfDone, scheduleReengagementEmails, } from '../server/study-helpers.js' function setup() { state.cachedSiteContent = { studies: [{ slug: 'mini', sections: [{ id: 'a' }, { id: 'b' }] }, { slug: 'other', sections: [{ id: 'x' }] }], } } test('completing every lesson marks the study completed and keeps access after leaving', () => { setup() const user = { id: 'u1', enrolledStudySlugs: ['mini'] } assert.equal(markStudyCompletedIfDone(user, 'mini', ['a']), false) assert.equal(markStudyCompletedIfDone(user, 'mini', ['a', 'b']), true) assert.ok(isStudyUserCompleted(user, 'mini')) user.enrolledStudySlugs = [] // student leaves assert.ok(hasStudyAccess(user, 'mini')) assert.ok(!hasStudyAccess(user, 'other')) assert.deepEqual(getAccessibleStudySlugs(user), ['mini']) }) test('completion is sticky when a lesson is added later, and not marked twice', () => { setup() const user = { id: 'u2', enrolledStudySlugs: ['mini'] } markStudyCompletedIfDone(user, 'mini', ['a', 'b']) state.cachedSiteContent.studies[0].sections.push({ id: 'c' }) assert.equal(markStudyCompletedIfDone(user, 'mini', ['a', 'b']), false) assert.ok(isStudyUserCompleted(user, 'mini')) assert.deepEqual(user.completedStudySlugs, ['mini']) }) test('unknown or empty studies are never marked completed', () => { setup() const user = { id: 'u3', enrolledStudySlugs: [] } assert.equal(markStudyCompletedIfDone(user, 'nope', ['a']), false) state.cachedSiteContent.studies.push({ slug: 'empty', sections: [] }) assert.equal(markStudyCompletedIfDone(user, 'empty', []), false) }) test('re-engagement emails skip students whose only study is finished', async () => { setup() const sent = [] state.studyUsers = [{ id: 'u4', username: 'a@b.co', studyRemindersEnabled: true, lastLoginAt: new Date(Date.now() - 40 * 864e5).toISOString(), enrolledStudySlugs: ['mini'], completedStudySlugs: ['mini'], reengagementSentAt: {}, }, { id: 'u5', username: 'c@d.co', studyRemindersEnabled: true, lastLoginAt: new Date(Date.now() - 40 * 864e5).toISOString(), enrolledStudySlugs: ['mini'], reengagementSentAt: {}, }] await scheduleReengagementEmails(async (email) => { sent.push(email) }) assert.deepEqual(sent, ['c@d.co']) }) test('discussion is open only for active studies', async () => { const { isStudyDiscussionOpen } = await import('../server/study-helpers.js') const past = '2020-01-01T00:00:00Z' const future = '2099-01-01T00:00:00Z' state.cachedSiteContent = { studies: [ { slug: 'live', status: 'active', sections: [{ id: 'a', releasedAt: past }, { id: 'b', releasedAt: future }] }, { slug: 'done', status: 'complete', sections: [{ id: 'a', releasedAt: past }] }, { slug: 'auto-done', sections: [{ id: 'a', releasedAt: past }] }, // every lesson released => complete { slug: 'soon', status: 'planned', sections: [] }, ], } assert.equal(isStudyDiscussionOpen('live'), true) assert.equal(isStudyDiscussionOpen('done'), false) assert.equal(isStudyDiscussionOpen('auto-done'), false) assert.equal(isStudyDiscussionOpen('soon'), false) assert.equal(isStudyDiscussionOpen('missing'), false) })