diff --git a/src/store/__tests__/cartStore.test.ts b/src/store/__tests__/cartStore.test.ts new file mode 100644 index 00000000..ff088f70 --- /dev/null +++ b/src/store/__tests__/cartStore.test.ts @@ -0,0 +1,200 @@ +import { act, renderHook } from '@testing-library/react'; +import { useCartStore } from '../cartStore'; +import type { Property } from '@/types/property'; + +const mockProperty = (id: string, perToken: number, available = 10): Property => ({ + id, + name: `Property ${id}`, + description: 'A test property', + location: { + address: '1 Test St', + city: 'Testville', + state: 'TS', + country: 'Testland', + zipCode: '00000', + coordinates: { lat: 0, lng: 0 }, + }, + price: { total: perToken * 100, perToken, currency: 'USD' }, + propertyType: 'residential', + blockchain: 'ethereum', + tokenInfo: { + totalSupply: 1000, + available, + sold: 100, + contractAddress: '0x1234...5678', + tokenSymbol: 'TST', + }, + metrics: { + roi: 8, + annualReturn: 8000, + transactionVolume: 50000, + appreciationRate: 5, + }, + details: { squareFeet: 1000, yearBuilt: 2020, amenities: [] }, + images: [], + listedDate: '2024-01-01', + status: 'active', +}); + +describe('cartStore', () => { + beforeEach(() => { + localStorage.clear(); + useCartStore.getState().clearCart(); + useCartStore.setState({ isOpen: false, slippageTolerance: 0.005 }); + }); + + it('starts with an empty cart and zero totals', () => { + const { result } = renderHook(() => useCartStore()); + expect(result.current.items).toEqual([]); + expect(result.current.totalCost).toBe(0); + expect(result.current.totalGasEstimate).toBe(0); + expect(result.current.isOpen).toBe(false); + expect(result.current.slippageTolerance).toBe(0.005); + }); + + it('adds an item and computes the total cost', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100), 2); + }); + + expect(result.current.items).toHaveLength(1); + expect(result.current.items[0].quantity).toBe(2); + expect(result.current.totalCost).toBe(200); + // 1 item: 0.005 base + 1 * 0.0025 + expect(result.current.totalGasEstimate).toBeCloseTo(0.0075); + }); + + it('caps the quantity at the available supply', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100, 5), 50); + }); + + expect(result.current.items[0].quantity).toBe(5); + expect(result.current.totalCost).toBe(500); + }); + + it('increments quantity for duplicate adds, capped at availability', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100, 10), 4); + result.current.addItem(mockProperty('prop-1', 100, 10), 4); + }); + + expect(result.current.items).toHaveLength(1); + expect(result.current.items[0].quantity).toBe(8); + expect(result.current.totalCost).toBe(800); + + // A third add pushes past availability → capped at 10. + act(() => { + result.current.addItem(mockProperty('prop-1', 100, 10), 4); + }); + + expect(result.current.items[0].quantity).toBe(10); + expect(result.current.totalCost).toBe(1000); + }); + + it('removes an item and recomputes totals', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100), 2); + result.current.addItem(mockProperty('prop-2', 50), 1); + result.current.removeItem('prop-1'); + }); + + expect(result.current.items).toHaveLength(1); + expect(result.current.items[0].id).toBe('prop-2'); + expect(result.current.totalCost).toBe(50); + }); + + it('updates the quantity of an item', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100), 2); + result.current.updateQuantity('prop-1', 5); + }); + + expect(result.current.items[0].quantity).toBe(5); + expect(result.current.totalCost).toBe(500); + }); + + it('clamps quantity updates to the available supply', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100, 6), 2); + result.current.updateQuantity('prop-1', 99); + }); + + expect(result.current.items[0].quantity).toBe(6); + }); + + it('removes an item when its quantity is set to zero', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100), 2); + result.current.updateQuantity('prop-1', 0); + }); + + expect(result.current.items).toEqual([]); + expect(result.current.totalCost).toBe(0); + expect(result.current.totalGasEstimate).toBe(0); + }); + + it('clearCart resets items and totals', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100), 2); + result.current.clearCart(); + }); + + expect(result.current.items).toEqual([]); + expect(result.current.totalCost).toBe(0); + expect(result.current.totalGasEstimate).toBe(0); + }); + + it('toggles the cart open state', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => result.current.toggleCart()); + expect(result.current.isOpen).toBe(true); + + act(() => result.current.toggleCart()); + expect(result.current.isOpen).toBe(false); + }); + + it('calculateTotals reflects the current items', () => { + const { result } = renderHook(() => useCartStore()); + + expect(result.current.calculateTotals()).toEqual({ totalCost: 0, totalGasEstimate: 0 }); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100), 1); + result.current.addItem(mockProperty('prop-2', 50), 2); + }); + + expect(result.current.calculateTotals().totalCost).toBe(200); + // 2 items: 0.005 base + 2 * 0.0025 + expect(result.current.calculateTotals().totalGasEstimate).toBeCloseTo(0.01); + }); + + it('persists items across store instances', () => { + const { result } = renderHook(() => useCartStore()); + + act(() => { + result.current.addItem(mockProperty('prop-1', 100), 2); + }); + + const { result: result2 } = renderHook(() => useCartStore()); + expect(result2.current.items).toHaveLength(1); + expect(result2.current.items[0].quantity).toBe(2); + }); +}); diff --git a/src/store/__tests__/compareStore.test.ts b/src/store/__tests__/compareStore.test.ts new file mode 100644 index 00000000..bb698adc --- /dev/null +++ b/src/store/__tests__/compareStore.test.ts @@ -0,0 +1,119 @@ +import { act, renderHook } from '@testing-library/react'; +import { useCompareStore } from '../compareStore'; + +describe('compareStore', () => { + beforeEach(() => { + localStorage.clear(); + useCompareStore.getState().clearCompare(); + }); + + it('starts with no selected properties', () => { + const { result } = renderHook(() => useCompareStore()); + expect(result.current.selectedIds).toEqual([]); + }); + + it('adds a property to the selection', () => { + const { result } = renderHook(() => useCompareStore()); + + act(() => { + result.current.addProperty('prop-1'); + }); + + expect(result.current.selectedIds).toEqual(['prop-1']); + }); + + it('does not add a duplicate property', () => { + const { result } = renderHook(() => useCompareStore()); + + act(() => { + result.current.addProperty('prop-1'); + result.current.addProperty('prop-1'); + }); + + expect(result.current.selectedIds).toEqual(['prop-1']); + }); + + it('limits the selection to 3 properties', () => { + const { result } = renderHook(() => useCompareStore()); + + act(() => { + result.current.addProperty('prop-1'); + result.current.addProperty('prop-2'); + result.current.addProperty('prop-3'); + result.current.addProperty('prop-4'); + }); + + expect(result.current.selectedIds).toEqual(['prop-1', 'prop-2', 'prop-3']); + }); + + it('removes a property from the selection', () => { + const { result } = renderHook(() => useCompareStore()); + + act(() => { + result.current.addProperty('prop-1'); + result.current.addProperty('prop-2'); + result.current.removeProperty('prop-1'); + }); + + expect(result.current.selectedIds).toEqual(['prop-2']); + }); + + it('toggles a property in and out of the selection', () => { + const { result } = renderHook(() => useCompareStore()); + + act(() => { + result.current.toggleProperty('prop-1'); + }); + expect(result.current.selectedIds).toEqual(['prop-1']); + + act(() => { + result.current.toggleProperty('prop-1'); + }); + expect(result.current.selectedIds).toEqual([]); + }); + + it('does not toggle beyond the 3-property limit', () => { + const { result } = renderHook(() => useCompareStore()); + + act(() => { + result.current.addProperty('prop-1'); + result.current.addProperty('prop-2'); + result.current.addProperty('prop-3'); + result.current.toggleProperty('prop-4'); + }); + + expect(result.current.selectedIds).toEqual(['prop-1', 'prop-2', 'prop-3']); + }); + + it('setSelectedIds replaces the selection and clamps to 3', () => { + const { result } = renderHook(() => useCompareStore()); + + act(() => { + result.current.setSelectedIds(['a', 'b', 'c', 'd', 'e']); + }); + + expect(result.current.selectedIds).toEqual(['a', 'b', 'c']); + }); + + it('clearCompare empties the selection', () => { + const { result } = renderHook(() => useCompareStore()); + + act(() => { + result.current.addProperty('prop-1'); + result.current.clearCompare(); + }); + + expect(result.current.selectedIds).toEqual([]); + }); + + it('persists the selection across store instances', () => { + const { result } = renderHook(() => useCompareStore()); + + act(() => { + result.current.addProperty('prop-1'); + }); + + const { result: result2 } = renderHook(() => useCompareStore()); + expect(result2.current.selectedIds).toEqual(['prop-1']); + }); +}); diff --git a/src/store/__tests__/comparisonHistoryStore.test.ts b/src/store/__tests__/comparisonHistoryStore.test.ts new file mode 100644 index 00000000..b0de39da --- /dev/null +++ b/src/store/__tests__/comparisonHistoryStore.test.ts @@ -0,0 +1,94 @@ +import { act, renderHook } from '@testing-library/react'; +import { useComparisonHistoryStore } from '../comparisonHistoryStore'; + +describe('comparisonHistoryStore', () => { + beforeEach(() => { + localStorage.clear(); + useComparisonHistoryStore.getState().clearHistory(); + }); + + it('starts with an empty history', () => { + const { result } = renderHook(() => useComparisonHistoryStore()); + expect(result.current.getHistory()).toEqual([]); + }); + + it('records a comparison with a share URL', () => { + const { result } = renderHook(() => useComparisonHistoryStore()); + + act(() => { + result.current.addComparison(['prop-1', 'prop-2']); + }); + + const history = result.current.getHistory(); + expect(history).toHaveLength(1); + expect(history[0].propertyIds).toEqual(['prop-1', 'prop-2']); + expect(history[0].shareUrl).toBe('/compare?ids=prop-1,prop-2'); + expect(history[0].timestamp).toBeGreaterThan(0); + }); + + it('ignores empty comparison requests', () => { + const { result } = renderHook(() => useComparisonHistoryStore()); + + act(() => { + result.current.addComparison([]); + }); + + expect(result.current.getHistory()).toEqual([]); + }); + + it('caps the history at 5 entries, evicting the oldest', () => { + const { result } = renderHook(() => useComparisonHistoryStore()); + + act(() => { + for (let i = 1; i <= 6; i++) { + result.current.addComparison([`prop-${i}`]); + } + }); + + const history = result.current.getHistory(); + expect(history).toHaveLength(5); + expect(history[0].propertyIds).toEqual(['prop-6']); + expect(history[4].propertyIds).toEqual(['prop-2']); + }); + + it('removes a single comparison entry', () => { + const { result } = renderHook(() => useComparisonHistoryStore()); + + act(() => { + result.current.addComparison(['prop-1']); + result.current.addComparison(['prop-2']); + }); + + const firstId = result.current.getHistory()[0].id; + act(() => { + result.current.removeComparison(firstId); + }); + + const history = result.current.getHistory(); + expect(history).toHaveLength(1); + expect(history[0].propertyIds).toEqual(['prop-1']); + }); + + it('clearHistory empties the history', () => { + const { result } = renderHook(() => useComparisonHistoryStore()); + + act(() => { + result.current.addComparison(['prop-1']); + result.current.clearHistory(); + }); + + expect(result.current.getHistory()).toEqual([]); + }); + + it('persists the history across store instances', () => { + const { result } = renderHook(() => useComparisonHistoryStore()); + + act(() => { + result.current.addComparison(['prop-1', 'prop-2']); + }); + + const { result: result2 } = renderHook(() => useComparisonHistoryStore()); + expect(result2.current.getHistory()).toHaveLength(1); + expect(result2.current.getHistory()[0].propertyIds).toEqual(['prop-1', 'prop-2']); + }); +}); diff --git a/src/store/__tests__/comparisonStore.test.ts b/src/store/__tests__/comparisonStore.test.ts new file mode 100644 index 00000000..7cfcb18a --- /dev/null +++ b/src/store/__tests__/comparisonStore.test.ts @@ -0,0 +1,159 @@ +import { act, renderHook } from '@testing-library/react'; +import { useComparisonStore } from '../comparisonStore'; +import type { Property } from '@/types/property'; + +const mockProperty = (id: string): Property => ({ + id, + name: `Property ${id}`, + description: 'A test property', + location: { + address: '1 Test St', + city: 'Testville', + state: 'TS', + country: 'Testland', + zipCode: '00000', + coordinates: { lat: 0, lng: 0 }, + }, + price: { total: 100000, perToken: 100, currency: 'USD' }, + propertyType: 'residential', + blockchain: 'ethereum', + tokenInfo: { + totalSupply: 1000, + available: 900, + sold: 100, + contractAddress: '0x1234...5678', + tokenSymbol: 'TST', + }, + metrics: { + roi: 8, + annualReturn: 8000, + transactionVolume: 50000, + appreciationRate: 5, + }, + details: { squareFeet: 1000, yearBuilt: 2020, amenities: [] }, + images: [], + listedDate: '2024-01-01', + status: 'active', +}); + +describe('comparisonStore', () => { + beforeEach(() => { + localStorage.clear(); + useComparisonStore.getState().clearProperties(); + }); + + it('starts with no selected properties and a max of 3', () => { + const { result } = renderHook(() => useComparisonStore()); + expect(result.current.selectedProperties).toEqual([]); + expect(result.current.maxProperties).toBe(3); + }); + + it('adds a property to the selection', () => { + const { result } = renderHook(() => useComparisonStore()); + + act(() => { + result.current.addProperty(mockProperty('prop-1')); + }); + + expect(result.current.selectedProperties).toHaveLength(1); + expect(result.current.selectedProperties[0].id).toBe('prop-1'); + }); + + it('does not add a property twice', () => { + const { result } = renderHook(() => useComparisonStore()); + + act(() => { + result.current.addProperty(mockProperty('prop-1')); + result.current.addProperty(mockProperty('prop-1')); + }); + + expect(result.current.selectedProperties).toHaveLength(1); + }); + + it('stops adding once the max is reached', () => { + const { result } = renderHook(() => useComparisonStore()); + + act(() => { + result.current.addProperty(mockProperty('prop-1')); + result.current.addProperty(mockProperty('prop-2')); + result.current.addProperty(mockProperty('prop-3')); + result.current.addProperty(mockProperty('prop-4')); + }); + + expect(result.current.selectedProperties).toHaveLength(3); + }); + + it('removes a property from the selection', () => { + const { result } = renderHook(() => useComparisonStore()); + + act(() => { + result.current.addProperty(mockProperty('prop-1')); + result.current.addProperty(mockProperty('prop-2')); + result.current.removeProperty(mockProperty('prop-1')); + }); + + expect(result.current.selectedProperties).toHaveLength(1); + expect(result.current.selectedProperties[0].id).toBe('prop-2'); + }); + + it('reports whether a property is selected', () => { + const { result } = renderHook(() => useComparisonStore()); + + act(() => { + result.current.addProperty(mockProperty('prop-1')); + }); + + expect(result.current.isPropertySelected('prop-1')).toBe(true); + expect(result.current.isPropertySelected('prop-2')).toBe(false); + }); + + it('toggles a property in and out of the selection', () => { + const { result } = renderHook(() => useComparisonStore()); + + act(() => { + result.current.toggleProperty(mockProperty('prop-1')); + }); + expect(result.current.isPropertySelected('prop-1')).toBe(true); + + act(() => { + result.current.toggleProperty(mockProperty('prop-1')); + }); + expect(result.current.isPropertySelected('prop-1')).toBe(false); + }); + + it('does not toggle beyond the max selection size', () => { + const { result } = renderHook(() => useComparisonStore()); + + act(() => { + result.current.addProperty(mockProperty('prop-1')); + result.current.addProperty(mockProperty('prop-2')); + result.current.addProperty(mockProperty('prop-3')); + result.current.toggleProperty(mockProperty('prop-4')); + }); + + expect(result.current.selectedProperties).toHaveLength(3); + }); + + it('clearProperties empties the selection', () => { + const { result } = renderHook(() => useComparisonStore()); + + act(() => { + result.current.addProperty(mockProperty('prop-1')); + result.current.clearProperties(); + }); + + expect(result.current.selectedProperties).toEqual([]); + }); + + it('persists the selection across store instances', () => { + const { result } = renderHook(() => useComparisonStore()); + + act(() => { + result.current.addProperty(mockProperty('prop-1')); + }); + + const { result: result2 } = renderHook(() => useComparisonStore()); + expect(result2.current.selectedProperties).toHaveLength(1); + expect(result2.current.selectedProperties[0].id).toBe('prop-1'); + }); +}); diff --git a/src/store/__tests__/referralStore.test.ts b/src/store/__tests__/referralStore.test.ts new file mode 100644 index 00000000..9674fc05 --- /dev/null +++ b/src/store/__tests__/referralStore.test.ts @@ -0,0 +1,236 @@ +import { act, renderHook } from '@testing-library/react'; +import { useReferralStore } from '../referral/store'; +import type { + ReferralLink, + ReferralStats, + ReferralReward, + LeaderboardEntry, + ReferralCampaign, +} from '@/types/referral'; +import { ReferralRewardStatus, ReferralTier } from '@/types/referral'; + +const address = '0xAbCd1234567890AbCd1234567890AbCd12345678' as const; + +const mockLink = (code: string): ReferralLink => ({ + code: code as ReferralLink['code'], + referrerId: address as ReferralLink['referrerId'], + url: `https://propchain.app/r/${code}`, + createdAt: Date.now(), + isActive: true, +}); + +const mockStats = (): ReferralStats => ({ + referrerId: address as ReferralStats['referrerId'], + totalClicks: 10, + totalSignups: 4, + totalRewardsEarned: '4000000000000000000', + totalRewardsClaimed: '1000000000000000000', + pendingRewards: '3000000000000000000', + conversionRate: 40, + tier: ReferralTier.BRONZE, + referralsSinceReset: 4, + lastActivityAt: Date.now(), + joinedAt: Date.now(), +}); + +const mockReward = (id: string): ReferralReward => ({ + id, + referrerId: address as ReferralReward['referrerId'], + refereeId: '0xOtherWallet1234567890OtherWallet1234567890' as ReferralReward['refereeId'], + referralCode: 'ABC123' as ReferralReward['referralCode'], + rewardAmount: '1000000000000000000', + rewardToken: '0xToken', + status: ReferralRewardStatus.PENDING, + chainId: 1, + createdAt: Date.now(), +}); + +const mockLeaderboardEntry = (rank: number): LeaderboardEntry => ({ + rank, + referrerId: address as LeaderboardEntry['referrerId'], + displayName: 'Alice', + totalRewardsEarned: '5000000000000000000', + totalSignups: 8, + tier: ReferralTier.SILVER, + recentActivityScore: 90, +}); + +describe('referralStore', () => { + beforeEach(() => { + localStorage.clear(); + useReferralStore.getState().reset(); + }); + + it('starts in the empty initial state', () => { + const { result } = renderHook(() => useReferralStore()); + expect(result.current.referrerId).toBeNull(); + expect(result.current.currentReferralLinks).toEqual([]); + expect(result.current.currentStats).toBeNull(); + expect(result.current.recentRewards).toEqual([]); + expect(result.current.leaderboardCache).toEqual([]); + expect(result.current.termsAccepted).toBe(false); + }); + + it('initializes with a referrer address', async () => { + const { result } = renderHook(() => useReferralStore()); + + await act(async () => { + await result.current.initialize(address as never); + }); + + expect(result.current.referrerId).toBe(address); + expect(result.current.isLoading).toBe(false); + expect(result.current.lastUpdated).not.toBeNull(); + }); + + it('adds, removes and replaces referral links', () => { + const { result } = renderHook(() => useReferralStore()); + + act(() => { + result.current.addReferralLink(mockLink('CODE1')); + result.current.addReferralLink(mockLink('CODE2')); + }); + expect(result.current.currentReferralLinks).toHaveLength(2); + + act(() => { + result.current.removeReferralLink('CODE1' as never); + }); + expect(result.current.currentReferralLinks).toHaveLength(1); + expect(result.current.currentReferralLinks[0].code).toBe('CODE2'); + + act(() => { + result.current.updateReferralLinks([mockLink('CODE3')]); + }); + expect(result.current.currentReferralLinks).toHaveLength(1); + expect(result.current.currentReferralLinks[0].code).toBe('CODE3'); + }); + + it('tracks the selected referral code', () => { + const { result } = renderHook(() => useReferralStore()); + + act(() => { + result.current.setSelectedReferralCode('CODE1' as never); + }); + + expect(result.current.selectedReferralCode).toBe('CODE1'); + + act(() => { + result.current.setSelectedReferralCode(null); + }); + expect(result.current.selectedReferralCode).toBeNull(); + }); + + it('updates stats and stamps the lastUpdated timestamp', () => { + const { result } = renderHook(() => useReferralStore()); + + act(() => { + result.current.updateStats(mockStats()); + }); + + expect(result.current.currentStats?.totalSignups).toBe(4); + expect(result.current.currentStats?.conversionRate).toBe(40); + expect(result.current.lastUpdated).not.toBeNull(); + }); + + it('adds rewards to the top of the recent feed', () => { + const { result } = renderHook(() => useReferralStore()); + + act(() => { + result.current.addReward(mockReward('r-1')); + result.current.addReward(mockReward('r-2')); + }); + + expect(result.current.recentRewards).toHaveLength(2); + expect(result.current.recentRewards[0].id).toBe('r-2'); + }); + + it('caps the recent rewards feed at 10 entries', () => { + const { result } = renderHook(() => useReferralStore()); + + act(() => { + for (let i = 1; i <= 12; i++) { + result.current.addReward(mockReward(`r-${i}`)); + } + }); + + expect(result.current.recentRewards).toHaveLength(10); + expect(result.current.recentRewards[0].id).toBe('r-12'); + }); + + it('updates the leaderboard cache', () => { + const { result } = renderHook(() => useReferralStore()); + + act(() => { + result.current.updateLeaderboard([mockLeaderboardEntry(1), mockLeaderboardEntry(2)]); + }); + + expect(result.current.leaderboardCache).toHaveLength(2); + expect(result.current.lastLeaderboardUpdate).not.toBeNull(); + }); + + it('tracks terms acceptance and program settings', () => { + const { result } = renderHook(() => useReferralStore()); + + act(() => { + result.current.updateTermsAccepted(true); + result.current.setProgramSettings({ isEnabled: true, minSignupsForReward: 1 }); + }); + + expect(result.current.termsAccepted).toBe(true); + expect(result.current.programSettings).toEqual({ isEnabled: true, minSignupsForReward: 1 }); + }); + + it('sets the dashboard data bundle', () => { + const { result } = renderHook(() => useReferralStore()); + + act(() => { + result.current.setDashboardData({ + referrerId: address as never, + stats: mockStats(), + referralLinks: [mockLink('CODE1')], + recentRewards: [mockReward('r-1')], + leaderboardPosition: mockLeaderboardEntry(1), + }); + }); + + expect(result.current.currentStats?.totalSignups).toBe(4); + expect(result.current.currentReferralLinks).toHaveLength(1); + expect(result.current.recentRewards).toHaveLength(1); + expect(result.current.leaderboardCache).toHaveLength(1); + }); + + it('auto-clears notifications after five seconds', () => { + jest.useFakeTimers(); + const { result } = renderHook(() => useReferralStore()); + + act(() => { + result.current.setNotification('Rewards claimed', 'success'); + }); + + expect(result.current.notificationMessage).toBe('Rewards claimed'); + expect(result.current.notificationType).toBe('success'); + + act(() => { + jest.advanceTimersByTime(5000); + }); + + expect(result.current.notificationMessage).toBeNull(); + expect(result.current.notificationType).toBeNull(); + jest.useRealTimers(); + }); + + it('reset restores the initial state', () => { + const { result } = renderHook(() => useReferralStore()); + + act(() => { + result.current.setReferrerId(address as never); + result.current.addReferralLink(mockLink('CODE1')); + result.current.updateStats(mockStats()); + result.current.reset(); + }); + + expect(result.current.referrerId).toBeNull(); + expect(result.current.currentReferralLinks).toEqual([]); + expect(result.current.currentStats).toBeNull(); + }); +});