@@ -10,187 +10,203 @@ import { noop, stringify } from '@polkadot/util';
10
10
11
11
import { ScProvider } from './index.js' ;
12
12
13
- interface MockChain extends Sc . Chain {
14
- _spec : ( ) => string ;
15
- _recevedRequests : ( ) => string [ ] ;
13
+ // Well known chain constants
14
+ const mockWellKnownChain = {
15
+ polkadot : 'polkadot' ,
16
+ ksmcc3 : 'ksmcc3' ,
17
+ rococo_v2_2 : 'rococo_v2_2' ,
18
+ westend2 : 'westend2' ,
19
+ paseo : 'paseo'
20
+ } as const ;
21
+
22
+ interface MockChain {
23
+ sendJsonRpc : ( rpc : string ) => void ;
24
+ remove : ( ) => void ;
25
+ nextJsonRpcResponse : ( ) => Promise < string > ;
26
+ jsonRpcResponses : AsyncIterableIterator < string > ;
27
+ addChain : Sc . AddChain ;
28
+ _requests : string [ ] ;
29
+ _terminated : boolean ;
30
+ _callback : ( response : string ) => void ;
31
+ _interceptor : ( ( rpc : string ) => void ) | null ;
32
+ _setInterceptor : ( fn : ( ( rpc : string ) => void ) | null ) => void ;
33
+ _getLatestRequest : ( ) => string | undefined ;
34
+ _triggerCallback : ( response : unknown ) => void ;
16
35
_isTerminated : ( ) => boolean ;
17
- _triggerCallback : ( response : string | object ) => void ;
18
- _setTerminateInterceptor : ( fn : ( ) => void ) => void ;
19
- _setSendJsonRpcInterceptor : ( fn : ( rpc : string ) => void ) => void ;
20
- _getLatestRequest : ( ) => string ;
21
- }
22
-
23
- interface MockedHealthChecker extends HealthChecker {
24
- _isActive : ( ) => boolean ;
25
- _triggerHealthUpdate : ( update : SmoldotHealth ) => void ;
26
- }
27
-
28
- type MockSc = typeof Sc & {
29
- latestChain : ( ) => MockChain ;
30
- } ;
31
-
32
- enum WellKnownChain {
33
- polkadot = 'polkadot' ,
34
- ksmcc3 = 'ksmcc3' ,
35
- rococo_v2_2 = 'rococo_v2_2' ,
36
- westend2 = 'westend2'
36
+ _setSendJsonRpcInterceptor : ( fn : ( ( rpc : string ) => void ) | null ) => void ;
37
+ _recevedRequests : ( ) => string [ ] ;
37
38
}
38
39
39
- const wait = ( ms : number ) =>
40
- new Promise ( ( resolve ) =>
41
- setTimeout ( resolve , ms )
42
- ) ;
43
-
44
- function healthCheckerMock ( ) : MockedHealthChecker {
45
- let cb : ( health : SmoldotHealth ) => void = ( ) => undefined ;
46
- let sendJsonRpc : ( request : string ) => void = ( ) => undefined ;
47
- let isActive = false ;
40
+ // Helper function to wait for a specified number of milliseconds
41
+ const wait = ( ms : number ) : Promise < void > => new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
42
+
43
+ function createMockChain ( callback : ( response : string ) => void ) : MockChain {
44
+ const requests : string [ ] = [ ] ;
45
+ let terminated = false ;
46
+ let interceptor : ( ( rpc : string ) => void ) | null = null ;
47
+ let responseQueue : string [ ] = [ ] ;
48
+
49
+ const nextJsonRpcResponse : MockChain [ 'nextJsonRpcResponse' ] = async ( ) => {
50
+ if ( responseQueue . length === 0 ) {
51
+ return new Promise < string > ( ( resolve ) => {
52
+ const checkQueue = ( ) => {
53
+ if ( responseQueue . length > 0 ) {
54
+ resolve ( responseQueue . shift ( ) ! ) ;
55
+ } else {
56
+ setTimeout ( checkQueue , 10 ) ;
57
+ }
58
+ } ;
59
+ checkQueue ( ) ;
60
+ } ) ;
61
+ }
62
+ return responseQueue . shift ( ) ! ;
63
+ }
48
64
49
- return {
50
- _isActive : ( ) => isActive ,
51
- _triggerHealthUpdate : ( update : SmoldotHealth ) => {
52
- cb ( update ) ;
65
+ const jsonRpcResponses : MockChain [ 'jsonRpcResponses' ] = {
66
+ async next ( ) {
67
+ const value = await nextJsonRpcResponse ( ) ;
68
+ return { done : false , value } ;
53
69
} ,
54
- responsePassThrough : ( response ) => response ,
55
- sendJsonRpc : ( ...args ) => sendJsonRpc ( ...args ) ,
56
- setSendJsonRpc : ( cb ) => {
57
- sendJsonRpc = cb ;
70
+ [ Symbol . asyncIterator ] ( ) {
71
+ return this ;
58
72
} ,
59
- start : ( x ) => {
60
- isActive = true ;
61
- cb = x ;
73
+ return : ( ) => Promise . resolve ( { done : true , value : undefined } ) ,
74
+ throw : ( ) => Promise . resolve ( { done : true , value : undefined } )
75
+ }
76
+
77
+ const chain : MockChain = {
78
+ _requests : requests ,
79
+ _terminated : terminated ,
80
+ _callback : ( response : string ) => {
81
+ responseQueue . push ( response ) ;
82
+ callback ( response ) ;
62
83
} ,
63
- stop : ( ) => {
64
- isActive = false ;
65
- }
66
- } ;
67
- }
68
-
69
- function healthCheckerFactory ( ) {
70
- const _healthCheckers : MockedHealthChecker [ ] = [ ] ;
71
-
72
- return {
73
- _healthCheckers,
74
- _latestHealthChecker : ( ) => _healthCheckers . slice ( - 1 ) [ 0 ] ,
75
- healthChecker : ( ) => {
76
- const result = healthCheckerMock ( ) ;
77
-
78
- _healthCheckers . push ( result ) ;
79
-
80
- return result ;
81
- }
82
- } ;
83
- }
84
-
85
- function getFakeChain ( spec : string , callback : Sc . JsonRpcCallback ) : MockChain {
86
- const _receivedRequests : string [ ] = [ ] ;
87
- let _isTerminated = false ;
84
+ _interceptor : null ,
85
+ _setInterceptor : ( fn : ( ( rpc : string ) => void ) | null ) => {
86
+ interceptor = fn ;
87
+ } ,
88
+ _getLatestRequest : ( ) => requests [ requests . length - 1 ] ,
89
+ sendJsonRpc : ( rpc : string ) => {
90
+ if ( terminated ) {
91
+ throw new Error ( 'Chain terminated' ) ;
92
+ }
88
93
89
- let terminateInterceptor = Function . prototype ;
90
- let sendJsonRpcInterceptor = Function . prototype ;
94
+ if ( interceptor ) {
95
+ interceptor ( rpc ) ;
96
+ }
91
97
92
- return {
93
- _getLatestRequest : ( ) => _receivedRequests [ _receivedRequests . length - 1 ] ,
94
- _isTerminated : ( ) => _isTerminated ,
95
- _recevedRequests : ( ) => _receivedRequests ,
96
- _setSendJsonRpcInterceptor : ( fn ) => {
97
- sendJsonRpcInterceptor = fn ;
98
+ requests . push ( rpc ) ;
98
99
} ,
99
- _setTerminateInterceptor : ( fn ) => {
100
- terminateInterceptor = fn ;
100
+ remove : ( ) => {
101
+ terminated = true ;
101
102
} ,
102
- _spec : ( ) => spec ,
103
- _triggerCallback : ( response ) => {
104
- callback (
105
- typeof response === 'string'
106
- ? response
107
- : stringify ( response )
108
- ) ;
103
+ nextJsonRpcResponse,
104
+ jsonRpcResponses,
105
+ addChain : async ( ) => createMockChain ( noop ) ,
106
+ _triggerCallback : ( response : unknown ) => {
107
+ callback ( stringify ( response ) ) ;
109
108
} ,
110
- addChain : ( chainSpec , jsonRpcCallback ) =>
111
- Promise . resolve ( getFakeChain ( chainSpec , jsonRpcCallback ?? noop ) ) ,
112
- remove : ( ) => {
113
- terminateInterceptor ( ) ;
114
- _isTerminated = true ;
109
+ _isTerminated : ( ) => terminated ,
110
+ _setSendJsonRpcInterceptor : ( fn : ( ( rpc : string ) => void ) | null ) => {
111
+ interceptor = fn ;
115
112
} ,
116
- sendJsonRpc : ( rpc ) => {
117
- sendJsonRpcInterceptor ( rpc ) ;
118
- _receivedRequests . push ( rpc ) ;
119
- }
113
+ _recevedRequests : ( ) => requests
120
114
} ;
115
+
116
+ return chain ;
121
117
}
122
118
123
- function getFakeClient ( ) {
119
+ function createMockClient ( ) {
124
120
const chains : MockChain [ ] = [ ] ;
125
- let addChainInterceptor : Promise < void > = Promise . resolve ( ) ;
126
- let addWellKnownChainInterceptor : Promise < void > = Promise . resolve ( ) ;
121
+ let interceptor : Promise < void > = Promise . resolve ( ) ;
127
122
128
123
return {
129
- _chains : ( ) => chains ,
130
- _setAddChainInterceptor : ( interceptor : Promise < void > ) => {
131
- addChainInterceptor = interceptor ;
132
- } ,
133
- _setAddWellKnownChainInterceptor : ( interceptor : Promise < void > ) => {
134
- addWellKnownChainInterceptor = interceptor ;
135
- } ,
136
- addChain : ( chainSpec : string , cb : Sc . JsonRpcCallback ) : Promise < MockChain > =>
137
- addChainInterceptor . then ( ( ) => {
138
- const result = getFakeChain ( chainSpec , cb ) ;
124
+ addChain : async ( spec : string ) => {
125
+ await interceptor ;
126
+ const chain = createMockChain ( noop ) ;
139
127
140
- chains . push ( result ) ;
128
+ chains . push ( chain ) ;
141
129
142
- return result ;
143
- } ) ,
144
- addWellKnownChain : (
145
- wellKnownChain : string ,
146
- cb : Sc . JsonRpcCallback
147
- ) : Promise < MockChain > =>
148
- addWellKnownChainInterceptor . then ( ( ) => {
149
- const result = getFakeChain ( wellKnownChain , cb ) ;
130
+ return chain ;
131
+ } ,
132
+ addWellKnownChain : async ( chain : string ) => {
133
+ await interceptor ;
134
+ const mockChain = createMockChain ( noop ) ;
150
135
151
- chains . push ( result ) ;
136
+ chains . push ( mockChain ) ;
152
137
153
- return result ;
154
- } )
138
+ return mockChain ;
139
+ } ,
140
+ _chains : chains ,
141
+ _setInterceptor : ( p : Promise < void > ) => {
142
+ interceptor = p ;
143
+ } ,
144
+ latestChain : ( ) => chains [ chains . length - 1 ]
155
145
} ;
156
146
}
157
147
158
- function connectorFactory ( ) : MockSc {
159
- const clients : ReturnType < typeof getFakeClient > [ ] = [ ] ;
160
- const latestClient = ( ) => clients [ clients . length - 1 ] ;
161
-
162
- return {
163
- WellKnownChain,
164
- _clients : ( ) => clients ,
165
- createScClient : ( ) => {
166
- const result = getFakeClient ( ) ;
167
-
168
- clients . push ( result ) ;
148
+ // Mock client instance that will be shared
149
+ let mockClient = createMockClient ( ) ;
150
+
151
+ // Mock Sc client with mockClient instance
152
+ const mockSc = {
153
+ createScClient : ( ) => {
154
+ mockClient = createMockClient ( ) ;
155
+ return mockClient ;
156
+ } ,
157
+ WellKnownChain : mockWellKnownChain ,
158
+ latestChain : ( ) => mockClient . latestChain ( )
159
+ } ;
169
160
170
- return result ;
171
- } ,
172
- latestChain : ( ) =>
173
- latestClient ( ) . _chains ( ) [ latestClient ( ) . _chains ( ) . length - 1 ] ,
174
- latestClient
175
- } as unknown as MockSc ;
176
- }
161
+ // Mock health checker factory
162
+ const mockedHealthChecker = {
163
+ healthChecker : ( ) => createMockHealthChecker ( )
164
+ } ;
177
165
178
- function setChainSyncyingStatus ( isSyncing : boolean ) : void {
179
- getCurrentHealthChecker ( ) . _triggerHealthUpdate ( {
166
+ // Helper function to set chain syncing status
167
+ function setChainSyncyingStatus ( isSyncing : boolean ) {
168
+ const health : SmoldotHealth = {
180
169
isSyncing,
181
170
peers : 1 ,
182
171
shouldHavePeers : true
183
- } ) ;
172
+ } ;
173
+ mockedHealthChecker . healthChecker ( ) . _update ( health ) ;
184
174
}
185
175
186
- let mockSc : MockSc ;
187
- let mockedHealthChecker : ReturnType < typeof healthCheckerFactory > ;
188
- const getCurrentHealthChecker = ( ) => mockedHealthChecker . _latestHealthChecker ( ) ;
176
+ function createMockHealthChecker ( ) : HealthChecker & { _update : ( health : SmoldotHealth ) => void } {
177
+ let sendRpc : ( ( req : string ) => void ) | null = null ;
178
+ let healthCb : ( ( health : SmoldotHealth ) => void ) | null = null ;
179
+
180
+ return {
181
+ setSendJsonRpc : ( cb ) => {
182
+ sendRpc = cb ;
183
+ } ,
184
+ sendJsonRpc : ( req ) => sendRpc ?.( req ) ,
185
+ responsePassThrough : ( res ) => res ,
186
+ start : ( cb ) => {
187
+ healthCb = cb ;
188
+ } ,
189
+ stop : ( ) => {
190
+ healthCb = null ;
191
+ } ,
192
+ _update : ( health ) => healthCb ?.( health )
193
+ } ;
194
+ }
189
195
190
196
describe ( 'ScProvider' , ( ) => {
191
- beforeAll ( ( ) => {
192
- mockSc = connectorFactory ( ) ;
193
- mockedHealthChecker = healthCheckerFactory ( ) ;
197
+ let provider : ScProvider ;
198
+ let mockClient : ReturnType < typeof createMockClient > ;
199
+ let mockHealthChecker : ReturnType < typeof createMockHealthChecker > ;
200
+
201
+ beforeEach ( async ( ) => {
202
+ mockClient = createMockClient ( ) ;
203
+ mockHealthChecker = createMockHealthChecker ( ) ;
204
+ provider = new ScProvider ( { createScClient : ( ) => mockClient , WellKnownChain : mockWellKnownChain } , '' ) ;
205
+ await provider . connect ( undefined , ( ) => mockHealthChecker ) ;
206
+ } ) ;
207
+
208
+ afterEach ( async ( ) => {
209
+ await provider . disconnect ( ) ;
194
210
} ) ;
195
211
196
212
describe ( 'on' , ( ) => {
@@ -372,7 +388,7 @@ describe('ScProvider', () => {
372
388
373
389
setTimeout ( ( ) => {
374
390
chain . _triggerCallback ( {
375
- id : 1 ,
391
+ id : 1 ,
376
392
jsonrpc : '2.0'
377
393
} ) ;
378
394
} , 0 ) ;
@@ -488,8 +504,8 @@ describe('ScProvider', () => {
488
504
} ) ;
489
505
setTimeout ( ( ) => {
490
506
chain . _triggerCallback ( {
491
- id : 1 ,
492
- jsonrpc : '2.0' ,
507
+ id : 1 ,
508
+ jsonrpc : '2.0' ,
493
509
result : unsubscribeToken
494
510
} ) ;
495
511
} , 0 ) ;
@@ -519,8 +535,8 @@ describe('ScProvider', () => {
519
535
520
536
setTimeout ( ( ) => {
521
537
chain . _triggerCallback ( {
522
- id : 1 ,
523
- jsonrpc : '2.0' ,
538
+ id : 1 ,
539
+ jsonrpc : '2.0' ,
524
540
result : unsubscribeToken
525
541
} ) ;
526
542
} , 0 ) ;
0 commit comments