import { describe, it, expect, vi, beforeEach } from 'vitest' vi.mock('../../../server/utils/auth.js', () => ({ requireAuth: vi.fn() })) vi.mock('../../../server/utils/mongoose.js', () => ({ connectDB: vi.fn() })) import { requireAuth } from '../../../server/utils/auth.js' import handler from '../../../server/api/onboarding/status.get.js' import { createMockEvent } from '../helpers/createMockEvent.js' describe('GET /api/onboarding/status', () => { beforeEach(() => { vi.clearAllMocks() }) // 1.1: Default state for new member — all false, completedAt null it('returns all goals false for a new member with no data', async () => { requireAuth.mockResolvedValue({ _id: 'member-1', craftTags: [], board: { topics: [] }, onboarding: { completedAt: null, eventPageVisited: false, boardPageVisited: false, wikiClicked: false, }, }) const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' }) const result = await handler(event) expect(result).toEqual({ goals: { hasProfileTags: false, hasVisitedEvent: false, hasEngagedEcology: false, hasClickedWiki: false, }, completedAt: null, }) }) // 1.2: hasProfileTags true when both tag types present it('hasProfileTags is true when member has both craft tags and ecology topics', async () => { requireAuth.mockResolvedValue({ _id: 'member-1', craftTags: ['game-design'], board: { topics: [{ tagSlug: 'governance', state: 'interested' }], }, onboarding: { completedAt: null, eventPageVisited: false, boardPageVisited: false, wikiClicked: false, }, }) const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' }) const result = await handler(event) expect(result.goals.hasProfileTags).toBe(true) }) // 1.3: hasProfileTags false when only craft tags it('hasProfileTags is false when member has craft tags but no ecology topics', async () => { requireAuth.mockResolvedValue({ _id: 'member-1', craftTags: ['game-design'], board: { topics: [] }, onboarding: { completedAt: null, eventPageVisited: false, boardPageVisited: false, wikiClicked: false, }, }) const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' }) const result = await handler(event) expect(result.goals.hasProfileTags).toBe(false) }) // 1.5: hasEngagedEcology true when visited AND has tag with engagement state it('hasEngagedEcology is true when page visited and has engaged topic', async () => { requireAuth.mockResolvedValue({ _id: 'member-1', craftTags: [], board: { topics: [{ tagSlug: 'governance', state: 'help' }], }, onboarding: { completedAt: null, eventPageVisited: false, boardPageVisited: true, wikiClicked: false, }, }) const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' }) const result = await handler(event) expect(result.goals.hasEngagedEcology).toBe(true) }) // 1.6: hasEngagedEcology false when visited but no engagement state it('hasEngagedEcology is false when page visited but no topics have engagement state', async () => { requireAuth.mockResolvedValue({ _id: 'member-1', craftTags: [], board: { topics: [] }, onboarding: { completedAt: null, eventPageVisited: false, boardPageVisited: true, wikiClicked: false, }, }) const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' }) const result = await handler(event) expect(result.goals.hasEngagedEcology).toBe(false) }) // 1.9: Maps stored booleans directly it('maps stored onboarding booleans directly for visit and wiki goals', async () => { requireAuth.mockResolvedValue({ _id: 'member-1', craftTags: [], board: { topics: [] }, onboarding: { completedAt: null, eventPageVisited: true, boardPageVisited: false, wikiClicked: true, }, }) const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' }) const result = await handler(event) expect(result.goals.hasVisitedEvent).toBe(true) expect(result.goals.hasEngagedEcology).toBe(false) expect(result.goals.hasClickedWiki).toBe(true) }) // 1.11: Requires auth (401) it('returns 401 when not authenticated', async () => { requireAuth.mockRejectedValue( createError({ statusCode: 401, statusMessage: 'Authentication required' }) ) const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' }) await expect(handler(event)).rejects.toMatchObject({ statusCode: 401 }) }) })