import { setOnchainKitConfig } from '@/core/OnchainKitConfig'; import { FundEvent } from '@/core/analytics/types'; import { render, screen, waitFor } from '@testing-library/react'; import { renderHook } from '@testing-library/react'; import { act } from 'react'; import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest'; import { quoteResponseDataMock } from '../mocks'; import { FundCardProvider, useFundContext } from './FundCardProvider'; global.fetch = vi.fn(() => Promise.resolve({ json: () => Promise.resolve(quoteResponseDataMock), }), ) as Mock; let mockSendAnalytics: Mock; vi.mock('@/core/analytics/hooks/useAnalytics', () => ({ useAnalytics: () => ({ sendAnalytics: mockSendAnalytics, }), })); const TestComponent = () => { const context = useFundContext(); return (
{context.asset} {context.exchangeRate} {context.exchangeRateLoading ? 'loading' : 'not-loading'}
); }; describe('FundCardProvider', () => { beforeEach(() => { setOnchainKitConfig({ apiKey: '123456789' }); vi.clearAllMocks(); }); describe('analytics', () => { beforeEach(() => { mockSendAnalytics = vi.fn(); }); it('tracks fund amount changes for fiat', async () => { const { result } = await act(async () => renderHook(() => useFundContext(), { wrapper: ({ children }) => ( {children} ), }), ); act(() => { result.current.setFundAmountFiat('100.00'); }); expect(mockSendAnalytics).toHaveBeenCalledWith( FundEvent.FundAmountChanged, { amount: 100, currency: 'USD', }, ); }); it('does not track fund amount changes when amount is invalid', async () => { const { result } = await act(async () => renderHook(() => useFundContext(), { wrapper: ({ children }) => ( {children} ), }), ); act(() => { result.current.setFundAmountFiat('invalid'); }); expect(mockSendAnalytics).not.toHaveBeenCalled(); }); it('tracks payment method selection', async () => { const { result } = await act(async () => renderHook(() => useFundContext(), { wrapper: ({ children }) => ( {children} ), }), ); const mockPaymentMethod = { id: 'debit_card', name: 'Debit Card', description: 'Pay with debit card', icon: 'card-icon', disabled: false, }; act(() => { result.current.setSelectedPaymentMethod(mockPaymentMethod); }); expect(mockSendAnalytics).toHaveBeenCalledWith( FundEvent.FundOptionSelected, { option: 'debit_card', }, ); }); it('handles fund amount changes with different currencies', async () => { const { result } = await act(async () => renderHook(() => useFundContext(), { wrapper: ({ children }) => ( {children} ), }), ); act(() => { result.current.setFundAmountFiat('50.00'); }); expect(mockSendAnalytics).toHaveBeenCalledWith( FundEvent.FundAmountChanged, { amount: 50, currency: 'GBP', }, ); }); }); it('provides default context values', async () => { await act(async () => { render( , ); }); expect(screen.getByTestId('selected-asset').textContent).toBe('BTC'); }); it('fetches and sets exchange rate on mount', async () => { act(() => { render( , ); }); // Check initial loading state expect(screen.getByTestId('loading-state').textContent).toBe('loading'); // Wait for exchange rate to be set await waitFor(() => { expect(screen.getByTestId('exchange-rate').textContent).toBe( '0.0008333333333333334', ); expect(screen.getByTestId('loading-state').textContent).toBe( 'not-loading', ); }); // Verify fetch was called with correct parameters expect(fetch).toHaveBeenCalledWith( expect.stringContaining('/quote'), expect.objectContaining({ method: 'POST', body: expect.stringContaining('"purchase_currency":"BTC"'), }), ); }); it('throws error when useFundContext is used outside of FundCardProvider', () => { const TestOutsideProvider = () => { useFundContext(); return
Test
; }; expect(() => render()).toThrow( 'useFundContext must be used within a FundCardProvider', ); }); it('handles exchange rate fetch error', async () => { const mockError = new Error('Failed to fetch exchange rate'); const mockOnError = vi.fn(); global.fetch = vi.fn(() => Promise.reject(mockError)) as Mock; render( , ); await waitFor(() => { expect(mockOnError).toHaveBeenCalledWith({ errorType: 'handled_error', code: 'EXCHANGE_RATE_ERROR', debugMessage: 'Failed to fetch exchange rate', }); }); }); });