import { beforeEach, describe, expect, it, vi } from 'vitest' const getMock = vi.fn() const postMock = vi.fn() vi.mock('@/lib/http/client', () => ({ get: getMock, post: postMock, })) describe('auth service', () => { beforeEach(() => { getMock.mockReset() postMock.mockReset() postMock.mockResolvedValue(undefined) }) it('loads public auth capabilities without auth headers', async () => { const { getAuthCapabilities } = await import('./auth') await getAuthCapabilities() expect(getMock).toHaveBeenCalledWith('/auth/capabilities', undefined, { auth: false }) }) it('normalizes null oauth provider lists from auth capabilities', async () => { getMock.mockResolvedValue({ password: true, email_activation: false, email_code: false, sms_code: false, password_reset: false, admin_bootstrap_required: undefined, oauth_providers: null, }) const { getAuthCapabilities } = await import('./auth') const result = await getAuthCapabilities() expect(result.admin_bootstrap_required).toBe(false) expect(result.email_activation).toBe(false) expect(result.oauth_providers).toEqual([]) }) it('preserves admin bootstrap status from auth capabilities', async () => { getMock.mockResolvedValue({ password: true, email_activation: true, email_code: false, sms_code: false, password_reset: false, admin_bootstrap_required: true, oauth_providers: [], }) const { getAuthCapabilities } = await import('./auth') const result = await getAuthCapabilities() expect(result.admin_bootstrap_required).toBe(true) expect(result.email_activation).toBe(true) }) it('requests oauth authorization url without auth headers', async () => { const { getOAuthAuthorizationUrl } = await import('./auth') await getOAuthAuthorizationUrl('github', 'https://admin.example.com/login/oauth/callback') expect(getMock).toHaveBeenCalledWith( '/auth/oauth/github', { return_to: 'https://admin.example.com/login/oauth/callback' }, { auth: false }, ) }) it('exchanges oauth handoff code without auth headers', async () => { const { exchangeOAuthHandoff } = await import('./auth') await exchangeOAuthHandoff('handoff-code') expect(postMock).toHaveBeenCalledWith( '/auth/oauth/exchange', { code: 'handoff-code' }, { auth: false, credentials: 'include' }, ) }) it('submits public registration without auth headers', async () => { const { register } = await import('./auth') await register({ username: 'new-user', password: 'SecurePass123!', email: 'new-user@example.com', nickname: 'New User', }) expect(postMock).toHaveBeenCalledWith( '/auth/register', { username: 'new-user', password: 'SecurePass123!', email: 'new-user@example.com', nickname: 'New User', }, { auth: false }, ) }) it('submits first-admin bootstrap without auth headers', async () => { const { bootstrapAdmin } = await import('./auth') await bootstrapAdmin({ username: 'bootstrap_admin', password: 'Bootstrap123!@#', email: 'bootstrap_admin@example.com', nickname: 'Bootstrap Admin', }) expect(postMock).toHaveBeenCalledWith( '/auth/bootstrap-admin', { username: 'bootstrap_admin', password: 'Bootstrap123!@#', email: 'bootstrap_admin@example.com', nickname: 'Bootstrap Admin', }, { auth: false, credentials: 'include' }, ) }) it('activates email accounts without auth headers', async () => { const { activateEmail } = await import('./auth') await activateEmail('activation-token') expect(postMock).toHaveBeenCalledWith( '/auth/activate-email', { token: 'activation-token' }, { auth: false }, ) }) it('resends activation emails without auth headers', async () => { const { resendActivationEmail } = await import('./auth') await resendActivationEmail({ email: 'new-user@example.com' }) expect(postMock).toHaveBeenCalledWith( '/auth/resend-activation', { email: 'new-user@example.com' }, { auth: false }, ) }) it('sends sms purpose instead of the deprecated scene field', async () => { const { sendSmsCode } = await import('./auth') await sendSmsCode({ phone: '13812345678', purpose: 'register', }) expect(postMock).toHaveBeenCalledWith( '/auth/send-code', { phone: '13812345678', purpose: 'register', }, { auth: false }, ) }) it('sends refresh_token when logging out with a persisted session', async () => { const { logout } = await import('./auth') await logout('refresh-token-demo') expect(postMock).toHaveBeenCalledWith( '/auth/logout', { refresh_token: 'refresh-token-demo', }, { credentials: 'include' }, ) }) it('omits the request body when no refresh_token is available', async () => { const { logout } = await import('./auth') await logout() expect(postMock).toHaveBeenCalledWith('/auth/logout', undefined, { credentials: 'include' }) }) it('refreshes the session with credentials even when no body token is supplied', async () => { const { refreshSession } = await import('./auth') await refreshSession() expect(postMock).toHaveBeenCalledWith( '/auth/refresh', undefined, { auth: false, credentials: 'include' }, ) }) })