242 lines
7.2 KiB
TypeScript
242 lines
7.2 KiB
TypeScript
import { mount } from '@vue/test-utils'
|
|
import { createPinia, setActivePinia } from 'pinia'
|
|
import { createI18n } from 'vue-i18n'
|
|
import { createMemoryHistory, createRouter } from 'vue-router'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import ReservationAppShell from '@/layouts/ReservationAppShell.vue'
|
|
import enUS from '@/i18n/locales/en-US'
|
|
import thTH from '@/i18n/locales/th-TH'
|
|
import zhCN from '@/i18n/locales/zh-CN'
|
|
import { useAuthStore } from '@/stores/authStore'
|
|
import type { AuthMenuResult } from '@/types/auth'
|
|
|
|
vi.mock('@/services/healthService', () => ({
|
|
fetchBackendHealth: vi.fn().mockResolvedValue({
|
|
status: 'UP',
|
|
service: 'test',
|
|
}),
|
|
}))
|
|
|
|
function createAuthPayload(menus: AuthMenuResult[]) {
|
|
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', 'RESERVATION_TASK_READ'],
|
|
menus,
|
|
}
|
|
}
|
|
|
|
function createReservationOrdersMenu(): AuthMenuResult {
|
|
return {
|
|
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,
|
|
}
|
|
}
|
|
|
|
function createReservationTasksMenu(): AuthMenuResult {
|
|
return {
|
|
menu_code: 'RESERVATION_TASKS',
|
|
menu_name: '任务队列',
|
|
route_path: '/reservation/tasks',
|
|
component_key: 'ReservationTasks',
|
|
icon_key: 'pi pi-check-square',
|
|
permission_code: 'RESERVATION_TASK_READ',
|
|
sort_order: 20,
|
|
}
|
|
}
|
|
|
|
function createDebugMenu(): AuthMenuResult {
|
|
return {
|
|
menu_code: 'DEBUG_EML_SUPERAGENT',
|
|
menu_name: 'Debug EML',
|
|
route_path: '/debug/eml-superagent',
|
|
component_key: 'DebugEmlSuperAgent',
|
|
icon_key: 'pi pi-upload',
|
|
permission_code: 'SYSTEM_DEBUG_EML_RUN',
|
|
sort_order: 30,
|
|
}
|
|
}
|
|
|
|
function createManualInvoiceMenu(): AuthMenuResult {
|
|
return {
|
|
menu_code: 'RESERVATION_MANUAL_INVOICE',
|
|
menu_name: '手工开票',
|
|
route_path: '/reservation/invoices/new',
|
|
component_key: 'ReservationManualInvoice',
|
|
icon_key: 'pi pi-file-pdf',
|
|
permission_code: 'RESERVATION_INVOICE_GENERATE',
|
|
sort_order: 25,
|
|
}
|
|
}
|
|
|
|
function createRoomingListMenu(): AuthMenuResult {
|
|
return {
|
|
menu_code: 'RESERVATION_ROOMING_LIST',
|
|
menu_name: 'Rooming List',
|
|
route_path: '/reservation/rooming-lists/new',
|
|
component_key: 'ReservationRoomingList',
|
|
icon_key: 'pi pi-file-excel',
|
|
permission_code: 'RESERVATION_ROOMING_LIST_GENERATE',
|
|
sort_order: 26,
|
|
}
|
|
}
|
|
|
|
function createSystemMenu(): AuthMenuResult {
|
|
return {
|
|
menu_code: 'SYSTEM_SETTINGS',
|
|
menu_name: '系统设置',
|
|
route_path: '/system',
|
|
component_key: 'SystemSettings',
|
|
icon_key: 'pi pi-cog',
|
|
permission_code: 'SYSTEM_ADMIN_CONSOLE_ACCESS',
|
|
sort_order: 40,
|
|
}
|
|
}
|
|
|
|
async function mountShell(menus = [createReservationOrdersMenu(), createReservationTasksMenu()]) {
|
|
const i18n = createI18n({
|
|
legacy: false,
|
|
locale: 'zh-CN',
|
|
fallbackLocale: 'zh-CN',
|
|
messages: {
|
|
'zh-CN': zhCN,
|
|
'en-US': enUS,
|
|
'th-TH': thTH,
|
|
},
|
|
})
|
|
const router = createRouter({
|
|
history: createMemoryHistory(),
|
|
routes: [
|
|
{
|
|
path: '/reservation/orders',
|
|
component: { template: '<div />' },
|
|
meta: { titleKey: 'nav.orders' },
|
|
},
|
|
{
|
|
path: '/reservation/tasks',
|
|
component: { template: '<div />' },
|
|
meta: { titleKey: 'nav.taskQueue' },
|
|
},
|
|
{
|
|
path: '/debug/eml-superagent',
|
|
component: { template: '<div />' },
|
|
meta: { titleKey: 'debugEml.title' },
|
|
},
|
|
{
|
|
path: '/reservation/invoices/new',
|
|
component: { template: '<div />' },
|
|
meta: { titleKey: 'nav.manualInvoice' },
|
|
},
|
|
{
|
|
path: '/reservation/rooming-lists/new',
|
|
component: { template: '<div />' },
|
|
meta: { titleKey: 'nav.roomingList' },
|
|
},
|
|
{
|
|
path: '/system',
|
|
component: { template: '<div />' },
|
|
meta: { titleKey: 'nav.systemSettings' },
|
|
},
|
|
],
|
|
})
|
|
const pinia = createPinia()
|
|
setActivePinia(pinia)
|
|
useAuthStore().applyLoginResult(createAuthPayload(menus))
|
|
await router.push('/reservation/orders')
|
|
await router.isReady()
|
|
|
|
return mount(ReservationAppShell, {
|
|
global: {
|
|
plugins: [i18n, router, pinia],
|
|
},
|
|
slots: {
|
|
default: '<section />',
|
|
},
|
|
})
|
|
}
|
|
|
|
describe('ReservationAppShell', () => {
|
|
beforeEach(() => {
|
|
sessionStorage.clear()
|
|
})
|
|
|
|
it('switches between Chinese, English, and Thai labels', async () => {
|
|
const wrapper = await mountShell()
|
|
|
|
expect(wrapper.text()).toContain('订单列表')
|
|
|
|
await wrapper.findAll('button').find((button) => button.text() === 'ไทย')?.trigger('click')
|
|
expect(wrapper.text()).toContain('รายการออเดอร์')
|
|
|
|
await wrapper.findAll('button').find((button) => button.text() === 'EN')?.trigger('click')
|
|
expect(wrapper.text()).toContain('Order list')
|
|
})
|
|
|
|
it('renders navigation from backend menus and hides Debug EML when the menu is absent', async () => {
|
|
const wrapper = await mountShell()
|
|
|
|
expect(wrapper.find('a[href="/reservation/orders"]').exists()).toBe(true)
|
|
expect(wrapper.find('a[href="/reservation/tasks"]').exists()).toBe(true)
|
|
expect(wrapper.text()).toContain('预订事项')
|
|
expect(wrapper.text()).not.toContain('任务队列')
|
|
expect(wrapper.find('a[href="/debug/eml-superagent"]').exists()).toBe(false)
|
|
})
|
|
|
|
it('shows Debug EML only when backend menus include it', async () => {
|
|
const wrapper = await mountShell([createReservationOrdersMenu(), createDebugMenu()])
|
|
|
|
expect(wrapper.find('a[href="/debug/eml-superagent"]').exists()).toBe(true)
|
|
expect(wrapper.text()).toContain('Debug EML')
|
|
})
|
|
|
|
it('shows Manual Invoice only when backend menus include it', async () => {
|
|
const wrapper = await mountShell([createReservationOrdersMenu(), createManualInvoiceMenu()])
|
|
|
|
expect(wrapper.find('a[href="/reservation/invoices/new"]').exists()).toBe(true)
|
|
expect(wrapper.text()).toContain('手工开票')
|
|
})
|
|
|
|
it('shows Rooming List only when backend menus include it', async () => {
|
|
const wrapper = await mountShell([createReservationOrdersMenu(), createRoomingListMenu()])
|
|
|
|
expect(wrapper.find('a[href="/reservation/rooming-lists/new"]').exists()).toBe(true)
|
|
expect(wrapper.text()).toContain('房表生成')
|
|
})
|
|
|
|
it('shows System Settings only when backend menus include it', async () => {
|
|
const wrapper = await mountShell([createReservationOrdersMenu(), createSystemMenu()])
|
|
|
|
expect(wrapper.find('a[href="/system"]').exists()).toBe(true)
|
|
expect(wrapper.text()).toContain('系统设置')
|
|
})
|
|
|
|
it('shows current user and hotel context in the top bar', async () => {
|
|
const wrapper = await mountShell()
|
|
|
|
expect(wrapper.text()).toContain('系统管理员')
|
|
expect(wrapper.text()).toContain('测试酒店')
|
|
})
|
|
})
|