112 lines
3.8 KiB
JavaScript
112 lines
3.8 KiB
JavaScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
|
|
vi.mock('../../../server/models/member.js', () => {
|
|
const mockSave = vi.fn().mockResolvedValue(undefined)
|
|
function MockMember(data) {
|
|
Object.assign(this, data)
|
|
this._id = 'new-member-123'
|
|
this.status = data.status || 'pending_payment'
|
|
this.save = mockSave
|
|
}
|
|
MockMember.findOne = vi.fn()
|
|
MockMember.findByIdAndUpdate = vi.fn()
|
|
MockMember._mockSave = mockSave
|
|
return { default: MockMember }
|
|
})
|
|
vi.mock('../../../server/utils/mongoose.js', () => ({ connectDB: vi.fn() }))
|
|
vi.mock('../../../server/utils/validateBody.js', () => ({ validateBody: vi.fn() }))
|
|
vi.mock('../../../server/utils/schemas.js', () => ({ memberCreateSchema: {} }))
|
|
vi.mock('../../../server/utils/slack.ts', () => ({
|
|
getSlackService: vi.fn().mockReturnValue(null)
|
|
}))
|
|
vi.mock('../../../server/utils/resend.js', () => ({
|
|
sendWelcomeEmail: vi.fn().mockResolvedValue(undefined)
|
|
}))
|
|
vi.mock('../../../server/utils/memberNumber.js', () => ({
|
|
assignMemberNumber: vi.fn().mockResolvedValue(1)
|
|
}))
|
|
|
|
import Member from '../../../server/models/member.js'
|
|
import { validateBody } from '../../../server/utils/validateBody.js'
|
|
import { sendWelcomeEmail } from '../../../server/utils/resend.js'
|
|
import createHandler from '../../../server/api/members/create.post.js'
|
|
import { createMockEvent } from '../helpers/createMockEvent.js'
|
|
|
|
describe('members/create.post handler', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
Member.findOne.mockResolvedValue(null)
|
|
Member._mockSave.mockResolvedValue(undefined)
|
|
validateBody.mockResolvedValue({
|
|
email: 'new@example.com',
|
|
name: 'New Member',
|
|
circle: 'community',
|
|
contributionAmount: 0
|
|
})
|
|
})
|
|
|
|
it('validates request body via memberCreateSchema', async () => {
|
|
const event = createMockEvent({ method: 'POST', path: '/api/members/create' })
|
|
|
|
await createHandler(event)
|
|
|
|
expect(validateBody).toHaveBeenCalledOnce()
|
|
expect(validateBody).toHaveBeenCalledWith(event, expect.any(Object))
|
|
})
|
|
|
|
it('rejects duplicate email with 409', async () => {
|
|
Member.findOne.mockResolvedValue({ _id: 'existing-123', email: 'new@example.com' })
|
|
|
|
const event = createMockEvent({ method: 'POST', path: '/api/members/create' })
|
|
|
|
await expect(createHandler(event)).rejects.toMatchObject({
|
|
statusCode: 409,
|
|
statusMessage: 'A member with this email already exists'
|
|
})
|
|
})
|
|
|
|
it('does not expose helcimCustomerId or role in response', async () => {
|
|
validateBody.mockResolvedValue({
|
|
email: 'new@example.com',
|
|
name: 'New Member',
|
|
circle: 'community',
|
|
contributionAmount: 0,
|
|
helcimCustomerId: 'cust-999',
|
|
role: 'admin'
|
|
})
|
|
|
|
const event = createMockEvent({ method: 'POST', path: '/api/members/create' })
|
|
const result = await createHandler(event)
|
|
|
|
expect(result.member).not.toHaveProperty('helcimCustomerId')
|
|
expect(result.member).not.toHaveProperty('role')
|
|
expect(result.success).toBe(true)
|
|
expect(result.member).toEqual({
|
|
id: 'new-member-123',
|
|
email: 'new@example.com',
|
|
name: 'New Member',
|
|
circle: 'community',
|
|
contributionAmount: 0,
|
|
status: 'pending_payment'
|
|
})
|
|
})
|
|
|
|
it('succeeds when Slack service is unavailable', async () => {
|
|
const event = createMockEvent({ method: 'POST', path: '/api/members/create' })
|
|
const result = await createHandler(event)
|
|
|
|
expect(result.success).toBe(true)
|
|
expect(result.member.email).toBe('new@example.com')
|
|
})
|
|
|
|
it('succeeds when welcome email fails', async () => {
|
|
sendWelcomeEmail.mockRejectedValue(new Error('email service down'))
|
|
|
|
const event = createMockEvent({ method: 'POST', path: '/api/members/create' })
|
|
const result = await createHandler(event)
|
|
|
|
expect(result.success).toBe(true)
|
|
expect(result.member.email).toBe('new@example.com')
|
|
expect(sendWelcomeEmail).toHaveBeenCalledOnce()
|
|
})
|
|
})
|