@@ -4,7 +4,9 @@ jest.mock('node:crypto');
44jest . mock ( 'node:os' ) ;
55jest . mock ( 'express' ) ;
66jest . mock ( 'webtorrent' ) ;
7- jest . mock ( 'nat-upnp' ) ;
7+ jest . mock ( 'nat-upnp' , ( ) => ( {
8+ createClient : jest . fn ( )
9+ } ) ) ;
810jest . mock ( 'public-ip' ) ;
911jest . mock ( '../src/registry/gun-registry' ) ;
1012
@@ -14,6 +16,8 @@ import * as crypto from 'node:crypto';
1416import * as os from 'node:os' ;
1517import express from 'express' ;
1618import WebTorrent from 'webtorrent' ;
19+ import natUpnp from 'nat-upnp' ;
20+ import { publicIpv4 } from 'public-ip' ;
1721import { GunRegistry } from '../src/registry/gun-registry' ;
1822
1923// Mock implementations
@@ -23,6 +27,7 @@ const mockOs = os as jest.Mocked<typeof os>;
2327const mockExpress = express as jest . MockedFunction < typeof express > ;
2428const MockWebTorrent = WebTorrent as jest . MockedClass < typeof WebTorrent > ;
2529const MockGunRegistry = GunRegistry as jest . MockedClass < typeof GunRegistry > ;
30+ const mockPublicIpv4 = publicIpv4 as jest . MockedFunction < typeof publicIpv4 > ;
2631
2732// Mock express app
2833const mockApp = {
@@ -43,7 +48,9 @@ const mockWebTorrentInstance = {
4348 seed : jest . fn ( ) ,
4449 get : jest . fn ( ) ,
4550 destroy : jest . fn ( ) ,
46- on : jest . fn ( )
51+ on : jest . fn ( ) ,
52+ setMaxListeners : jest . fn ( ) ,
53+ ready : true // Mark as ready to avoid delays
4754} ;
4855
4956// Mock torrent
@@ -52,6 +59,23 @@ const mockTorrent = {
5259 destroy : jest . fn ( )
5360} ;
5461
62+ // Mock UPnP client
63+ const mockUpnpClient = {
64+ portMapping : jest . fn ( ( options : any , callback : ( err : Error | null ) => void ) => {
65+ // Simulate successful port mapping
66+ setTimeout ( ( ) => callback ( null ) , 0 ) ;
67+ } ) ,
68+ externalIp : jest . fn ( ( callback : ( err : Error | null , ip ?: string ) => void ) => {
69+ // Simulate getting external IP
70+ setTimeout ( ( ) => callback ( null , '203.0.113.0' ) , 0 ) ;
71+ } ) ,
72+ portUnmapping : jest . fn ( ( options : any , callback : ( err : Error | null ) => void ) => {
73+ // Simulate successful port unmapping
74+ setTimeout ( ( ) => callback ( null ) , 0 ) ;
75+ } ) ,
76+ close : jest . fn ( )
77+ } ;
78+
5579// Mock GunRegistry instance
5680const mockGunRegistryInstance = {
5781 register : jest . fn ( ) ,
@@ -96,8 +120,12 @@ describe('FileHost', () => {
96120
97121 // Setup WebTorrent mocks
98122 MockWebTorrent . mockImplementation ( ( ) => mockWebTorrentInstance as any ) ;
99- mockWebTorrentInstance . seed . mockImplementation ( ( file : any , callback : any ) => {
100- setTimeout ( ( ) => callback ( mockTorrent ) , 0 ) ;
123+ mockWebTorrentInstance . seed . mockImplementation ( ( file : any , options : any , callback : any ) => {
124+ // Handle both cases: seed(file, callback) and seed(file, options, callback)
125+ const actualCallback = typeof options === 'function' ? options : callback ;
126+ if ( actualCallback ) {
127+ setTimeout ( ( ) => actualCallback ( mockTorrent ) , 0 ) ;
128+ }
101129 } ) ;
102130
103131 // Setup fs mocks
@@ -120,9 +148,18 @@ describe('FileHost', () => {
120148 } ]
121149 } ) ;
122150
151+ // Setup nat-upnp mocks
152+ ( natUpnp . createClient as jest . Mock ) . mockReturnValue ( mockUpnpClient ) ;
153+
154+ // Setup public-ip mocks
155+ mockPublicIpv4 . mockResolvedValue ( '203.0.113.0' ) ; // Use a test IP address
156+
123157 // Setup GunRegistry mocks
124158 MockGunRegistry . mockImplementation ( ( ) => mockGunRegistryInstance as any ) ;
125159
160+ // Speed up WebTorrent ready check for all instances in tests
161+ jest . spyOn ( FileHost . prototype as any , 'waitForWebTorrentReady' ) . mockResolvedValue ( undefined ) ;
162+
126163 fileHost = new FileHost ( { port : 3000 } ) ;
127164 } ) ;
128165
@@ -264,7 +301,7 @@ describe('FileHost', () => {
264301
265302 expect ( mockApp . listen ) . toHaveBeenCalled ( ) ;
266303 expect ( MockWebTorrent ) . toHaveBeenCalled ( ) ;
267- expect ( capabilities . directHttp ?. available ) . toBeUndefined ( ) ; // UPnP fails so directHttp is not set
304+ expect ( capabilities . directHttp ?. available ) . toBe ( true ) ; // UPnP succeeds in mock so directHttp is available
268305 expect ( capabilities . webTorrent ?. available ) . toBe ( true ) ;
269306 } , 10000 ) ;
270307
@@ -502,7 +539,7 @@ describe('FileHost', () => {
502539
503540 const url = await hostWithHttp . getFileUrl ( hash ) ;
504541
505- expect ( url ) . toBe ( `http://192.168.1.100 :3000/files/${ hash } ` ) ;
542+ expect ( url ) . toBe ( `http://203.0.113.0 :3000/files/${ hash } ` ) ;
506543
507544 await hostWithHttp . stop ( ) ;
508545 } , 15000 ) ;
0 commit comments