Files
happy-life-star/web-new/tests/unit/stores/auth.test.ts
T

350 lines
10 KiB
TypeScript

/**
* 认证状态管理测试
*/
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useAuthStore } from '@/stores/auth'
// 模拟 API
vi.mock('@/api/auth', () => ({
authApi: {
login: vi.fn(),
register: vi.fn(),
logout: vi.fn(),
refreshToken: vi.fn(),
getUserInfo: vi.fn()
}
}))
// 模拟存储工具
vi.mock('@/utils/storage', () => ({
default: {
get: vi.fn(),
set: vi.fn(),
remove: vi.fn(),
clear: vi.fn()
}
}))
// 模拟路由
const mockRouter = {
push: vi.fn(),
replace: vi.fn()
}
vi.mock('vue-router', () => ({
useRouter: () => mockRouter
}))
// 模拟配置
vi.mock('@/config/constants', () => ({
STORAGE_KEYS: {
TOKEN: 'auth_token',
REFRESH_TOKEN: 'refresh_token',
USER_INFO: 'user_info'
},
TOKEN_CONFIG: {
EXPIRES_IN: 7200,
REFRESH_THRESHOLD: 300
}
}))
describe('useAuthStore', () => {
let authStore: ReturnType<typeof useAuthStore>
beforeEach(() => {
setActivePinia(createPinia())
authStore = useAuthStore()
vi.clearAllMocks()
})
describe('initial state', () => {
it('should have correct initial state', () => {
expect(authStore.token).toBe('')
expect(authStore.refreshToken).toBe('')
expect(authStore.user).toBeNull()
expect(authStore.isAuthenticated).toBe(false)
expect(authStore.isTokenExpired).toBe(true)
})
})
describe('getters', () => {
it('should compute isAuthenticated correctly', () => {
expect(authStore.isAuthenticated).toBe(false)
authStore.token = 'valid-token'
authStore.tokenExpireTime = Date.now() + 3600000 // 1小时后过期
expect(authStore.isAuthenticated).toBe(true)
})
it('should compute isTokenExpired correctly', () => {
expect(authStore.isTokenExpired).toBe(true)
authStore.tokenExpireTime = Date.now() + 3600000 // 1小时后过期
expect(authStore.isTokenExpired).toBe(false)
authStore.tokenExpireTime = Date.now() - 3600000 // 1小时前过期
expect(authStore.isTokenExpired).toBe(true)
})
it('should compute needsRefresh correctly', () => {
authStore.tokenExpireTime = Date.now() + 600000 // 10分钟后过期
expect(authStore.needsRefresh).toBe(true)
authStore.tokenExpireTime = Date.now() + 3600000 // 1小时后过期
expect(authStore.needsRefresh).toBe(false)
})
it('should compute user properties correctly', () => {
authStore.user = {
id: '1',
username: 'testuser',
nickname: 'Test User',
email: 'test@example.com',
avatar: 'avatar.jpg',
role: 'user',
createTime: Date.now(),
updateTime: Date.now()
}
expect(authStore.userId).toBe('1')
expect(authStore.username).toBe('testuser')
expect(authStore.nickname).toBe('Test User')
expect(authStore.email).toBe('test@example.com')
expect(authStore.avatar).toBe('avatar.jpg')
expect(authStore.userRole).toBe('user')
})
})
describe('actions', () => {
describe('login', () => {
it('should login successfully', async () => {
const mockResponse = {
token: 'new-token',
refreshToken: 'new-refresh-token',
expiresIn: 7200,
user: {
id: '1',
username: 'testuser',
nickname: 'Test User',
email: 'test@example.com'
}
}
const { authApi } = await import('@/api/auth')
vi.mocked(authApi.login).mockResolvedValue(mockResponse)
const loginData = {
username: 'testuser',
password: 'password123'
}
const result = await authStore.login(loginData)
expect(authApi.login).toHaveBeenCalledWith(loginData)
expect(authStore.token).toBe('new-token')
expect(authStore.refreshToken).toBe('new-refresh-token')
expect(authStore.user).toEqual(mockResponse.user)
expect(result).toEqual(mockResponse)
})
it('should handle login failure', async () => {
const { authApi } = await import('@/api/auth')
const error = new Error('Invalid credentials')
vi.mocked(authApi.login).mockRejectedValue(error)
const loginData = {
username: 'testuser',
password: 'wrongpassword'
}
await expect(authStore.login(loginData)).rejects.toThrow('Invalid credentials')
expect(authStore.token).toBe('')
expect(authStore.user).toBeNull()
})
})
describe('register', () => {
it('should register successfully', async () => {
const mockResponse = {
token: 'new-token',
refreshToken: 'new-refresh-token',
expiresIn: 7200,
user: {
id: '1',
username: 'newuser',
nickname: 'New User',
email: 'new@example.com'
}
}
const { authApi } = await import('@/api/auth')
vi.mocked(authApi.register).mockResolvedValue(mockResponse)
const registerData = {
username: 'newuser',
password: 'password123',
email: 'new@example.com',
nickname: 'New User'
}
const result = await authStore.register(registerData)
expect(authApi.register).toHaveBeenCalledWith(registerData)
expect(authStore.token).toBe('new-token')
expect(authStore.user).toEqual(mockResponse.user)
expect(result).toEqual(mockResponse)
})
})
describe('logout', () => {
it('should logout successfully', async () => {
// 设置初始状态
authStore.token = 'current-token'
authStore.refreshToken = 'current-refresh-token'
authStore.user = { id: '1', username: 'testuser' } as any
const { authApi } = await import('@/api/auth')
vi.mocked(authApi.logout).mockResolvedValue(undefined)
await authStore.logout()
expect(authApi.logout).toHaveBeenCalled()
expect(authStore.token).toBe('')
expect(authStore.refreshToken).toBe('')
expect(authStore.user).toBeNull()
expect(authStore.tokenExpireTime).toBe(0)
})
it('should clear state even if API call fails', async () => {
authStore.token = 'current-token'
authStore.user = { id: '1', username: 'testuser' } as any
const { authApi } = await import('@/api/auth')
vi.mocked(authApi.logout).mockRejectedValue(new Error('Network error'))
await authStore.logout()
expect(authStore.token).toBe('')
expect(authStore.user).toBeNull()
})
})
describe('refreshToken', () => {
it('should refresh token successfully', async () => {
authStore.refreshToken = 'current-refresh-token'
const mockResponse = {
token: 'new-token',
refreshToken: 'new-refresh-token',
expiresIn: 7200
}
const { authApi } = await import('@/api/auth')
vi.mocked(authApi.refreshToken).mockResolvedValue(mockResponse)
const result = await authStore.refreshTokenAction()
expect(authApi.refreshToken).toHaveBeenCalledWith('current-refresh-token')
expect(authStore.token).toBe('new-token')
expect(authStore.refreshToken).toBe('new-refresh-token')
expect(result).toEqual(mockResponse)
})
it('should handle refresh token failure', async () => {
authStore.refreshToken = 'invalid-refresh-token'
const { authApi } = await import('@/api/auth')
vi.mocked(authApi.refreshToken).mockRejectedValue(new Error('Invalid refresh token'))
await expect(authStore.refreshTokenAction()).rejects.toThrow('Invalid refresh token')
})
})
describe('updateUserInfo', () => {
it('should update user info', async () => {
authStore.user = {
id: '1',
username: 'testuser',
nickname: 'Old Name',
email: 'old@example.com'
} as any
const updates = {
nickname: 'New Name',
email: 'new@example.com'
}
await authStore.updateUserInfo(updates)
expect(authStore.user?.nickname).toBe('New Name')
expect(authStore.user?.email).toBe('new@example.com')
expect(authStore.user?.username).toBe('testuser') // 保持不变
})
})
describe('checkAuthStatus', () => {
it('should return true for valid authentication', () => {
authStore.token = 'valid-token'
authStore.tokenExpireTime = Date.now() + 3600000
expect(authStore.checkAuthStatus()).toBe(true)
})
it('should return false for expired token', () => {
authStore.token = 'expired-token'
authStore.tokenExpireTime = Date.now() - 3600000
expect(authStore.checkAuthStatus()).toBe(false)
})
it('should return false for missing token', () => {
authStore.token = ''
expect(authStore.checkAuthStatus()).toBe(false)
})
})
})
describe('persistence', () => {
it('should save state to storage', () => {
const storage = require('@/utils/storage').default
authStore.token = 'test-token'
authStore.refreshToken = 'test-refresh-token'
authStore.user = { id: '1', username: 'testuser' } as any
authStore.saveToStorage()
expect(storage.set).toHaveBeenCalledWith('auth_token', 'test-token')
expect(storage.set).toHaveBeenCalledWith('refresh_token', 'test-refresh-token')
expect(storage.set).toHaveBeenCalledWith('user_info', authStore.user)
})
it('should load state from storage', () => {
const storage = require('@/utils/storage').default
storage.get.mockImplementation((key: string) => {
switch (key) {
case 'auth_token':
return 'stored-token'
case 'refresh_token':
return 'stored-refresh-token'
case 'user_info':
return { id: '1', username: 'storeduser' }
default:
return null
}
})
authStore.loadFromStorage()
expect(authStore.token).toBe('stored-token')
expect(authStore.refreshToken).toBe('stored-refresh-token')
expect(authStore.user).toEqual({ id: '1', username: 'storeduser' })
})
})
})