Files
ComfyUI_frontend/tests-ui/tests/store/firebaseAuthStore.test.ts
2025-04-15 17:15:51 -04:00

276 lines
8.3 KiB
TypeScript

import * as firebaseAuth from 'firebase/auth'
import { createPinia, setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import * as vuefire from 'vuefire'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
vi.mock('vuefire', () => ({
useFirebaseAuth: vi.fn()
}))
vi.mock('firebase/auth', () => ({
signInWithEmailAndPassword: vi.fn(),
createUserWithEmailAndPassword: vi.fn(),
signOut: vi.fn(),
onAuthStateChanged: vi.fn()
}))
describe('useFirebaseAuthStore', () => {
let store: ReturnType<typeof useFirebaseAuthStore>
let authStateCallback: (user: any) => void
const mockAuth = {
/* mock Auth object */
}
const mockUser = {
uid: 'test-user-id',
email: 'test@example.com',
getIdToken: vi.fn().mockResolvedValue('mock-id-token')
}
beforeEach(() => {
vi.resetAllMocks()
// Mock useFirebaseAuth to return our mock auth object
vi.mocked(vuefire.useFirebaseAuth).mockReturnValue(mockAuth as any)
// Mock onAuthStateChanged to capture the callback and simulate initial auth state
vi.mocked(firebaseAuth.onAuthStateChanged).mockImplementation(
(_, callback) => {
authStateCallback = callback as (user: any) => void
// Call the callback with our mock user
;(callback as (user: any) => void)(mockUser)
// Return an unsubscribe function
return vi.fn()
}
)
// Initialize Pinia
setActivePinia(createPinia())
store = useFirebaseAuthStore()
})
it('should initialize with the current user', () => {
expect(store.currentUser).toEqual(mockUser)
expect(store.isAuthenticated).toBe(true)
expect(store.userEmail).toBe('test@example.com')
expect(store.userId).toBe('test-user-id')
expect(store.loading).toBe(false)
expect(store.error).toBe(null)
})
it('should properly clean up error state between operations', async () => {
// First, cause an error
const mockError = new Error('Invalid password')
vi.mocked(firebaseAuth.signInWithEmailAndPassword).mockRejectedValueOnce(
mockError
)
try {
await store.login('test@example.com', 'wrong-password')
} catch (e) {
// Error expected
}
expect(store.error).toBe('Invalid password')
// Now, succeed on next attempt
vi.mocked(firebaseAuth.signInWithEmailAndPassword).mockResolvedValueOnce({
user: mockUser
} as any)
await store.login('test@example.com', 'correct-password')
// Error should be cleared
expect(store.error).toBe(null)
})
it('should handle auth initialization failure', async () => {
// Mock auth as null to simulate initialization failure
vi.mocked(vuefire.useFirebaseAuth).mockReturnValue(null)
// Create a new store instance
setActivePinia(createPinia())
const uninitializedStore = useFirebaseAuthStore()
// Check that isInitialized is false
expect(uninitializedStore.isInitialized).toBe(false)
// Verify store actions throw appropriate errors
await expect(
uninitializedStore.login('test@example.com', 'password')
).rejects.toThrow('Firebase Auth not initialized')
})
describe('login', () => {
it('should login with valid credentials', async () => {
const mockUserCredential = { user: mockUser }
vi.mocked(firebaseAuth.signInWithEmailAndPassword).mockResolvedValue(
mockUserCredential as any
)
const result = await store.login('test@example.com', 'password')
expect(firebaseAuth.signInWithEmailAndPassword).toHaveBeenCalledWith(
mockAuth,
'test@example.com',
'password'
)
expect(result).toEqual(mockUserCredential)
expect(store.loading).toBe(false)
expect(store.error).toBe(null)
})
it('should handle login errors', async () => {
const mockError = new Error('Invalid password')
vi.mocked(firebaseAuth.signInWithEmailAndPassword).mockRejectedValue(
mockError
)
await expect(
store.login('test@example.com', 'wrong-password')
).rejects.toThrow('Invalid password')
expect(firebaseAuth.signInWithEmailAndPassword).toHaveBeenCalledWith(
mockAuth,
'test@example.com',
'wrong-password'
)
expect(store.loading).toBe(false)
expect(store.error).toBe('Invalid password')
})
})
describe('register', () => {
it('should register a new user', async () => {
const mockUserCredential = { user: mockUser }
vi.mocked(firebaseAuth.createUserWithEmailAndPassword).mockResolvedValue(
mockUserCredential as any
)
const result = await store.register('new@example.com', 'password')
expect(firebaseAuth.createUserWithEmailAndPassword).toHaveBeenCalledWith(
mockAuth,
'new@example.com',
'password'
)
expect(result).toEqual(mockUserCredential)
expect(store.loading).toBe(false)
expect(store.error).toBe(null)
})
it('should handle registration errors', async () => {
const mockError = new Error('Email already in use')
vi.mocked(firebaseAuth.createUserWithEmailAndPassword).mockRejectedValue(
mockError
)
await expect(
store.register('existing@example.com', 'password')
).rejects.toThrow('Email already in use')
expect(firebaseAuth.createUserWithEmailAndPassword).toHaveBeenCalledWith(
mockAuth,
'existing@example.com',
'password'
)
expect(store.loading).toBe(false)
expect(store.error).toBe('Email already in use')
})
it('should handle concurrent login attempts correctly', async () => {
// Set up multiple login promises
const mockUserCredential = { user: mockUser }
vi.mocked(firebaseAuth.signInWithEmailAndPassword).mockResolvedValue(
mockUserCredential as any
)
const loginPromise1 = store.login('user1@example.com', 'password1')
const loginPromise2 = store.login('user2@example.com', 'password2')
// Resolve both promises
await Promise.all([loginPromise1, loginPromise2])
// Verify the loading state is reset
expect(store.loading).toBe(false)
})
})
describe('logout', () => {
it('should sign out the user', async () => {
vi.mocked(firebaseAuth.signOut).mockResolvedValue(undefined)
await store.logout()
expect(firebaseAuth.signOut).toHaveBeenCalledWith(mockAuth)
})
it('should handle logout errors', async () => {
const mockError = new Error('Network error')
vi.mocked(firebaseAuth.signOut).mockRejectedValue(mockError)
await expect(store.logout()).rejects.toThrow('Network error')
expect(firebaseAuth.signOut).toHaveBeenCalledWith(mockAuth)
expect(store.error).toBe('Network error')
})
})
describe('getIdToken', () => {
it('should return the user ID token', async () => {
// FIX 2: Reset the mock and set a specific return value
mockUser.getIdToken.mockReset()
mockUser.getIdToken.mockResolvedValue('mock-id-token')
const token = await store.getIdToken()
expect(mockUser.getIdToken).toHaveBeenCalled()
expect(token).toBe('mock-id-token')
})
it('should return null when no user is logged in', async () => {
// Simulate logged out state
authStateCallback(null)
const token = await store.getIdToken()
expect(token).toBeNull()
})
it('should return null for token after login and logout sequence', async () => {
// Setup mock for login
const mockUserCredential = { user: mockUser }
vi.mocked(firebaseAuth.signInWithEmailAndPassword).mockResolvedValue(
mockUserCredential as any
)
// Login
await store.login('test@example.com', 'password')
// Simulate successful auth state update after login
authStateCallback(mockUser)
// Verify we're logged in and can get a token
mockUser.getIdToken.mockReset()
mockUser.getIdToken.mockResolvedValue('mock-id-token')
expect(await store.getIdToken()).toBe('mock-id-token')
// Setup mock for logout
vi.mocked(firebaseAuth.signOut).mockResolvedValue(undefined)
// Logout
await store.logout()
// Simulate successful auth state update after logout
authStateCallback(null)
// Verify token is null after logout
const tokenAfterLogout = await store.getIdToken()
expect(tokenAfterLogout).toBeNull()
})
})
})