@@ -2,240 +2,151 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
22import { renderHook , act } from '@testing-library/react' ;
33import { useTracking } from '@/hooks/useTracking' ;
44
5- // Mock Firebase
6- const mockAddDoc = vi . fn ( ) ;
7- const mockGetDoc = vi . fn ( ) ;
5+ // Mock Supabase
6+ const mockSupabaseInsert = vi . fn ( ) ;
7+ const mockSupabaseSelect = vi . fn ( ) ;
88
9- vi . mock ( 'firebase/firestore' , ( ) => ( {
10- collection : vi . fn ( ) ,
11- addDoc : mockAddDoc ,
12- doc : vi . fn ( ) ,
13- getDoc : mockGetDoc ,
9+ vi . mock ( '@/integrations/supabase/client' , ( ) => ( {
10+ supabase : {
11+ from : vi . fn ( ( ) => ( {
12+ insert : mockSupabaseInsert ,
13+ select : vi . fn ( ( ) => ( {
14+ eq : vi . fn ( ( ) => ( {
15+ maybeSingle : mockSupabaseSelect ,
16+ } ) ) ,
17+ } ) ) ,
18+ } ) ) ,
19+ } ,
1420} ) ) ;
1521
16- // Mock hooks
17- const mockUseAntifraud = vi . fn ( ) ;
18- const mockUseConversionVerification = vi . fn ( ) ;
19-
20- vi . mock ( '@/hooks/useAntifraud' , ( ) => ( {
21- useAntifraud : mockUseAntifraud ,
22- } ) ) ;
23-
24- vi . mock ( '@/hooks/useConversionVerification' , ( ) => ( {
25- useConversionVerification : mockUseConversionVerification ,
22+ // Mock auth
23+ vi . mock ( '@/hooks/useAuth' , ( ) => ( {
24+ useAuth : ( ) => ( {
25+ user : { uid : 'test-user-123' } ,
26+ } ) ,
2627} ) ) ;
2728
2829describe ( 'useTracking Hook' , ( ) => {
2930 beforeEach ( ( ) => {
3031 vi . clearAllMocks ( ) ;
3132
32- mockUseAntifraud . mockReturnValue ( {
33- validateClick : vi . fn ( ) . mockResolvedValue ( {
34- valid : true ,
35- riskScore : 0.1 ,
36- reasons : [ ] ,
37- } ) ,
38- } ) ;
39-
40- mockUseConversionVerification . mockReturnValue ( {
41- createConversion : vi . fn ( ) . mockResolvedValue ( {
42- id : 'conversion-123' ,
43- success : true ,
44- } ) ,
45- } ) ;
46-
47- // Mock sessionStorage
48- Object . defineProperty ( window , 'sessionStorage' , {
49- value : {
50- getItem : vi . fn ( ) ,
51- setItem : vi . fn ( ) ,
52- removeItem : vi . fn ( ) ,
53- clear : vi . fn ( ) ,
54- } ,
55- writable : true ,
33+ mockSupabaseInsert . mockResolvedValue ( { error : null } ) ;
34+ mockSupabaseSelect . mockResolvedValue ( {
35+ data : { id : 'campaign-456' , name : 'Test Campaign' } ,
36+ error : null
5637 } ) ;
5738 } ) ;
5839
59- it ( 'should record click successfully' , async ( ) => {
60- mockAddDoc . mockResolvedValue ( { id : 'click-123' } ) ;
61- window . sessionStorage . getItem = vi . fn ( ) . mockReturnValue ( null ) ;
62-
40+ it ( 'should track click successfully' , async ( ) => {
6341 const { result } = renderHook ( ( ) => useTracking ( ) ) ;
6442
6543 await act ( async ( ) => {
66- const clickId = await result . current . recordClick (
67- 'affiliate-123' ,
68- 'campaign-456' ,
69- 'https://example.com'
70- ) ;
71- expect ( typeof clickId ) . toBe ( 'string' ) ;
44+ await result . current . trackClick ( {
45+ affiliateId : 'affiliate-123' ,
46+ campaignId : 'campaign-456'
47+ } ) ;
7248 } ) ;
7349
74- expect ( mockAddDoc ) . toHaveBeenCalled ( ) ;
75- expect ( window . sessionStorage . setItem ) . toHaveBeenCalled ( ) ;
50+ expect ( mockSupabaseInsert ) . toHaveBeenCalledWith ( {
51+ affiliate_id : 'affiliate-123' ,
52+ campaign_id : 'campaign-456' ,
53+ user_agent : undefined ,
54+ referrer : undefined
55+ } ) ;
7656 } ) ;
7757
78- it ( 'should prevent duplicate clicks in same session' , async ( ) => {
79- window . sessionStorage . getItem = vi . fn ( ) . mockReturnValue ( 'existing-click-id' ) ;
80-
58+ it ( 'should track conversion successfully' , async ( ) => {
8159 const { result } = renderHook ( ( ) => useTracking ( ) ) ;
8260
8361 await act ( async ( ) => {
84- const clickId = await result . current . recordClick (
85- 'affiliate-123' ,
86- 'campaign-456' ,
87- 'https://example.com'
88- ) ;
89- expect ( clickId ) . toBe ( 'existing-click-id' ) ;
90- } ) ;
91-
92- expect ( mockAddDoc ) . not . toHaveBeenCalled ( ) ;
93- } ) ;
94-
95- it ( 'should record conversion successfully' , async ( ) => {
96- mockGetDoc . mockResolvedValue ( {
97- exists : ( ) => true ,
98- data : ( ) => ( {
62+ await result . current . trackConversion ( {
9963 affiliateId : 'affiliate-123' ,
10064 campaignId : 'campaign-456' ,
101- commissionRate : 15 ,
102- } ) ,
65+ amount : 100 ,
66+ commission : 15
67+ } ) ;
10368 } ) ;
10469
105- const { result } = renderHook ( ( ) => useTracking ( ) ) ;
106-
107- await act ( async ( ) => {
108- const conversion = await result . current . recordConversion (
109- 'affiliate-123' ,
110- 'campaign-456' ,
111- 100 ,
112- 15
113- ) ;
114- expect ( conversion ) . toBeDefined ( ) ;
70+ expect ( mockSupabaseInsert ) . toHaveBeenCalledWith ( {
71+ affiliate_id : 'affiliate-123' ,
72+ campaign_id : 'campaign-456' ,
73+ amount : 100 ,
74+ commission : 15 ,
75+ status : 'pending' ,
76+ verified : false
11577 } ) ;
116-
117- expect ( mockUseConversionVerification ( ) . createConversion ) . toHaveBeenCalled ( ) ;
11878 } ) ;
11979
120- it ( 'should handle antifraud rejection' , async ( ) => {
121- mockUseAntifraud . mockReturnValue ( {
122- validateClick : vi . fn ( ) . mockResolvedValue ( {
123- valid : false ,
124- riskScore : 0.9 ,
125- reasons : [ 'Suspicious IP' , 'Bot detected' ] ,
126- } ) ,
127- } ) ;
128-
129- window . sessionStorage . getItem = vi . fn ( ) . mockReturnValue ( null ) ;
130-
80+ it ( 'should get campaign by id successfully' , async ( ) => {
13181 const { result } = renderHook ( ( ) => useTracking ( ) ) ;
13282
83+ let campaign ;
13384 await act ( async ( ) => {
134- await expect ( result . current . recordClick (
135- 'affiliate-123' ,
136- 'campaign-456' ,
137- 'https://example.com'
138- ) ) . rejects . toThrow ( 'Clic rejeté' ) ;
85+ campaign = await result . current . getCampaignById ( 'campaign-456' ) ;
13986 } ) ;
14087
141- expect ( mockAddDoc ) . not . toHaveBeenCalled ( ) ;
88+ expect ( mockSupabaseSelect ) . toHaveBeenCalled ( ) ;
89+ expect ( campaign ) . toEqual ( { id : 'campaign-456' , name : 'Test Campaign' } ) ;
14290 } ) ;
14391
144- it ( 'should validate click data before recording' , async ( ) => {
92+ it ( 'should handle track click errors' , async ( ) => {
93+ mockSupabaseInsert . mockResolvedValue ( { error : new Error ( 'Database error' ) } ) ;
94+
14595 const { result } = renderHook ( ( ) => useTracking ( ) ) ;
14696
14797 await act ( async ( ) => {
148- await expect ( result . current . recordClick (
149- '' , // Empty affiliate ID
150- 'campaign-456' ,
151- 'https://example.com'
152- ) ) . rejects . toThrow ( ) ;
98+ await expect ( result . current . trackClick ( {
99+ affiliateId : 'affiliate-123' ,
100+ campaignId : 'campaign-456'
101+ } ) ) . rejects . toThrow ( ) ;
153102 } ) ;
154103 } ) ;
155104
156- it ( 'should handle network errors gracefully' , async ( ) => {
157- mockAddDoc . mockRejectedValue ( new Error ( 'Network error' ) ) ;
158- window . sessionStorage . getItem = vi . fn ( ) . mockReturnValue ( null ) ;
105+ it ( 'should handle track conversion errors' , async ( ) => {
106+ mockSupabaseInsert . mockResolvedValue ( { error : new Error ( 'Database error' ) } ) ;
159107
160108 const { result } = renderHook ( ( ) => useTracking ( ) ) ;
161109
162110 await act ( async ( ) => {
163- await expect ( result . current . recordClick (
164- 'affiliate-123' ,
165- 'campaign-456' ,
166- 'https://example.com'
167- ) ) . rejects . toThrow ( 'Network error' ) ;
111+ await expect ( result . current . trackConversion ( {
112+ affiliateId : 'affiliate-123' ,
113+ campaignId : 'campaign-456' ,
114+ amount : 100 ,
115+ commission : 15
116+ } ) ) . rejects . toThrow ( ) ;
168117 } ) ;
169118 } ) ;
170119
171- it ( 'should calculate commission correctly' , async ( ) => {
172- mockGetDoc . mockResolvedValue ( {
173- exists : ( ) => true ,
174- data : ( ) => ( {
175- affiliateId : 'affiliate-123' ,
176- campaignId : 'campaign-456' ,
177- commissionRate : 10 ,
178- } ) ,
120+ it ( 'should handle get campaign errors' , async ( ) => {
121+ mockSupabaseSelect . mockResolvedValue ( {
122+ data : null ,
123+ error : new Error ( 'Campaign not found' )
179124 } ) ;
180125
181126 const { result } = renderHook ( ( ) => useTracking ( ) ) ;
182127
183128 await act ( async ( ) => {
184- await result . current . recordConversion (
185- 'affiliate-123' ,
186- 'campaign-456' ,
187- 100 , // Revenue
188- 10 // Commission rate
189- ) ;
129+ await expect ( result . current . getCampaignById ( 'invalid-campaign' ) ) . rejects . toThrow ( ) ;
190130 } ) ;
191-
192- const createConversionCall = mockUseConversionVerification ( ) . createConversion . mock . calls [ 0 ] ;
193- expect ( createConversionCall [ 0 ] ) . toEqual (
194- expect . objectContaining ( {
195- revenue : 100 ,
196- commissionAmount : 10 , // 10% of 100
197- } )
198- ) ;
199131 } ) ;
200132
201- it ( 'should handle invalid conversion data ' , async ( ) => {
133+ it ( 'should include user agent and referrer when provided ' , async ( ) => {
202134 const { result } = renderHook ( ( ) => useTracking ( ) ) ;
203135
204136 await act ( async ( ) => {
205- await expect ( result . current . recordConversion (
206- '' , // Empty affiliate ID
207- 'campaign-456' ,
208- 100 ,
209- 10
210- ) ) . rejects . toThrow ( ) ;
211- } ) ;
212- } ) ;
213-
214- it ( 'should detect bot traffic' , async ( ) => {
215- // Mock bot user agent
216- Object . defineProperty ( navigator , 'userAgent' , {
217- value : 'Mozilla/5.0 (compatible; Googlebot/2.1)' ,
218- writable : true ,
219- } ) ;
220-
221- mockUseAntifraud . mockReturnValue ( {
222- validateClick : vi . fn ( ) . mockResolvedValue ( {
223- valid : false ,
224- riskScore : 1.0 ,
225- reasons : [ 'Bot detected' ] ,
226- } ) ,
137+ await result . current . trackClick ( {
138+ affiliateId : 'affiliate-123' ,
139+ campaignId : 'campaign-456' ,
140+ userAgent : 'Mozilla/5.0 Test Browser' ,
141+ referrer : 'https://example.com'
142+ } ) ;
227143 } ) ;
228144
229- window . sessionStorage . getItem = vi . fn ( ) . mockReturnValue ( null ) ;
230-
231- const { result } = renderHook ( ( ) => useTracking ( ) ) ;
232-
233- await act ( async ( ) => {
234- await expect ( result . current . recordClick (
235- 'affiliate-123' ,
236- 'campaign-456' ,
237- 'https://example.com'
238- ) ) . rejects . toThrow ( 'Bot detected' ) ;
145+ expect ( mockSupabaseInsert ) . toHaveBeenCalledWith ( {
146+ affiliate_id : 'affiliate-123' ,
147+ campaign_id : 'campaign-456' ,
148+ user_agent : 'Mozilla/5.0 Test Browser' ,
149+ referrer : 'https://example.com'
239150 } ) ;
240151 } ) ;
241152} ) ;
0 commit comments