import { act, renderHook } from '@testing-library/react-native' import { useUserBalanceStore } from '@/stores/userBalanceStore' import { subscription } from '@/lib/auth' // Mock subscription API jest.mock('@/lib/auth', () => ({ subscription: { list: jest.fn(), }, })) // Mock AppState jest.mock('react-native', () => ({ AppState: { addEventListener: jest.fn(() => ({ remove: jest.fn() })), }, })) describe('userBalanceStore', () => { beforeEach(() => { // Reset store state before each test const { reset } = useUserBalanceStore.getState() reset() jest.clearAllMocks() }) describe('load', () => { it('should load balance from API', async () => { const mockData = [ { type: 'metered', creditBalance: { remainingTokenBalance: 1000, }, }, ] ;(subscription.list as jest.Mock).mockResolvedValue({ data: mockData }) const { load } = useUserBalanceStore.getState() await act(async () => { await load(true) }) const { balance } = useUserBalanceStore.getState() expect(balance).toBe(1000) }) it('should handle API error', async () => { const mockError = { message: 'API Error', status: 500, statusText: 'Internal Server Error' } ;(subscription.list as jest.Mock).mockResolvedValue({ error: mockError }) const { load } = useUserBalanceStore.getState() await act(async () => { await load(true) }) const { error } = useUserBalanceStore.getState() expect(error).toEqual(mockError) }) it('should debounce requests within 5 seconds', async () => { const mockData = [ { type: 'metered', creditBalance: { remainingTokenBalance: 500, }, }, ] ;(subscription.list as jest.Mock).mockResolvedValue({ data: mockData }) const { load } = useUserBalanceStore.getState() // First call await act(async () => { await load(false) }) // Second call within 5 seconds (should be skipped) await act(async () => { await load(false) }) // API should only be called once expect(subscription.list).toHaveBeenCalledTimes(1) }) it('should force load when force=true', async () => { const mockData = [ { type: 'metered', creditBalance: { remainingTokenBalance: 500, }, }, ] ;(subscription.list as jest.Mock).mockResolvedValue({ data: mockData }) const { load } = useUserBalanceStore.getState() // First call await act(async () => { await load(true) }) // Second call with force=true (should not be skipped) await act(async () => { await load(true) }) // API should be called twice expect(subscription.list).toHaveBeenCalledTimes(2) }) }) describe('setBalance', () => { it('should set balance directly', () => { const { setBalance } = useUserBalanceStore.getState() act(() => { setBalance(2000) }) const { balance } = useUserBalanceStore.getState() expect(balance).toBe(2000) }) }) describe('deductBalance', () => { it('should deduct balance', () => { const { setBalance, deductBalance } = useUserBalanceStore.getState() act(() => { setBalance(1000) deductBalance(300) }) const { balance } = useUserBalanceStore.getState() expect(balance).toBe(700) }) it('should not go below zero', () => { const { setBalance, deductBalance } = useUserBalanceStore.getState() act(() => { setBalance(100) deductBalance(500) }) const { balance } = useUserBalanceStore.getState() expect(balance).toBe(0) }) }) describe('reset', () => { it('should reset all state', () => { const { setBalance, reset } = useUserBalanceStore.getState() act(() => { setBalance(5000) }) expect(useUserBalanceStore.getState().balance).toBe(5000) act(() => { reset() }) const state = useUserBalanceStore.getState() expect(state.balance).toBe(0) expect(state.loading).toBe(false) expect(state.error).toBe(null) }) }) })