Files
th-hotel-simple/client/src/tests/reservationRouter.spec.ts
2026-07-20 00:09:58 +07:00

201 lines
7.3 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import type { RouteLocationNormalized } from 'vue-router'
import { createAuthGuard, router } from '@/router'
import type { useAuthStore } from '@/stores/authStore'
type AuthStoreForGuard = ReturnType<typeof useAuthStore>
function createRoute(
path: string,
meta: Record<string, unknown> = {},
overrides: Partial<RouteLocationNormalized> = {},
): RouteLocationNormalized {
return {
fullPath: path,
path,
name: undefined,
params: {},
query: {},
hash: '',
matched: [],
meta,
redirectedFrom: undefined,
...overrides,
} as RouteLocationNormalized
}
function createAuthStoreForGuard(overrides: Partial<AuthStoreForGuard> = {}): AuthStoreForGuard {
return {
restoreAttempted: true,
isAuthenticated: true,
firstMenuPath: '/reservation/orders',
hasStoredToken: () => false,
restoreFromSession: async () => true,
hasPermission: () => true,
...overrides,
} as unknown as AuthStoreForGuard
}
describe('reservation router', () => {
it('exposes the P0 frontend routes', () => {
expect(router.resolve('/login').name).toBe('login')
expect(router.resolve('/reservation/orders').name).toBe('reservation-order-list')
expect(router.resolve('/reservation/tasks').name).toBe('reservation-task-list')
expect(router.resolve('/reservation/invoices/new').name).toBe('reservation-manual-invoice')
expect(router.resolve('/reservation/rooming-lists/new').name).toBe('reservation-rooming-list')
expect(router.resolve('/reservation/orders/20001').name).toBe('reservation-order-detail')
expect(router.resolve('/reservation/tasks/10001').name).toBe('reservation-task-detail')
expect(router.resolve('/reservation/source-messages/30001/conversation').name).toBe(
'reservation-source-message-conversation',
)
})
it('exposes the Debug EML route', () => {
expect(router.resolve('/debug/eml-superagent').name).toBe('debug-eml-superagent')
})
it('exposes the System Admin V1 routes', () => {
expect(router.resolve('/system/users').name).toBe('system-users')
expect(router.resolve('/system/roles').name).toBe('system-roles')
expect(router.resolve('/system/menus').name).toBe('system-menus')
expect(router.resolve('/system/hotels').name).toBe('system-hotels')
expect(router.resolve('/system/reservation-catalogs').name).toBe('system-reservation-catalogs')
expect(router.resolve('/system/audits').name).toBe('system-audits')
expect(router.resolve('/system/not-ready').name).toBe('not-found')
})
it('declares permissions for protected P0 routes', () => {
expect(router.resolve('/reservation/orders').meta.permission).toBe('RESERVATION_ORDER_READ')
expect(router.resolve('/reservation/orders/20001').meta.permission).toBe('RESERVATION_ORDER_READ')
expect(router.resolve('/reservation/tasks').meta.permission).toBe('RESERVATION_TASK_READ')
expect(router.resolve('/reservation/tasks/10001').meta.permission).toBe('RESERVATION_TASK_READ')
expect(router.resolve('/reservation/invoices/new').meta.permission).toBe('RESERVATION_INVOICE_GENERATE')
expect(router.resolve('/reservation/rooming-lists/new').meta.permission).toBe(
'RESERVATION_ROOMING_LIST_GENERATE',
)
expect(router.resolve('/reservation/source-messages/30001/conversation').meta.permission).toBe(
'SOURCE_MESSAGE_ORIGINAL_READ',
)
expect(router.resolve('/debug/eml-superagent').meta.permission).toBe('SYSTEM_DEBUG_EML_RUN')
expect(router.resolve('/system/users').meta.permission).toBe('SYSTEM_USER_MANAGE')
expect(router.resolve('/system/roles').meta.permission).toBe('SYSTEM_ROLE_MANAGE')
expect(router.resolve('/system/menus').meta.permission).toBe('SYSTEM_MENU_MANAGE')
expect(router.resolve('/system/hotels').meta.permission).toBe('HOTEL_MANAGE')
expect(router.resolve('/system/reservation-catalogs').meta.permission).toBe('RESERVATION_CATALOG_MANAGE')
expect(router.resolve('/system/audits').meta.permission).toBe('SYSTEM_ADMIN_CONSOLE_ACCESS')
})
it('redirects anonymous users to login with the protected target as redirect', async () => {
const guard = createAuthGuard(() =>
createAuthStoreForGuard({
isAuthenticated: false,
}),
)
await expect(guard(createRoute('/reservation/orders', { permission: 'RESERVATION_ORDER_READ' }))).resolves.toEqual({
path: '/login',
query: {
redirect: '/reservation/orders',
},
})
})
it('redirects authenticated users without route permission to the unauthorized page', async () => {
const guard = createAuthGuard(() =>
createAuthStoreForGuard({
hasPermission: () => false,
}),
)
await expect(guard(createRoute('/debug/eml-superagent', { permission: 'SYSTEM_DEBUG_EML_RUN' }))).resolves.toEqual({
name: 'unauthorized',
})
})
it('redirects the root route to the restored first backend menu', async () => {
let restored = false
let authenticated = false
let firstMenuPath: string | null = null
const authStore = {
restoreAttempted: false,
get isAuthenticated() {
return authenticated
},
get firstMenuPath() {
return firstMenuPath
},
hasStoredToken: () => true,
restoreFromSession: async () => {
restored = true
authStore.restoreAttempted = true
authenticated = true
firstMenuPath = '/reservation/tasks'
return true
},
hasPermission: () => true,
} as unknown as AuthStoreForGuard
const guard = createAuthGuard(() => authStore)
await expect(guard(createRoute('/'))).resolves.toBe('/reservation/tasks')
expect(restored).toBe(true)
})
it('redirects the System Admin entry to the first allowed management page', async () => {
const guard = createAuthGuard(() =>
createAuthStoreForGuard({
hasPermission: (permission: string) =>
permission === 'SYSTEM_ADMIN_CONSOLE_ACCESS' || permission === 'HOTEL_MANAGE',
}),
)
await expect(guard(createRoute('/system', { permission: 'SYSTEM_ADMIN_CONSOLE_ACCESS' }))).resolves.toBe(
'/system/hotels',
)
})
it('redirects the System Admin entry to catalog management when it is the first allowed admin page', async () => {
const guard = createAuthGuard(() =>
createAuthStoreForGuard({
hasPermission: (permission: string) =>
permission === 'SYSTEM_ADMIN_CONSOLE_ACCESS' || permission === 'RESERVATION_CATALOG_MANAGE',
}),
)
await expect(guard(createRoute('/system', { permission: 'SYSTEM_ADMIN_CONSOLE_ACCESS' }))).resolves.toBe(
'/system/reservation-catalogs',
)
})
it('redirects the root route to the default page when the backend menu points to root', async () => {
const guard = createAuthGuard(() =>
createAuthStoreForGuard({
firstMenuPath: '/',
}),
)
await expect(guard(createRoute('/'))).resolves.toBe('/reservation/orders')
})
it('ignores root login redirects after authentication', async () => {
const guard = createAuthGuard(() => createAuthStoreForGuard())
await expect(
guard(
createRoute(
'/login',
{
public: true,
},
{
name: 'login',
query: {
redirect: '/',
},
},
),
),
).resolves.toBe('/reservation/orders')
})
})