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 function createRoute( path: string, meta: Record = {}, overrides: Partial = {}, ): RouteLocationNormalized { return { fullPath: path, path, name: undefined, params: {}, query: {}, hash: '', matched: [], meta, redirectedFrom: undefined, ...overrides, } as RouteLocationNormalized } function createAuthStoreForGuard(overrides: Partial = {}): 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') }) })