Files
th-hotel-simple/client/src/tests/authService.spec.ts
2026-07-09 20:42:16 +08:00

126 lines
3.5 KiB
TypeScript

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()
})
})