11import { fireEvent , render , screen } from '@testing-library/react'
22import { useAdvancedUserAgentData , useAsyncMemo } from '@dcl/hooks'
3- import { useAnonUserId } from '../../../hooks/useAnonUserId'
43import { useDownloadClick } from '../../../hooks/useDownloadClick'
4+ import { useDownloadSuccessHref } from '../../../hooks/useDownloadSuccessHref'
55import { useHangOutAction } from '../../../hooks/useHangOutAction'
66import { DownloadPlace , SectionViewedTrack , SegmentEvent } from '../../../modules/segment'
77import { ComeHangOut } from './ComeHangOut'
@@ -39,10 +39,11 @@ jest.mock('../../../hooks/useDownloadClick', () => ({
3939 useDownloadClick : jest . fn ( )
4040} ) )
4141
42- jest . mock ( '../../../hooks/useAnonUserId' , ( ) => ( {
43- ANON_USER_ID_PARAM : 'anon_user_id' ,
44- useAnonUserId : jest . fn ( ( ) => undefined )
45- } ) )
42+ // The hook's own UTM-forwarding / anon_user_id behavior is covered by
43+ // useDownloadSuccessHref.spec.ts — mock it here as a plain (os, place) => href
44+ // builder so this spec only asserts ComeHangOut's wiring (which CTAs call it,
45+ // what data-* attributes they carry).
46+ jest . mock ( '../../../hooks/useDownloadSuccessHref' , ( ) => ( { useDownloadSuccessHref : jest . fn ( ) } ) )
4647
4748jest . mock ( '../../../hooks/useHangOutAction' , ( ) => ( {
4849 useHangOutAction : jest . fn ( )
@@ -56,30 +57,29 @@ jest.mock('../../Icon/VerifiedIcon', () => ({
5657 VerifiedIcon : ( ) => < span data-testid = "verified-icon" />
5758} ) )
5859
59- jest . mock ( '../../../modules/url' , ( ) => ( {
60- buildDownloadSuccessHref : ( os : string , place : string , options ?: { anonUserId ?: string } ) =>
61- `/download_success?os=${ os } &place=${ place } ${ options ?. anonUserId ? `&anon_user_id=${ options . anonUserId } ` : '' } `
62- } ) )
63-
6460const mockUserAgent = jest . mocked ( useAdvancedUserAgentData )
6561const mockAsyncMemo = jest . mocked ( useAsyncMemo )
6662const mockDownloadClick = jest . mocked ( useDownloadClick )
63+ const mockDownloadSuccessHref = jest . mocked ( useDownloadSuccessHref )
6764const mockHangOut = jest . mocked ( useHangOutAction )
68- const mockAnonUserId = jest . mocked ( useAnonUserId )
6965
7066const trackDownloadClick = jest . fn ( )
67+ const downloadSuccessHref = jest . fn ( )
7168
7269describe ( 'ComeHangOut' , ( ) => {
7370 beforeEach ( ( ) => {
7471 mockDownloadClick . mockReturnValue ( trackDownloadClick )
72+ // Re-armed every test: jest.resetAllMocks() in afterEach wipes the
73+ // implementation, not just the return value.
74+ downloadSuccessHref . mockImplementation ( ( os : string , place : string ) => `/download_success?os=${ os } &place=${ place } ` )
75+ mockDownloadSuccessHref . mockReturnValue ( downloadSuccessHref )
7576 mockHangOut . mockReturnValue ( {
7677 isDownloadModalOpen : false ,
7778 closeDownloadModal : jest . fn ( ) ,
7879 downloadModalProps : { } ,
7980 totalDownloads : '+400K'
8081 } as unknown as ReturnType < typeof useHangOutAction > )
8182 mockAsyncMemo . mockReturnValue ( [ 500000 , { loading : false , loaded : true } ] as unknown as ReturnType < typeof useAsyncMemo > )
82- mockAnonUserId . mockReturnValue ( undefined )
8383 } )
8484
8585 afterEach ( ( ) => {
@@ -126,21 +126,38 @@ describe('ComeHangOut', () => {
126126 expect ( trackDownloadClick ) . toHaveBeenCalledTimes ( 1 )
127127 } )
128128
129- it ( 'should bake anon_user_id into the download and platform-switch hrefs so attribution survives the redirect' , ( ) => {
130- mockAnonUserId . mockReturnValue ( '11111111-1111-4111-8111-111111111111' )
129+ it ( 'should call the shared useDownloadSuccessHref builder for the main CTA and platform-switch icon' , ( ) => {
130+ // UTM/anon_user_id forwarding is a useDownloadSuccessHref concern, covered
131+ // in useDownloadSuccessHref.spec.ts — this asserts ComeHangOut wires
132+ // os/place through to it correctly for both call sites.
131133 render ( < ComeHangOut /> )
132134
133- const downloadButton = screen . getByText ( 'page.download.download_for_short' ) . closest ( 'a' ) as HTMLAnchorElement
134- expect ( downloadButton ) . toHaveAttribute (
135- 'href' ,
136- `/download_success?os=Windows&place=${ DownloadPlace . COME_HANG_OUT } &anon_user_id=11111111-1111-4111-8111-111111111111`
137- )
135+ expect ( downloadSuccessHref ) . toHaveBeenCalledWith ( 'Windows' , DownloadPlace . COME_HANG_OUT )
136+ expect ( downloadSuccessHref ) . toHaveBeenCalledWith ( 'macOS' , DownloadPlace . COME_HANG_OUT_PLATFORM_SWITCH )
137+ } )
138+
139+ it ( 'should preserve campaign params on the /download fallback href when the user agent has not resolved' , ( ) => {
140+ mockUserAgent . mockReturnValue ( [ false , undefined ] as unknown as ReturnType < typeof useAdvancedUserAgentData > )
141+ window . history . pushState ( { } , '' , '/?utm_source=shefi' )
142+ try {
143+ render ( < ComeHangOut /> )
144+ const downloadButton = screen . getByText ( 'page.download.download_for_short' ) . closest ( 'a' ) as HTMLAnchorElement
145+ expect ( downloadButton ) . toHaveAttribute ( 'href' , '/download?utm_source=shefi' )
146+ } finally {
147+ window . history . pushState ( { } , '' , '/' )
148+ }
149+ } )
150+
151+ it ( 'should tag the main CTA, Epic button, and platform-switch icon as desktop_installer' , ( ) => {
152+ render ( < ComeHangOut /> )
138153
154+ const downloadButton = screen . getByText ( 'page.download.download_for_short' ) . closest ( 'a' ) as HTMLAnchorElement
155+ const epicButton = screen . getByText ( 'page.download.download_on' ) . closest ( 'a' ) as HTMLAnchorElement
139156 const macIcon = screen . getByAltText ( 'macOS' ) . closest ( 'a' ) as HTMLAnchorElement
140- expect ( macIcon ) . toHaveAttribute (
141- 'href' ,
142- `/download_success?os=macOS&place= ${ DownloadPlace . COME_HANG_OUT_PLATFORM_SWITCH } &anon_user_id=11111111-1111-4111-8111-111111111111`
143- )
157+
158+ expect ( downloadButton ) . toHaveAttribute ( 'data-download-target' , 'desktop_installer' )
159+ expect ( epicButton ) . toHaveAttribute ( 'data-download-target' , 'desktop_installer' )
160+ expect ( macIcon ) . toHaveAttribute ( 'data-download-target' , 'desktop_installer' )
144161 } )
145162
146163 it ( 'should track the iOS QR icon click and still open the QR modal' , ( ) => {
@@ -209,6 +226,7 @@ describe('ComeHangOut', () => {
209226 expect ( playButton ) . toHaveAttribute ( 'data-event' , SegmentEvent . DOWNLOAD )
210227 expect ( playButton ) . toHaveAttribute ( 'data-os' , 'Android' )
211228 expect ( playButton ) . toHaveAttribute ( 'data-place' , SectionViewedTrack . LANDING_COME_HANG_OUT )
229+ expect ( playButton ) . toHaveAttribute ( 'data-download-target' , 'google_play' )
212230
213231 fireEvent . click ( playButton )
214232
@@ -230,6 +248,7 @@ describe('ComeHangOut', () => {
230248 expect ( appStoreButton ) . toHaveAttribute ( 'data-event' , SegmentEvent . DOWNLOAD )
231249 expect ( appStoreButton ) . toHaveAttribute ( 'data-os' , 'iOS' )
232250 expect ( appStoreButton ) . toHaveAttribute ( 'data-place' , SectionViewedTrack . LANDING_COME_HANG_OUT )
251+ expect ( appStoreButton ) . toHaveAttribute ( 'data-download-target' , 'app_store' )
233252
234253 fireEvent . click ( appStoreButton )
235254
0 commit comments