263 lines
7.2 KiB
TypeScript
263 lines
7.2 KiB
TypeScript
/**
|
|
* Auth Store Tests
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { useAuthStore } from '../stores/auth.store';
|
|
import type { User, Tenant, Session } from '../types';
|
|
|
|
// Mock user data
|
|
const mockUser: User = {
|
|
id: 'user-123',
|
|
tenantId: 'tenant-456',
|
|
email: 'test@example.com',
|
|
firstName: 'John',
|
|
lastName: 'Doe',
|
|
displayName: 'John Doe',
|
|
avatarUrl: null,
|
|
phone: null,
|
|
status: 'active',
|
|
isOwner: true,
|
|
emailVerified: true,
|
|
emailVerifiedAt: '2024-01-01T00:00:00Z',
|
|
phoneVerified: false,
|
|
phoneVerifiedAt: null,
|
|
mfaEnabled: false,
|
|
passwordChangedAt: '2024-01-01T00:00:00Z',
|
|
failedLoginAttempts: 0,
|
|
lockedUntil: null,
|
|
lastLoginAt: '2024-01-10T12:00:00Z',
|
|
lastLoginIp: '192.168.1.1',
|
|
preferences: {
|
|
theme: 'dark',
|
|
language: 'en',
|
|
notifications: { email: true, push: true, sms: false },
|
|
},
|
|
createdAt: '2024-01-01T00:00:00Z',
|
|
updatedAt: '2024-01-10T12:00:00Z',
|
|
};
|
|
|
|
const mockTenant: Tenant = {
|
|
id: 'tenant-456',
|
|
name: 'Test Org',
|
|
slug: 'test-org',
|
|
status: 'active',
|
|
};
|
|
|
|
const mockSession: Session = {
|
|
id: 'session-789',
|
|
deviceType: 'desktop',
|
|
deviceName: 'Chrome on Windows',
|
|
browser: 'Chrome',
|
|
browserVersion: '120',
|
|
os: 'Windows',
|
|
osVersion: '11',
|
|
ipAddress: '192.168.1.1',
|
|
lastActiveAt: '2024-01-10T12:00:00Z',
|
|
expiresAt: '2024-01-17T12:00:00Z',
|
|
createdAt: '2024-01-10T12:00:00Z',
|
|
};
|
|
|
|
describe('Auth Store', () => {
|
|
beforeEach(() => {
|
|
// Reset store to initial state
|
|
useAuthStore.getState().reset();
|
|
localStorage.clear();
|
|
});
|
|
|
|
describe('Initial State', () => {
|
|
it('should have correct initial state', () => {
|
|
const state = useAuthStore.getState();
|
|
|
|
expect(state.user).toBeNull();
|
|
expect(state.tenant).toBeNull();
|
|
expect(state.session).toBeNull();
|
|
expect(state.isAuthenticated).toBe(false);
|
|
expect(state.isLoading).toBe(false);
|
|
expect(state.error).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('setUser', () => {
|
|
it('should set user', () => {
|
|
useAuthStore.getState().setUser(mockUser);
|
|
|
|
expect(useAuthStore.getState().user).toEqual(mockUser);
|
|
});
|
|
|
|
it('should clear user when set to null', () => {
|
|
useAuthStore.getState().setUser(mockUser);
|
|
useAuthStore.getState().setUser(null);
|
|
|
|
expect(useAuthStore.getState().user).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('setTenant', () => {
|
|
it('should set tenant', () => {
|
|
useAuthStore.getState().setTenant(mockTenant);
|
|
|
|
expect(useAuthStore.getState().tenant).toEqual(mockTenant);
|
|
});
|
|
});
|
|
|
|
describe('setSession', () => {
|
|
it('should set session', () => {
|
|
useAuthStore.getState().setSession(mockSession);
|
|
|
|
expect(useAuthStore.getState().session).toEqual(mockSession);
|
|
});
|
|
});
|
|
|
|
describe('setAuthenticated', () => {
|
|
it('should set authenticated state', () => {
|
|
useAuthStore.getState().setAuthenticated(true);
|
|
|
|
expect(useAuthStore.getState().isAuthenticated).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('setLoading', () => {
|
|
it('should set loading state', () => {
|
|
useAuthStore.getState().setLoading(true);
|
|
|
|
expect(useAuthStore.getState().isLoading).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('setError', () => {
|
|
it('should set error', () => {
|
|
useAuthStore.getState().setError('Test error');
|
|
|
|
expect(useAuthStore.getState().error).toBe('Test error');
|
|
});
|
|
|
|
it('should clear error when set to null', () => {
|
|
useAuthStore.getState().setError('Test error');
|
|
useAuthStore.getState().setError(null);
|
|
|
|
expect(useAuthStore.getState().error).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('login', () => {
|
|
it('should set all auth state and store tokens', () => {
|
|
const accessToken = 'access-token-123';
|
|
const refreshToken = 'refresh-token-456';
|
|
|
|
useAuthStore.getState().login(mockUser, mockTenant, mockSession, accessToken, refreshToken);
|
|
|
|
const state = useAuthStore.getState();
|
|
|
|
expect(state.user).toEqual(mockUser);
|
|
expect(state.tenant).toEqual(mockTenant);
|
|
expect(state.session).toEqual(mockSession);
|
|
expect(state.isAuthenticated).toBe(true);
|
|
expect(state.isLoading).toBe(false);
|
|
expect(state.error).toBeNull();
|
|
|
|
// Verify tokens stored in localStorage
|
|
expect(localStorage.getItem('accessToken')).toBe(accessToken);
|
|
expect(localStorage.getItem('refreshToken')).toBe(refreshToken);
|
|
expect(localStorage.getItem('tenantId')).toBe(mockTenant.id);
|
|
expect(localStorage.getItem('userId')).toBe(mockUser.id);
|
|
});
|
|
});
|
|
|
|
describe('logout', () => {
|
|
it('should clear all auth state and tokens', () => {
|
|
// First login
|
|
useAuthStore.getState().login(mockUser, mockTenant, mockSession, 'access', 'refresh');
|
|
|
|
// Then logout
|
|
useAuthStore.getState().logout();
|
|
|
|
const state = useAuthStore.getState();
|
|
|
|
expect(state.user).toBeNull();
|
|
expect(state.tenant).toBeNull();
|
|
expect(state.session).toBeNull();
|
|
expect(state.isAuthenticated).toBe(false);
|
|
|
|
// Verify tokens removed from localStorage
|
|
expect(localStorage.getItem('accessToken')).toBeNull();
|
|
expect(localStorage.getItem('refreshToken')).toBeNull();
|
|
expect(localStorage.getItem('tenantId')).toBeNull();
|
|
expect(localStorage.getItem('userId')).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('updateUser', () => {
|
|
it('should update user properties', () => {
|
|
useAuthStore.getState().setUser(mockUser);
|
|
|
|
useAuthStore.getState().updateUser({
|
|
firstName: 'Jane',
|
|
displayName: 'Jane Doe',
|
|
});
|
|
|
|
const user = useAuthStore.getState().user;
|
|
|
|
expect(user?.firstName).toBe('Jane');
|
|
expect(user?.displayName).toBe('Jane Doe');
|
|
expect(user?.lastName).toBe('Doe'); // Unchanged
|
|
expect(user?.email).toBe('test@example.com'); // Unchanged
|
|
});
|
|
|
|
it('should not update if no user exists', () => {
|
|
useAuthStore.getState().updateUser({ firstName: 'Jane' });
|
|
|
|
expect(useAuthStore.getState().user).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('reset', () => {
|
|
it('should reset to initial state', () => {
|
|
// Set some state
|
|
useAuthStore.getState().setUser(mockUser);
|
|
useAuthStore.getState().setTenant(mockTenant);
|
|
useAuthStore.getState().setAuthenticated(true);
|
|
useAuthStore.getState().setError('Some error');
|
|
|
|
// Reset
|
|
useAuthStore.getState().reset();
|
|
|
|
const state = useAuthStore.getState();
|
|
|
|
expect(state.user).toBeNull();
|
|
expect(state.tenant).toBeNull();
|
|
expect(state.isAuthenticated).toBe(false);
|
|
expect(state.error).toBeNull();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Auth Store Selectors', () => {
|
|
beforeEach(() => {
|
|
useAuthStore.getState().reset();
|
|
});
|
|
|
|
it('useUser should return user', () => {
|
|
useAuthStore.getState().setUser(mockUser);
|
|
|
|
// Access via selector pattern
|
|
const user = useAuthStore.getState().user;
|
|
expect(user).toEqual(mockUser);
|
|
});
|
|
|
|
it('useTenant should return tenant', () => {
|
|
useAuthStore.getState().setTenant(mockTenant);
|
|
|
|
const tenant = useAuthStore.getState().tenant;
|
|
expect(tenant).toEqual(mockTenant);
|
|
});
|
|
|
|
it('useIsAuthenticated should return authentication state', () => {
|
|
expect(useAuthStore.getState().isAuthenticated).toBe(false);
|
|
|
|
useAuthStore.getState().setAuthenticated(true);
|
|
|
|
expect(useAuthStore.getState().isAuthenticated).toBe(true);
|
|
});
|
|
});
|