208 lines
6.9 KiB
JavaScript
208 lines
6.9 KiB
JavaScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
||
import { nextTick } from 'vue'
|
||
import { createTestPinia } from '../helpers/app.js'
|
||
import { useAppStore } from '@/stores/app'
|
||
import { useAuthStore } from '@/stores/auth'
|
||
import { useI18nStore } from '@/stores/i18n'
|
||
|
||
// app store 的 initThemeSync 依赖 theme 模块操作 documentElement,jest 环境可安全执行
|
||
vi.mock('@/theme/index', () => ({
|
||
applyPrimaryColor: vi.fn(),
|
||
applyDarkMode: vi.fn(),
|
||
}))
|
||
|
||
beforeEach(() => {
|
||
localStorage.clear()
|
||
sessionStorage.clear()
|
||
vi.clearAllMocks()
|
||
})
|
||
|
||
describe('app store · 主题与布局', () => {
|
||
it('初始状态:暗色关、默认主色、侧栏展开、工作台页签固定', () => {
|
||
createTestPinia()
|
||
const app = useAppStore()
|
||
expect(app.darkMode).toBe(false)
|
||
expect(app.sidebarCollapsed).toBe(false)
|
||
expect(app.visitedTabs).toHaveLength(1)
|
||
expect(app.visitedTabs[0]).toMatchObject({ key: '/dashboard', closable: false })
|
||
})
|
||
|
||
it('setDark / toggleDark 切换暗色', () => {
|
||
createTestPinia()
|
||
const app = useAppStore()
|
||
app.setDark(true)
|
||
expect(app.darkMode).toBe(true)
|
||
app.toggleDark()
|
||
expect(app.darkMode).toBe(false)
|
||
})
|
||
|
||
it('setPrimary / toggleSidebar / setSidebar', () => {
|
||
createTestPinia()
|
||
const app = useAppStore()
|
||
app.setPrimary('#123456')
|
||
expect(app.primaryColor).toBe('#123456')
|
||
app.toggleSidebar()
|
||
expect(app.sidebarCollapsed).toBe(true)
|
||
app.setSidebar(false)
|
||
expect(app.sidebarCollapsed).toBe(false)
|
||
})
|
||
|
||
it('i18n store 管理界面语言切换', () => {
|
||
createTestPinia()
|
||
const i18n = useI18nStore()
|
||
i18n.setLocale('zh-CN')
|
||
expect(i18n.locale).toBe('zh-CN')
|
||
i18n.toggleLocale()
|
||
expect(i18n.locale).toBe('en-US')
|
||
})
|
||
})
|
||
|
||
describe('app store · 页签管理', () => {
|
||
function seedTabs() {
|
||
const app = useAppStore()
|
||
app.addVisitedTab({ key: '/a', label: 'A', closable: true, name: 'A' })
|
||
app.addVisitedTab({ key: '/b', label: 'B', closable: true, name: 'B' })
|
||
app.addVisitedTab({ key: '/c', label: 'C', closable: true, name: 'C' })
|
||
app.refreshRoute('/a')
|
||
app.refreshRoute('/a')
|
||
app.refreshRoute('/b')
|
||
return app
|
||
}
|
||
|
||
it('addVisitedTab 去重:重复 key 不重复添加', () => {
|
||
createTestPinia()
|
||
const app = seedTabs()
|
||
app.addVisitedTab({ key: '/a', label: 'A2', closable: true, name: 'A' })
|
||
expect(app.visitedTabs.filter((t) => t.key === '/a')).toHaveLength(1)
|
||
})
|
||
|
||
it('cachedViews:按 visitedTabs 去重取组件名', () => {
|
||
createTestPinia()
|
||
const app = seedTabs()
|
||
app.addVisitedTab({ key: '/a', label: 'A', closable: true, name: 'A' })
|
||
expect(app.cachedViews).toEqual(['Dashboard', 'A', 'B', 'C'])
|
||
})
|
||
|
||
it('removeVisitedTab:移除页签并清理该页刷新计数', () => {
|
||
createTestPinia()
|
||
const app = seedTabs()
|
||
app.removeVisitedTab('/a')
|
||
expect(app.visitedTabs.some((t) => t.key === '/a')).toBe(false)
|
||
expect(app.routeRefreshKeys['/a']).toBeUndefined()
|
||
})
|
||
|
||
it('closeOthers:保留工作台与指定页签', () => {
|
||
createTestPinia()
|
||
const app = seedTabs()
|
||
app.closeOthers('/b')
|
||
expect(app.visitedTabs.map((t) => t.key)).toEqual(['/dashboard', '/b'])
|
||
expect(app.routeRefreshKeys['/a']).toBeUndefined()
|
||
})
|
||
|
||
it('closeLeft:保留工作台、指定页签及其右侧', () => {
|
||
createTestPinia()
|
||
const app = seedTabs()
|
||
app.closeLeft('/b')
|
||
expect(app.visitedTabs.map((t) => t.key)).toEqual(['/dashboard', '/b', '/c'])
|
||
})
|
||
|
||
it('closeLeft:指定工作台时不裁剪', () => {
|
||
createTestPinia()
|
||
const app = seedTabs()
|
||
app.closeLeft('/dashboard')
|
||
expect(app.visitedTabs).toHaveLength(4)
|
||
})
|
||
|
||
it('closeRight:保留指定页签及其左侧', () => {
|
||
createTestPinia()
|
||
const app = seedTabs()
|
||
app.closeRight('/b')
|
||
expect(app.visitedTabs.map((t) => t.key)).toEqual(['/dashboard', '/a', '/b'])
|
||
})
|
||
|
||
it('closeAll:仅保留工作台并清理全部刷新计数', () => {
|
||
createTestPinia()
|
||
const app = seedTabs()
|
||
app.closeAll()
|
||
expect(app.visitedTabs.map((t) => t.key)).toEqual(['/dashboard'])
|
||
expect(Object.keys(app.routeRefreshKeys)).toHaveLength(0)
|
||
})
|
||
|
||
it('refreshRoute / getRouteRefreshKey:计数递增与读取', () => {
|
||
createTestPinia()
|
||
const app = useAppStore()
|
||
expect(app.getRouteRefreshKey('/x')).toBe(0)
|
||
app.refreshRoute('/x')
|
||
app.refreshRoute('/x')
|
||
expect(app.getRouteRefreshKey('/x')).toBe(2)
|
||
})
|
||
})
|
||
|
||
describe('auth store · 用户信息回显(userInfo)', () => {
|
||
it('saveLastLogin 写入机构与账号', () => {
|
||
createTestPinia()
|
||
const auth = useAuthStore()
|
||
auth.saveLastLogin('ORG1', 'admin')
|
||
expect(auth.userInfo).toEqual({ orgId: 'ORG1', account: 'admin' })
|
||
})
|
||
|
||
it('持久化 key 为 fms-user(localStorage)', async () => {
|
||
createTestPinia()
|
||
const auth = useAuthStore()
|
||
auth.saveLastLogin('ORG9', 'u9')
|
||
// persist 插件通过 $subscribe 同步写 storage,冲刷微任务兜底
|
||
await nextTick()
|
||
expect(localStorage.getItem('fms-user')).toContain('ORG9')
|
||
expect(localStorage.getItem('fms-user')).toContain('"account":"u9"')
|
||
})
|
||
})
|
||
|
||
describe('auth store', () => {
|
||
it('setSession:token/orgid/user 三种字段形态兼容', () => {
|
||
createTestPinia()
|
||
const auth = useAuthStore()
|
||
auth.setSession(
|
||
{ access_token: 'at', orgid: 'O1', user_info: { id: 7 } },
|
||
'O_FALLBACK',
|
||
)
|
||
expect(auth.loginInfo.token).toBe('at')
|
||
expect(auth.userInfo.orgId).toBe('O1')
|
||
expect(auth.loginInfo.user).toEqual({ id: 7 })
|
||
expect(auth.isAuthenticated).toBe(true)
|
||
})
|
||
|
||
it('setSession:缺失字段时回退到 organizationId 参数', () => {
|
||
createTestPinia()
|
||
const auth = useAuthStore()
|
||
auth.setSession({ token: 't' }, 'ORG-FB')
|
||
expect(auth.userInfo.orgId).toBe('ORG-FB')
|
||
})
|
||
|
||
it('clearSession:清会话凭证,保留 userInfo 回显数据', () => {
|
||
createTestPinia()
|
||
const auth = useAuthStore()
|
||
auth.setSession({ token: 't', user: { id: 1 } }, 'ORG')
|
||
auth.saveLastLogin('ORG', 'admin')
|
||
auth.clearSession()
|
||
expect(auth.loginInfo.token).toBe('')
|
||
expect(auth.loginInfo.user).toBe(null)
|
||
expect(auth.isAuthenticated).toBe(false)
|
||
// userInfo 是登录页回显数据,不属于会话,退出登录后保留
|
||
expect(auth.userInfo).toEqual({ orgId: 'ORG', account: 'admin' })
|
||
})
|
||
|
||
it('持久化:会话写 sessionStorage(fms-login)、回显写 localStorage(fms-user)', async () => {
|
||
createTestPinia()
|
||
const auth = useAuthStore()
|
||
auth.setSession({ token: 't', user: { id: 1 } }, 'ORG')
|
||
auth.saveLastLogin('ORG', 'admin')
|
||
await nextTick()
|
||
expect(sessionStorage.getItem('fms-login')).toContain('"token":"t"')
|
||
expect(localStorage.getItem('fms-user')).toContain('"orgId":"ORG"')
|
||
// 会话与回显物理隔离:清会话不影响回显 key
|
||
auth.clearSession()
|
||
await nextTick()
|
||
expect(localStorage.getItem('fms-user')).toContain('"orgId":"ORG"')
|
||
})
|
||
})
|