192 lines
6.9 KiB
TypeScript
192 lines
6.9 KiB
TypeScript
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
|
|
import { setActivePinia, createPinia } from 'pinia'
|
|
import { useAuthStore } from '../auth'
|
|
import * as authApi from '@/api/auth'
|
|
|
|
describe('useAuthStore', () => {
|
|
beforeEach(() => {
|
|
setActivePinia(createPinia())
|
|
localStorage.clear()
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
afterEach(() => {
|
|
localStorage.clear()
|
|
})
|
|
|
|
it('initializes with tokens from localStorage if available', () => {
|
|
localStorage.setItem('access_token', 'initial-access-token')
|
|
localStorage.setItem('refresh_token', 'initial-refresh-token')
|
|
|
|
const authStore = useAuthStore()
|
|
|
|
expect(authStore.accessToken).toBe('initial-access-token')
|
|
expect(authStore.refreshToken).toBe('initial-refresh-token')
|
|
expect(authStore.isAuthenticated).toBe(true)
|
|
})
|
|
|
|
it('initializes with null tokens if localStorage is empty', () => {
|
|
const authStore = useAuthStore()
|
|
|
|
expect(authStore.accessToken).toBeNull()
|
|
expect(authStore.refreshToken).toBeNull()
|
|
expect(authStore.isAuthenticated).toBe(false)
|
|
})
|
|
|
|
it('successfully logs in and stores tokens in state and localStorage', async () => {
|
|
const mockTokenPair = {
|
|
access_token: 'new-access-token',
|
|
refresh_token: 'new-refresh-token',
|
|
}
|
|
|
|
vi.spyOn(authApi, 'loginApi').mockResolvedValueOnce(mockTokenPair)
|
|
|
|
const authStore = useAuthStore()
|
|
const result = await authStore.login({
|
|
email: 'test@example.com',
|
|
password: 'password123',
|
|
})
|
|
|
|
expect(result).toEqual(mockTokenPair)
|
|
expect(authStore.accessToken).toBe('new-access-token')
|
|
expect(authStore.refreshToken).toBe('new-refresh-token')
|
|
expect(authStore.isAuthenticated).toBe(true)
|
|
expect(localStorage.getItem('access_token')).toBe('new-access-token')
|
|
expect(localStorage.getItem('refresh_token')).toBe('new-refresh-token')
|
|
expect(authStore.error).toBeNull()
|
|
})
|
|
|
|
it('handles login failure and sets error message', async () => {
|
|
vi.spyOn(authApi, 'loginApi').mockRejectedValueOnce(new Error('Invalid credentials'))
|
|
|
|
const authStore = useAuthStore()
|
|
|
|
await expect(
|
|
authStore.login({
|
|
email: 'test@example.com',
|
|
password: 'wrong-password',
|
|
}),
|
|
).rejects.toThrow('Invalid credentials')
|
|
|
|
expect(authStore.accessToken).toBeNull()
|
|
expect(authStore.refreshToken).toBeNull()
|
|
expect(authStore.isAuthenticated).toBe(false)
|
|
expect(authStore.error).toBe('Invalid credentials')
|
|
})
|
|
|
|
it('refreshes tokens successfully and updates state and localStorage', async () => {
|
|
localStorage.setItem('access_token', 'old-access-token')
|
|
localStorage.setItem('refresh_token', 'old-refresh-token')
|
|
|
|
const authStore = useAuthStore()
|
|
|
|
const refreshedTokenPair = {
|
|
access_token: 'refreshed-access-token',
|
|
refresh_token: 'refreshed-refresh-token',
|
|
}
|
|
|
|
const refreshSpy = vi.spyOn(authApi, 'refreshApi').mockResolvedValueOnce(refreshedTokenPair)
|
|
|
|
const result = await authStore.refreshTokens()
|
|
|
|
expect(refreshSpy).toHaveBeenCalledWith({ refresh_token: 'old-refresh-token' })
|
|
expect(result).toEqual(refreshedTokenPair)
|
|
expect(authStore.accessToken).toBe('refreshed-access-token')
|
|
expect(authStore.refreshToken).toBe('refreshed-refresh-token')
|
|
expect(localStorage.getItem('access_token')).toBe('refreshed-access-token')
|
|
expect(localStorage.getItem('refresh_token')).toBe('refreshed-refresh-token')
|
|
})
|
|
|
|
it('clears tokens and throws if refreshTokens is called without a refresh token', async () => {
|
|
const authStore = useAuthStore()
|
|
|
|
await expect(authStore.refreshTokens()).rejects.toThrow('No refresh token available')
|
|
expect(authStore.accessToken).toBeNull()
|
|
expect(authStore.refreshToken).toBeNull()
|
|
})
|
|
|
|
it('clears tokens and sets error when refresh API call fails', async () => {
|
|
localStorage.setItem('access_token', 'old-access-token')
|
|
localStorage.setItem('refresh_token', 'expired-refresh-token')
|
|
|
|
const authStore = useAuthStore()
|
|
|
|
vi.spyOn(authApi, 'refreshApi').mockRejectedValueOnce(new Error('Refresh token expired'))
|
|
|
|
await expect(authStore.refreshTokens()).rejects.toThrow('Refresh token expired')
|
|
expect(authStore.accessToken).toBeNull()
|
|
expect(authStore.refreshToken).toBeNull()
|
|
expect(authStore.error).toBe('Refresh token expired')
|
|
expect(localStorage.getItem('access_token')).toBeNull()
|
|
expect(localStorage.getItem('refresh_token')).toBeNull()
|
|
})
|
|
|
|
it('clears tokens and calls logout API on logout', async () => {
|
|
localStorage.setItem('access_token', 'sample-access')
|
|
localStorage.setItem('refresh_token', 'sample-refresh')
|
|
|
|
const authStore = useAuthStore()
|
|
expect(authStore.isAuthenticated).toBe(true)
|
|
|
|
const logoutSpy = vi.spyOn(authApi, 'logoutApi').mockResolvedValueOnce()
|
|
|
|
await authStore.logout()
|
|
|
|
expect(logoutSpy).toHaveBeenCalledWith({ refresh_token: 'sample-refresh' })
|
|
expect(authStore.accessToken).toBeNull()
|
|
expect(authStore.refreshToken).toBeNull()
|
|
expect(authStore.isAuthenticated).toBe(false)
|
|
expect(localStorage.getItem('access_token')).toBeNull()
|
|
expect(localStorage.getItem('refresh_token')).toBeNull()
|
|
})
|
|
|
|
it('still clears tokens if logout API fails', async () => {
|
|
localStorage.setItem('access_token', 'sample-access')
|
|
localStorage.setItem('refresh_token', 'sample-refresh')
|
|
|
|
const authStore = useAuthStore()
|
|
vi.spyOn(authApi, 'logoutApi').mockRejectedValueOnce(new Error('Network error'))
|
|
|
|
await authStore.logout()
|
|
|
|
expect(authStore.accessToken).toBeNull()
|
|
expect(authStore.refreshToken).toBeNull()
|
|
expect(authStore.isAuthenticated).toBe(false)
|
|
expect(localStorage.getItem('access_token')).toBeNull()
|
|
expect(localStorage.getItem('refresh_token')).toBeNull()
|
|
})
|
|
|
|
it('clears tokens and calls logoutAll API on logoutAll', async () => {
|
|
localStorage.setItem('access_token', 'sample-access')
|
|
localStorage.setItem('refresh_token', 'sample-refresh')
|
|
|
|
const authStore = useAuthStore()
|
|
const logoutAllSpy = vi.spyOn(authApi, 'logoutAllApi').mockResolvedValueOnce()
|
|
|
|
await authStore.logoutAll()
|
|
|
|
expect(logoutAllSpy).toHaveBeenCalledWith('sample-access')
|
|
expect(authStore.accessToken).toBeNull()
|
|
expect(authStore.refreshToken).toBeNull()
|
|
expect(authStore.isAuthenticated).toBe(false)
|
|
expect(localStorage.getItem('access_token')).toBeNull()
|
|
expect(localStorage.getItem('refresh_token')).toBeNull()
|
|
})
|
|
|
|
it('still clears tokens if logoutAll API fails', async () => {
|
|
localStorage.setItem('access_token', 'sample-access')
|
|
localStorage.setItem('refresh_token', 'sample-refresh')
|
|
|
|
const authStore = useAuthStore()
|
|
vi.spyOn(authApi, 'logoutAllApi').mockRejectedValueOnce(new Error('Network error'))
|
|
|
|
await authStore.logoutAll()
|
|
|
|
expect(authStore.accessToken).toBeNull()
|
|
expect(authStore.refreshToken).toBeNull()
|
|
expect(authStore.isAuthenticated).toBe(false)
|
|
expect(localStorage.getItem('access_token')).toBeNull()
|
|
expect(localStorage.getItem('refresh_token')).toBeNull()
|
|
})
|
|
})
|