user.spec.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { describe, it, expect, vi, beforeEach } from 'vitest'
  2. import { setActivePinia, createPinia } from 'pinia'
  3. import { useUserStore } from '@/store/user'
  4. import * as loginApi from '@/api/login'
  5. import * as auth from '@/utils/auth'
  6. import { mockLoginResponse, mockAdminInfo, wrapResponse, wrapErrorResponse } from '../../fixtures'
  7. // Mock modules
  8. vi.mock('@/api/login', () => ({
  9. login: vi.fn(),
  10. getInfo: vi.fn(),
  11. logout: vi.fn()
  12. }))
  13. vi.mock('@/utils/auth', () => ({
  14. getToken: vi.fn(() => ''),
  15. setToken: vi.fn(),
  16. removeToken: vi.fn(),
  17. setRefreshToken: vi.fn(),
  18. removeRefreshToken: vi.fn()
  19. }))
  20. describe('User Store', () => {
  21. beforeEach(() => {
  22. setActivePinia(createPinia())
  23. vi.clearAllMocks()
  24. })
  25. describe('loginAction', () => {
  26. it('should login successfully and store token', async () => {
  27. const mockResponse = wrapResponse(mockLoginResponse)
  28. vi.mocked(loginApi.login).mockResolvedValue(mockResponse)
  29. const store = useUserStore()
  30. const result = await store.loginAction({ username: 'admin', password: 'password' })
  31. expect(result.code).toBe(200)
  32. expect(store.token).toBe(mockLoginResponse.token)
  33. expect(store.userInfo?.username).toBe(mockLoginResponse.admin.username)
  34. expect(auth.setToken).toHaveBeenCalledWith(mockLoginResponse.token)
  35. expect(auth.setRefreshToken).toHaveBeenCalledWith(mockLoginResponse.refreshToken)
  36. })
  37. it('should not store token on login failure', async () => {
  38. const mockResponse = wrapErrorResponse('用户名或密码错误', 401)
  39. vi.mocked(loginApi.login).mockResolvedValue(mockResponse)
  40. const store = useUserStore()
  41. const result = await store.loginAction({ username: 'wrong', password: 'wrong' })
  42. expect(result.code).toBe(401)
  43. expect(store.token).toBe('')
  44. expect(auth.setToken).not.toHaveBeenCalled()
  45. })
  46. })
  47. describe('getUserInfo', () => {
  48. it('should fetch and store user info', async () => {
  49. const mockResponse = wrapResponse(mockAdminInfo)
  50. vi.mocked(loginApi.getInfo).mockResolvedValue(mockResponse)
  51. const store = useUserStore()
  52. const result = await store.getUserInfo()
  53. expect(result.code).toBe(200)
  54. expect(store.userInfo?.username).toBe(mockAdminInfo.username)
  55. expect(store.userInfo?.role).toBe(mockAdminInfo.role)
  56. })
  57. })
  58. describe('logoutAction', () => {
  59. it('should clear token and user info on logout', async () => {
  60. vi.mocked(loginApi.logout).mockResolvedValue(wrapResponse(null))
  61. const store = useUserStore()
  62. // Set initial state
  63. store.token = mockLoginResponse.token
  64. store.userInfo = mockAdminInfo
  65. await store.logoutAction()
  66. expect(store.token).toBe('')
  67. expect(store.userInfo).toBeNull()
  68. expect(auth.removeToken).toHaveBeenCalled()
  69. expect(auth.removeRefreshToken).toHaveBeenCalled()
  70. })
  71. it('should clear state in finally block even if logout API fails', async () => {
  72. vi.mocked(loginApi.logout).mockRejectedValue(new Error('Network error'))
  73. const store = useUserStore()
  74. store.token = mockLoginResponse.token
  75. store.userInfo = mockAdminInfo
  76. // logoutAction uses try/finally without catch, so error will propagate
  77. // but finally block still clears the state
  78. try {
  79. await store.logoutAction()
  80. } catch {
  81. // Expected to throw
  82. }
  83. // State should be cleared in finally block
  84. expect(store.token).toBe('')
  85. expect(store.userInfo).toBeNull()
  86. expect(auth.removeToken).toHaveBeenCalled()
  87. expect(auth.removeRefreshToken).toHaveBeenCalled()
  88. })
  89. })
  90. describe('resetToken', () => {
  91. it('should clear all auth state', () => {
  92. const store = useUserStore()
  93. store.token = mockLoginResponse.token
  94. store.userInfo = mockAdminInfo
  95. store.resetToken()
  96. expect(store.token).toBe('')
  97. expect(store.userInfo).toBeNull()
  98. expect(auth.removeToken).toHaveBeenCalled()
  99. expect(auth.removeRefreshToken).toHaveBeenCalled()
  100. })
  101. })
  102. })