Files
th-hotel-simple/client/src/tests/systemAdminService.spec.ts
2026-07-16 12:47:21 +07:00

304 lines
9.1 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
import {
assignAdminRolePermissions,
assignAdminUserHotels,
assignAdminUserRoles,
createAdminHotel,
createAdminMenu,
createAdminRole,
createAdminUser,
fetchAdminAudits,
fetchAdminHotels,
fetchAdminMenuTree,
fetchAdminMenus,
fetchAdminPermissions,
fetchAdminRoleDetail,
fetchAdminRoles,
fetchAdminUserDetail,
fetchAdminUsers,
resetAdminUserPassword,
updateAdminHotel,
updateAdminHotelStatus,
updateAdminMenu,
updateAdminMenuTreeOrder,
updateAdminRole,
updateAdminUser,
} from '@/services/systemAdminService'
const jsonHeaders = {
headers: {
get: (name: string) => (name.toLowerCase() === 'content-type' ? 'application/json' : null),
},
}
function mockJsonResponse(payload: unknown): Response {
return {
ok: true,
status: 200,
json: async () => payload,
text: async () => JSON.stringify(payload),
...jsonHeaders,
} as Response
}
describe('systemAdminService', () => {
beforeEach(() => {
vi.restoreAllMocks()
sessionStorage.clear()
})
it('fetches admin users with filters', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
mockJsonResponse({
items: [],
page: {
page_num: 2,
page_size: 10,
total: 0,
},
}),
)
await fetchAdminUsers({
keyword: 'admin',
user_status: 'ACTIVE',
page_num: 2,
page_size: 10,
})
expect(fetchMock).toHaveBeenCalledWith(
'/api/admin/users?keyword=admin&user_status=ACTIVE&page_num=2&page_size=10',
expect.objectContaining({ method: 'GET' }),
)
})
it('fetches role, menu, hotel lists and details from admin endpoints', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse({ items: [], page: {} }))
await fetchAdminRoles({ role_status: 'DISABLED' })
await fetchAdminMenus({ menu_status: 'ACTIVE' })
await fetchAdminHotels({ hotel_status: 'ACTIVE' })
await fetchAdminUserDetail('10001')
await fetchAdminRoleDetail('20001')
expect(fetchMock).toHaveBeenNthCalledWith(
1,
'/api/admin/roles?role_status=DISABLED',
expect.objectContaining({ method: 'GET' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
2,
'/api/admin/menus?menu_status=ACTIVE',
expect.objectContaining({ method: 'GET' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
3,
'/api/admin/hotels?hotel_status=ACTIVE',
expect.objectContaining({ method: 'GET' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
4,
'/api/admin/users/10001',
expect.objectContaining({ method: 'GET' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
5,
'/api/admin/roles/20001',
expect.objectContaining({ method: 'GET' }),
)
})
it('fetches and saves the admin menu tree endpoints', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
mockJsonResponse({
items: [
{
id: '40001',
parent_id: null,
menu_code: 'SYSTEM_SETTINGS',
menu_name: '系统设置',
menu_type: 'GROUP',
route_path: '/system',
component_key: 'system',
icon_key: 'pi pi-cog',
permission_code: 'SYSTEM_ADMIN_CONSOLE_ACCESS',
sort_order: 900,
visible: true,
menu_status: 'ACTIVE',
known_route: true,
created_at: '2026-07-16T00:00:00Z',
updated_at: '2026-07-16T00:00:00Z',
children: [],
},
],
warnings: ['菜单 49999 的 parent_id 不存在,已按根级异常节点返回。'],
}),
)
const tree = await fetchAdminMenuTree()
await updateAdminMenuTreeOrder({
items: [
{
menu_id: '40002',
parent_id: '40001',
sort_order: 100,
},
],
})
expect(tree.items[0]?.children).toEqual([])
expect(tree.warnings[0]).toContain('parent_id')
expect(fetchMock).toHaveBeenNthCalledWith(
1,
'/api/admin/menus/tree',
expect.objectContaining({ method: 'GET' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
2,
'/api/admin/menus/tree-order',
expect.objectContaining({
method: 'PUT',
body: JSON.stringify({
items: [
{
menu_id: '40002',
parent_id: '40001',
sort_order: 100,
},
],
}),
}),
)
})
it('fetches the readonly permission list', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
mockJsonResponse([
{
id: '1',
permission_code: 'SYSTEM_USER_MANAGE',
permission_name: '用户管理',
permission_group: 'SYSTEM',
permission_status: 'ACTIVE',
},
]),
)
const result = await fetchAdminPermissions()
expect(fetchMock).toHaveBeenCalledWith('/api/admin/permissions', expect.objectContaining({ method: 'GET' }))
expect(result[0]?.permission_code).toBe('SYSTEM_USER_MANAGE')
})
it('sends admin user write operations to backend endpoints', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse({ id: '10001' }))
await createAdminUser({
username: 'operator',
initial_password: 'User@123456',
display_name: 'Operator',
user_status: 'ACTIVE',
role_ids: ['20001'],
hotel_ids: ['HOTEL-TEST'],
default_hotel_id: 'HOTEL-TEST',
})
await updateAdminUser('10001', {
display_name: 'Operator A',
user_status: 'DISABLED',
})
await assignAdminUserRoles('10001', {
role_ids: ['20002'],
})
await assignAdminUserHotels('10001', {
hotel_ids: ['HOTEL-TEST'],
default_hotel_id: 'HOTEL-TEST',
})
await resetAdminUserPassword('10001')
expect(fetchMock).toHaveBeenNthCalledWith(
1,
'/api/admin/users',
expect.objectContaining({ method: 'POST' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
2,
'/api/admin/users/10001',
expect.objectContaining({ method: 'PUT' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
3,
'/api/admin/users/10001/roles',
expect.objectContaining({ method: 'PUT' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
4,
'/api/admin/users/10001/hotels',
expect.objectContaining({ method: 'PUT' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
5,
'/api/admin/users/10001/password-reset',
expect.objectContaining({ method: 'POST', body: JSON.stringify({}) }),
)
})
it('sends role, menu, hotel writes and audit queries to admin endpoints', async () => {
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse({ id: '1', items: [], page: {} }))
await createAdminRole({ role_code: 'CUSTOM_ROLE', role_name: 'Custom role', role_status: 'ACTIVE' })
await updateAdminRole('20001', { role_name: 'Custom role A', role_status: 'DISABLED' })
await assignAdminRolePermissions('20001', { permission_ids: ['30001'] })
await createAdminMenu({
menu_code: 'CUSTOM_MENU',
menu_name: 'Custom menu',
menu_type: 'PAGE',
visible: false,
menu_status: 'DISABLED',
})
await updateAdminMenu('40001', {
menu_name: 'Custom menu A',
menu_type: 'PAGE',
visible: true,
menu_status: 'ACTIVE',
})
await createAdminHotel({
hotel_id: 'HOTEL-BKK',
hotel_name: 'Bangkok Hotel',
time_zone: 'Asia/Bangkok',
})
await updateAdminHotel('HOTEL-BKK', {
hotel_name: 'Bangkok Hotel A',
time_zone: 'Asia/Bangkok',
})
await updateAdminHotelStatus('HOTEL-BKK', { hotel_status: 'ACTIVE' })
await fetchAdminAudits({ target_type: 'PLATFORM_USER', page_num: 1, page_size: 20 })
expect(fetchMock).toHaveBeenNthCalledWith(1, '/api/admin/roles', expect.objectContaining({ method: 'POST' }))
expect(fetchMock).toHaveBeenNthCalledWith(2, '/api/admin/roles/20001', expect.objectContaining({ method: 'PUT' }))
expect(fetchMock).toHaveBeenNthCalledWith(
3,
'/api/admin/roles/20001/permissions',
expect.objectContaining({ method: 'PUT' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(4, '/api/admin/menus', expect.objectContaining({ method: 'POST' }))
expect(fetchMock).toHaveBeenNthCalledWith(5, '/api/admin/menus/40001', expect.objectContaining({ method: 'PUT' }))
expect(fetchMock).toHaveBeenNthCalledWith(6, '/api/admin/hotels', expect.objectContaining({ method: 'POST' }))
expect(fetchMock).toHaveBeenNthCalledWith(
7,
'/api/admin/hotels/HOTEL-BKK',
expect.objectContaining({ method: 'PUT' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
8,
'/api/admin/hotels/HOTEL-BKK/status',
expect.objectContaining({ method: 'PUT' }),
)
expect(fetchMock).toHaveBeenNthCalledWith(
9,
'/api/admin/audits?target_type=PLATFORM_USER&page_num=1&page_size=20',
expect.objectContaining({ method: 'GET' }),
)
})
})