import { beforeEach, describe, expect, it, vi } from 'vitest' import { fetchCurrentAuth, loginAuth, logoutAuth } from '@/services/authService' const jsonHeaders = { headers: { get: (name: string) => (name.toLowerCase() === 'content-type' ? 'application/json' : null), }, } function mockJsonResponse(payload: unknown, status = 200): Response { return { ok: status >= 200 && status < 300, status, json: async () => payload, text: async () => JSON.stringify(payload), ...jsonHeaders, } as Response } function createAuthPayload() { return { access_token: 'session-token', token_type: 'Bearer', expires_at: '2026-07-09T12:00:00Z', user: { id: '1900000000000000001', username: 'admin', display_name: '系统管理员', super_admin: true, }, default_hotel_id: 'HOTEL-TEST', hotels: [ { hotel_id: 'HOTEL-TEST', hotel_name: '测试酒店', time_zone: 'Asia/Bangkok', default_hotel: true, }, ], permissions: ['RESERVATION_ORDER_READ'], menus: [ { menu_code: 'RESERVATION_ORDERS', menu_name: '订单列表', route_path: '/reservation/orders', component_key: 'ReservationOrders', icon_key: 'pi pi-list', permission_code: 'RESERVATION_ORDER_READ', sort_order: 10, }, ], } } describe('authService', () => { beforeEach(() => { vi.restoreAllMocks() sessionStorage.clear() }) it('logs in with username, password, and optional preferred hotel id', async () => { const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse(createAuthPayload())) const result = await loginAuth({ username: 'admin', password: 'Admin@123456', preferred_hotel_id: 'HOTEL-TEST', }) expect(fetchMock).toHaveBeenCalledWith( '/api/auth/login', expect.objectContaining({ method: 'POST', headers: expect.objectContaining({ 'Content-Type': 'application/json', }), body: JSON.stringify({ username: 'admin', password: 'Admin@123456', preferred_hotel_id: 'HOTEL-TEST', }), }), ) expect(result.access_token).toBe('session-token') expect(result.default_hotel_id).toBe('HOTEL-TEST') }) it('restores the current user through auth me', async () => { const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse(createAuthPayload())) sessionStorage.setItem('th_hotel_access_token', 'session-token') const result = await fetchCurrentAuth() expect(fetchMock).toHaveBeenCalledWith( '/api/auth/me', expect.objectContaining({ method: 'GET', headers: expect.objectContaining({ Authorization: 'Bearer session-token', }), }), ) expect(result.user.username).toBe('admin') }) it('logs out the current token without persisting secrets outside sessionStorage', async () => { const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse({ success: true })) sessionStorage.setItem('th_hotel_access_token', 'session-token') const result = await logoutAuth() expect(fetchMock).toHaveBeenCalledWith( '/api/auth/logout', expect.objectContaining({ method: 'POST', headers: expect.objectContaining({ Authorization: 'Bearer session-token', }), }), ) expect(result.success).toBe(true) expect(localStorage.getItem('th_hotel_access_token')).toBeNull() }) })