user.spec.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. // Mock modules
  7. vi.mock('@/api/login', () => ({
  8. login: vi.fn(),
  9. getInfo: vi.fn(),
  10. logout: vi.fn()
  11. }))
  12. vi.mock('@/utils/auth', () => ({
  13. getToken: vi.fn(() => ''),
  14. setToken: vi.fn(),
  15. removeToken: vi.fn(),
  16. setRefreshToken: vi.fn(),
  17. removeRefreshToken: vi.fn()
  18. }))
  19. describe('User Store', () => {
  20. beforeEach(() => {
  21. setActivePinia(createPinia())
  22. vi.clearAllMocks()
  23. })
  24. describe('loginAction', () => {
  25. it('should login successfully and store token', async () => {
  26. const mockResponse = {
  27. code: 200,
  28. message: 'success',
  29. data: {
  30. token: 'test-token',
  31. refreshToken: 'refresh-token',
  32. admin: {
  33. id: 1,
  34. username: 'admin',
  35. nickname: 'Admin',
  36. role: 'admin'
  37. }
  38. }
  39. }
  40. vi.mocked(loginApi.login).mockResolvedValue(mockResponse)
  41. const store = useUserStore()
  42. const result = await store.loginAction({ username: 'admin', password: 'password' })
  43. expect(result.code).toBe(200)
  44. expect(store.token).toBe('test-token')
  45. expect(store.userInfo?.username).toBe('admin')
  46. expect(auth.setToken).toHaveBeenCalledWith('test-token')
  47. expect(auth.setRefreshToken).toHaveBeenCalledWith('refresh-token')
  48. })
  49. it('should not store token on login failure', async () => {
  50. const mockResponse = {
  51. code: 401,
  52. message: '用户名或密码错误',
  53. data: null
  54. }
  55. vi.mocked(loginApi.login).mockResolvedValue(mockResponse)
  56. const store = useUserStore()
  57. const result = await store.loginAction({ username: 'wrong', password: 'wrong' })
  58. expect(result.code).toBe(401)
  59. expect(store.token).toBe('')
  60. expect(auth.setToken).not.toHaveBeenCalled()
  61. })
  62. })
  63. describe('getUserInfo', () => {
  64. it('should fetch and store user info', async () => {
  65. const mockResponse = {
  66. code: 200,
  67. message: 'success',
  68. data: {
  69. id: 1,
  70. username: 'admin',
  71. nickname: 'Admin',
  72. role: 'admin'
  73. }
  74. }
  75. vi.mocked(loginApi.getInfo).mockResolvedValue(mockResponse)
  76. const store = useUserStore()
  77. const result = await store.getUserInfo()
  78. expect(result.code).toBe(200)
  79. expect(store.userInfo?.username).toBe('admin')
  80. expect(store.userInfo?.role).toBe('admin')
  81. })
  82. })
  83. describe('logoutAction', () => {
  84. it('should clear token and user info on logout', async () => {
  85. vi.mocked(loginApi.logout).mockResolvedValue({
  86. code: 200,
  87. message: 'success',
  88. data: null
  89. })
  90. const store = useUserStore()
  91. // Set initial state
  92. store.token = 'test-token'
  93. store.userInfo = { id: 1, username: 'admin', nickname: 'Admin', role: 'admin' }
  94. await store.logoutAction()
  95. expect(store.token).toBe('')
  96. expect(store.userInfo).toBeNull()
  97. expect(auth.removeToken).toHaveBeenCalled()
  98. expect(auth.removeRefreshToken).toHaveBeenCalled()
  99. })
  100. it('should clear state in finally block even if logout API fails', async () => {
  101. vi.mocked(loginApi.logout).mockRejectedValue(new Error('Network error'))
  102. const store = useUserStore()
  103. store.token = 'test-token'
  104. store.userInfo = { id: 1, username: 'admin', nickname: 'Admin', role: 'admin' }
  105. // logoutAction uses try/finally without catch, so error will propagate
  106. // but finally block still clears the state
  107. try {
  108. await store.logoutAction()
  109. } catch {
  110. // Expected to throw
  111. }
  112. // State should be cleared in finally block
  113. expect(store.token).toBe('')
  114. expect(store.userInfo).toBeNull()
  115. expect(auth.removeToken).toHaveBeenCalled()
  116. expect(auth.removeRefreshToken).toHaveBeenCalled()
  117. })
  118. })
  119. describe('resetToken', () => {
  120. it('should clear all auth state', () => {
  121. const store = useUserStore()
  122. store.token = 'test-token'
  123. store.userInfo = { id: 1, username: 'admin', nickname: 'Admin', role: 'admin' }
  124. store.resetToken()
  125. expect(store.token).toBe('')
  126. expect(store.userInfo).toBeNull()
  127. expect(auth.removeToken).toHaveBeenCalled()
  128. expect(auth.removeRefreshToken).toHaveBeenCalled()
  129. })
  130. })
  131. })