166 lines
4.8 KiB
JavaScript
166 lines
4.8 KiB
JavaScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
|
|
const { mockBoardPostExists } = vi.hoisted(() => ({
|
|
mockBoardPostExists: vi.fn()
|
|
}))
|
|
|
|
vi.mock('../../../server/utils/auth.js', () => ({
|
|
requireAuth: vi.fn()
|
|
}))
|
|
|
|
vi.mock('../../../server/utils/mongoose.js', () => ({
|
|
connectDB: vi.fn()
|
|
}))
|
|
|
|
vi.mock('../../../server/models/boardPost.js', () => ({
|
|
default: { exists: mockBoardPostExists }
|
|
}))
|
|
|
|
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()
|
|
mockBoardPostExists.mockResolvedValue(null)
|
|
})
|
|
|
|
// 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: [],
|
|
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,
|
|
hasEngagedBoard: false,
|
|
hasClickedWiki: false,
|
|
},
|
|
completedAt: null,
|
|
})
|
|
})
|
|
|
|
// 1.2: hasProfileTags true when craft tags present
|
|
it('hasProfileTags is true when member has craft tags', async () => {
|
|
requireAuth.mockResolvedValue({
|
|
_id: 'member-1',
|
|
craftTags: ['game-design'],
|
|
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 no craft tags
|
|
it('hasProfileTags is false when member has no craft tags', async () => {
|
|
requireAuth.mockResolvedValue({
|
|
_id: 'member-1',
|
|
craftTags: [],
|
|
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: hasEngagedBoard true when visited AND has a BoardPost
|
|
it('hasEngagedBoard is true when page visited and member has posted', async () => {
|
|
requireAuth.mockResolvedValue({
|
|
_id: 'member-1',
|
|
craftTags: [],
|
|
onboarding: {
|
|
completedAt: null,
|
|
eventPageVisited: false,
|
|
boardPageVisited: true,
|
|
wikiClicked: false,
|
|
},
|
|
})
|
|
mockBoardPostExists.mockResolvedValue({ _id: 'post-1' })
|
|
|
|
const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })
|
|
const result = await handler(event)
|
|
|
|
expect(result.goals.hasEngagedBoard).toBe(true)
|
|
expect(mockBoardPostExists).toHaveBeenCalledWith({ author: 'member-1' })
|
|
})
|
|
|
|
// 1.6: hasEngagedBoard false when visited but no posts
|
|
it('hasEngagedBoard is false when page visited but member has no posts', async () => {
|
|
requireAuth.mockResolvedValue({
|
|
_id: 'member-1',
|
|
craftTags: [],
|
|
onboarding: {
|
|
completedAt: null,
|
|
eventPageVisited: false,
|
|
boardPageVisited: true,
|
|
wikiClicked: false,
|
|
},
|
|
})
|
|
mockBoardPostExists.mockResolvedValue(null)
|
|
|
|
const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })
|
|
const result = await handler(event)
|
|
|
|
expect(result.goals.hasEngagedBoard).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: [],
|
|
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.hasEngagedBoard).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 })
|
|
})
|
|
})
|