import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { readFileSync } from 'node:fs' import { resolve } from 'node:path' vi.mock('../../../server/models/member.js', () => ({ default: { findOne: vi.fn(), create: vi.fn(), findOneAndUpdate: vi.fn() } })) vi.mock('../../../server/utils/mongoose.js', () => ({ connectDB: vi.fn() })) vi.mock('jsonwebtoken', () => ({ default: { sign: vi.fn().mockReturnValue('mock-token') } })) import Member from '../../../server/models/member.js' import testLoginHandler from '../../../server/api/dev/test-login.get.js' import memberLoginHandler from '../../../server/api/dev/member-login.get.js' import { createMockEvent } from '../helpers/createMockEvent.js' const mockMember = { _id: 'member-123', email: 'test-admin@ghostguild.dev', name: 'Test Admin', circle: 'founder', role: 'admin', status: 'active' } describe('dev endpoints', () => { let originalNodeEnv beforeEach(() => { originalNodeEnv = process.env.NODE_ENV process.env.NODE_ENV = 'development' vi.clearAllMocks() }) afterEach(() => { process.env.NODE_ENV = originalNodeEnv }) // ── Source inspection ────────────────────────────────────────── describe('source inspection', () => { const devDir = resolve(import.meta.dirname, '../../../server/api/dev') it('test-login.get.js first conditional is NODE_ENV production check', () => { const source = readFileSync(resolve(devDir, 'test-login.get.js'), 'utf-8') const handlerBody = source.slice(source.indexOf('defineEventHandler')) const firstIf = handlerBody.match(/if\s*\([\s\S]*?\)\s*\{/)?.[0] expect(firstIf).toContain('process.env.NODE_ENV === "production"') }) it('member-login.get.js first conditional is NODE_ENV production check', () => { const source = readFileSync(resolve(devDir, 'member-login.get.js'), 'utf-8') const handlerBody = source.slice(source.indexOf('defineEventHandler')) const firstIf = handlerBody.match(/if\s*\([\s\S]*?\)\s*\{/)?.[0] expect(firstIf).toContain('process.env.NODE_ENV === "production"') }) }) // ── test-login.get.js ────────────────────────────────────────── describe('test-login.get.js', () => { it('returns 404 in production', async () => { process.env.NODE_ENV = 'production' const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' }) await expect(testLoginHandler(event)).rejects.toMatchObject({ statusCode: 404 }) }) it('creates admin user when none exists', async () => { Member.findOneAndUpdate.mockResolvedValue(mockMember) const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' }) await testLoginHandler(event) expect(Member.findOneAndUpdate).toHaveBeenCalledWith( { email: 'test-admin@ghostguild.dev' }, expect.objectContaining({ $setOnInsert: expect.objectContaining({ role: 'admin', circle: 'founder' }) }), { upsert: true, new: true } ) }) it('uses existing admin when found', async () => { Member.findOneAndUpdate.mockResolvedValue(mockMember) const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' }) await testLoginHandler(event) expect(Member.findOneAndUpdate).toHaveBeenCalledWith( { email: 'test-admin@ghostguild.dev' }, expect.any(Object), { upsert: true, new: true } ) }) it('sets auth cookie', async () => { Member.findOneAndUpdate.mockResolvedValue(mockMember) const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' }) await testLoginHandler(event) const cookieHeader = event._testSetHeaders['set-cookie'] expect(cookieHeader).toBeDefined() expect(cookieHeader).toContain('auth-token=mock-token') }) }) // ── member-login.get.js ──────────────────────────────────────── describe('member-login.get.js', () => { it('returns 404 in production', async () => { process.env.NODE_ENV = 'production' const event = createMockEvent({ method: 'GET', path: '/api/dev/member-login' }) await expect(memberLoginHandler(event)).rejects.toMatchObject({ statusCode: 404 }) }) it('returns 400 when email query param is missing', async () => { const event = createMockEvent({ method: 'GET', path: '/api/dev/member-login' }) await expect(memberLoginHandler(event)).rejects.toMatchObject({ statusCode: 400 }) }) it('returns 404 when member not found', async () => { Member.findOne.mockResolvedValue(null) const event = createMockEvent({ method: 'GET', path: '/api/dev/member-login?email=nobody@example.com' }) await expect(memberLoginHandler(event)).rejects.toMatchObject({ statusCode: 404 }) }) it('sets auth cookie for found member', async () => { const foundMember = { _id: 'member-456', email: 'test@example.com', name: 'Test User', status: 'active' } Member.findOne.mockResolvedValue(foundMember) const event = createMockEvent({ method: 'GET', path: '/api/dev/member-login?email=test@example.com' }) await memberLoginHandler(event) const cookieHeader = event._testSetHeaders['set-cookie'] expect(cookieHeader).toBeDefined() expect(cookieHeader).toContain('auth-token=mock-token') }) }) })