1
- import { ObservableStore } from '@metamask/obs-store' ;
2
- import { ORIGIN_METAMASK } from '../../../shared/constants/app' ;
3
- import AppStateController from './app-state' ;
4
-
5
- let appStateController , mockStore ;
1
+ import {
2
+ AcceptRequest ,
3
+ AddApprovalRequest ,
4
+ } from '@metamask/approval-controller' ;
5
+ import { ControllerMessenger } from '@metamask/base-controller' ;
6
+ import { KeyringControllerQRKeyringStateChangeEvent } from '@metamask/keyring-controller' ;
7
+ import {
8
+ ENVIRONMENT_TYPE_POPUP ,
9
+ ORIGIN_METAMASK ,
10
+ POLLING_TOKEN_ENVIRONMENT_TYPES ,
11
+ } from '../../../shared/constants/app' ;
12
+ import AppStateController from './app-state-controller' ;
13
+ import type {
14
+ AllowedActions ,
15
+ AllowedEvents ,
16
+ AppStateControllerActions ,
17
+ AppStateControllerEvents ,
18
+ AppStateControllerState ,
19
+ } from './app-state-controller' ;
20
+ import { PreferencesControllerStateChangeEvent } from './preferences-controller' ;
21
+
22
+ let appStateController : AppStateController ;
23
+ let controllerMessenger : ControllerMessenger <
24
+ | AppStateControllerActions
25
+ | AllowedActions
26
+ | AddApprovalRequest
27
+ | AcceptRequest ,
28
+ | AppStateControllerEvents
29
+ | AllowedEvents
30
+ | PreferencesControllerStateChangeEvent
31
+ | KeyringControllerQRKeyringStateChangeEvent
32
+ > ;
6
33
7
34
describe ( 'AppStateController' , ( ) => {
8
- mockStore = new ObservableStore ( ) ;
9
- const createAppStateController = ( initState = { } ) => {
35
+ const createAppStateController = (
36
+ initState : Partial < AppStateControllerState > = { } ,
37
+ ) : AppStateController => {
38
+ controllerMessenger = new ControllerMessenger ( ) ;
39
+ jest . spyOn ( ControllerMessenger . prototype , 'call' ) ;
40
+ const appStateMessenger = controllerMessenger . getRestricted ( {
41
+ name : 'AppStateController' ,
42
+ allowedActions : [
43
+ `ApprovalController:addRequest` ,
44
+ `ApprovalController:acceptRequest` ,
45
+ ] ,
46
+ allowedEvents : [
47
+ `PreferencesController:stateChange` ,
48
+ `KeyringController:qrKeyringStateChange` ,
49
+ ] ,
50
+ } ) ;
10
51
return new AppStateController ( {
11
52
addUnlockListener : jest . fn ( ) ,
12
53
isUnlocked : jest . fn ( ( ) => true ) ,
13
54
initState,
14
55
onInactiveTimeout : jest . fn ( ) ,
15
- showUnlockRequest : jest . fn ( ) ,
16
56
preferencesStore : {
17
57
subscribe : jest . fn ( ) ,
18
58
getState : jest . fn ( ( ) => ( {
@@ -21,33 +61,44 @@ describe('AppStateController', () => {
21
61
} ,
22
62
} ) ) ,
23
63
} ,
24
- messenger : {
25
- call : jest . fn ( ( ) => ( {
26
- catch : jest . fn ( ) ,
27
- } ) ) ,
28
- subscribe : jest . fn ( ) ,
64
+ messenger : appStateMessenger ,
65
+ extension : {
66
+ alarms : {
67
+ clear : jest . fn ( ) ,
68
+ create : jest . fn ( ) ,
69
+ onAlarm : { addListener : jest . fn ( ) } ,
70
+ } ,
29
71
} ,
30
72
} ) ;
31
73
} ;
32
74
75
+ const createIsUnlockedMock = ( isUnlocked : boolean ) => {
76
+ return jest
77
+ . spyOn (
78
+ appStateController as unknown as { isUnlocked : ( ) => boolean } ,
79
+ 'isUnlocked' ,
80
+ )
81
+ . mockReturnValue ( isUnlocked ) ;
82
+ } ;
83
+
33
84
beforeEach ( ( ) => {
34
- appStateController = createAppStateController ( { store : mockStore } ) ;
85
+ appStateController = createAppStateController ( ) ;
35
86
} ) ;
36
87
37
88
describe ( 'setOutdatedBrowserWarningLastShown' , ( ) => {
38
89
it ( 'sets the last shown time' , ( ) => {
39
90
appStateController = createAppStateController ( ) ;
40
- const date = new Date ( ) ;
91
+ const timestamp : number = Date . now ( ) ;
41
92
42
- appStateController . setOutdatedBrowserWarningLastShown ( date ) ;
93
+ appStateController . setOutdatedBrowserWarningLastShown ( timestamp ) ;
43
94
44
95
expect (
45
96
appStateController . store . getState ( ) . outdatedBrowserWarningLastShown ,
46
- ) . toStrictEqual ( date ) ;
97
+ ) . toStrictEqual ( timestamp ) ;
47
98
} ) ;
48
99
49
100
it ( 'sets outdated browser warning last shown timestamp' , ( ) => {
50
- const lastShownTimestamp = Date . now ( ) ;
101
+ const lastShownTimestamp : number = Date . now ( ) ;
51
102
appStateController = createAppStateController ( ) ;
52
103
const updateStateSpy = jest . spyOn (
53
104
appStateController . store ,
@@ -67,10 +118,8 @@ describe('AppStateController', () => {
67
118
68
119
describe ( 'getUnlockPromise' , ( ) => {
69
120
it ( 'waits for unlock if the extension is locked' , async ( ) => {
70
- appStateController = createAppStateController ( ) ;
71
- const isUnlockedMock = jest
72
- . spyOn ( appStateController , 'isUnlocked' )
73
- . mockReturnValue ( false ) ;
121
+ appStateController = createAppStateController ( { } ) ;
122
+ const isUnlockedMock = createIsUnlockedMock ( false ) ;
74
123
const waitForUnlockSpy = jest . spyOn ( appStateController , 'waitForUnlock' ) ;
75
124
76
125
appStateController . getUnlockPromise ( true ) ;
@@ -80,9 +129,7 @@ describe('AppStateController', () => {
80
129
81
130
it ( 'resolves immediately if the extension is already unlocked' , async ( ) => {
82
131
appStateController = createAppStateController ( ) ;
83
- const isUnlockedMock = jest
84
- . spyOn ( appStateController , 'isUnlocked' )
85
- . mockReturnValue ( true ) ;
132
+ const isUnlockedMock = createIsUnlockedMock ( true ) ;
86
133
87
134
await expect (
88
135
appStateController . getUnlockPromise ( false ) ,
@@ -95,20 +142,27 @@ describe('AppStateController', () => {
95
142
describe ( 'waitForUnlock' , ( ) => {
96
143
it ( 'resolves immediately if already unlocked' , async ( ) => {
97
144
const emitSpy = jest . spyOn ( appStateController , 'emit' ) ;
98
- const resolveFn = jest . fn ( ) ;
145
+ const resolveFn : ( ) => void = jest . fn ( ) ;
99
146
appStateController . waitForUnlock ( resolveFn , false ) ;
100
147
expect ( emitSpy ) . toHaveBeenCalledWith ( 'updateBadge' ) ;
101
- expect ( appStateController . messagingSystem . call ) . toHaveBeenCalledTimes ( 0 ) ;
148
+ expect ( controllerMessenger . call ) . toHaveBeenCalledTimes ( 0 ) ;
102
149
} ) ;
103
150
104
151
it ( 'creates approval request when waitForUnlock is called with shouldShowUnlockRequest as true' , async ( ) => {
105
- jest . spyOn ( appStateController , 'isUnlocked' ) . mockReturnValue ( false ) ;
152
+ const addRequestSpy = jest . fn ( ) . mockImplementation ( ( ) => ( {
153
+ catch : jest . fn ( ) ,
154
+ } ) ) ;
155
+ controllerMessenger . registerActionHandler (
156
+ 'ApprovalController:addRequest' ,
157
+ addRequestSpy ,
158
+ ) ;
159
+ createIsUnlockedMock ( false ) ;
106
160
107
- const resolveFn = jest . fn ( ) ;
161
+ const resolveFn : ( ) => void = jest . fn ( ) ;
108
162
appStateController . waitForUnlock ( resolveFn , true ) ;
109
163
110
- expect ( appStateController . messagingSystem . call ) . toHaveBeenCalledTimes ( 1 ) ;
111
- expect ( appStateController . messagingSystem . call ) . toHaveBeenCalledWith (
164
+ expect ( controllerMessenger . call ) . toHaveBeenCalledTimes ( 1 ) ;
165
+ expect ( controllerMessenger . call ) . toHaveBeenCalledWith (
112
166
'ApprovalController:addRequest' ,
113
167
expect . objectContaining ( {
114
168
id : expect . any ( String ) ,
@@ -122,22 +176,29 @@ describe('AppStateController', () => {
122
176
123
177
describe ( 'handleUnlock' , ( ) => {
124
178
beforeEach ( ( ) => {
125
- jest . spyOn ( appStateController , 'isUnlocked' ) . mockReturnValue ( false ) ;
179
+ createIsUnlockedMock ( false ) ;
126
180
} ) ;
127
181
afterEach ( ( ) => {
128
182
jest . clearAllMocks ( ) ;
129
183
} ) ;
130
184
it ( 'accepts approval request revolving all the related promises' , async ( ) => {
185
+ const addRequestSpy = jest . fn ( ) . mockImplementation ( ( ) => ( {
186
+ catch : jest . fn ( ) ,
187
+ } ) ) ;
188
+ controllerMessenger . registerActionHandler (
189
+ 'ApprovalController:addRequest' ,
190
+ addRequestSpy ,
191
+ ) ;
131
192
const emitSpy = jest . spyOn ( appStateController , 'emit' ) ;
132
- const resolveFn = jest . fn ( ) ;
193
+ const resolveFn : ( ) => void = jest . fn ( ) ;
133
194
appStateController . waitForUnlock ( resolveFn , true ) ;
134
195
135
196
appStateController . handleUnlock ( ) ;
136
197
137
198
expect ( emitSpy ) . toHaveBeenCalled ( ) ;
138
199
expect ( emitSpy ) . toHaveBeenCalledWith ( 'updateBadge' ) ;
139
- expect ( appStateController . messagingSystem . call ) . toHaveBeenCalled ( ) ;
140
- expect ( appStateController . messagingSystem . call ) . toHaveBeenCalledWith (
200
+ expect ( controllerMessenger . call ) . toHaveBeenCalled ( ) ;
201
+ expect ( controllerMessenger . call ) . toHaveBeenCalledWith (
141
202
'ApprovalController:acceptRequest' ,
142
203
expect . any ( String ) ,
143
204
) ;
@@ -173,7 +234,7 @@ describe('AppStateController', () => {
173
234
174
235
describe ( 'setRecoveryPhraseReminderLastShown' , ( ) => {
175
236
it ( 'sets the last shown time of recovery phrase reminder' , ( ) => {
176
- const timestamp = Date . now ( ) ;
237
+ const timestamp : number = Date . now ( ) ;
177
238
appStateController . setRecoveryPhraseReminderLastShown ( timestamp ) ;
178
239
179
240
expect (
@@ -184,7 +245,10 @@ describe('AppStateController', () => {
184
245
185
246
describe ( 'setLastActiveTime' , ( ) => {
186
247
it ( 'sets the last active time to the current time' , ( ) => {
187
- const spy = jest . spyOn ( appStateController , '_resetTimer' ) ;
248
+ const spy = jest . spyOn (
249
+ appStateController as unknown as { _resetTimer : ( ) => void } ,
250
+ '_resetTimer' ,
251
+ ) ;
188
252
appStateController . setLastActiveTime ( ) ;
189
253
190
254
expect ( spy ) . toHaveBeenCalled ( ) ;
@@ -205,7 +269,8 @@ describe('AppStateController', () => {
205
269
206
270
describe ( 'addPollingToken' , ( ) => {
207
271
it ( 'adds a pollingToken for a given environmentType' , ( ) => {
208
- const pollingTokenType = 'popupGasPollTokens' ;
272
+ const pollingTokenType =
273
+ POLLING_TOKEN_ENVIRONMENT_TYPES [ ENVIRONMENT_TYPE_POPUP ] ;
209
274
appStateController . addPollingToken ( 'token1' , pollingTokenType ) ;
210
275
expect ( appStateController . store . getState ( ) [ pollingTokenType ] ) . toContain (
211
276
'token1' ,
@@ -215,7 +280,8 @@ describe('AppStateController', () => {
215
280
216
281
describe ( 'removePollingToken' , ( ) => {
217
282
it ( 'removes a pollingToken for a given environmentType' , ( ) => {
218
- const pollingTokenType = 'popupGasPollTokens' ;
283
+ const pollingTokenType =
284
+ POLLING_TOKEN_ENVIRONMENT_TYPES [ ENVIRONMENT_TYPE_POPUP ] ;
219
285
appStateController . addPollingToken ( 'token1' , pollingTokenType ) ;
220
286
appStateController . removePollingToken ( 'token1' , pollingTokenType ) ;
221
287
expect (
@@ -269,7 +335,7 @@ describe('AppStateController', () => {
269
335
270
336
describe ( 'setCurrentPopupId' , ( ) => {
271
337
it ( 'sets the currentPopupId in the appState' , ( ) => {
272
- const popupId = 'popup1' ;
338
+ const popupId = 12345 ;
273
339
274
340
appStateController . setCurrentPopupId ( popupId ) ;
275
341
expect ( appStateController . store . getState ( ) . currentPopupId ) . toBe ( popupId ) ;
@@ -278,7 +344,7 @@ describe('AppStateController', () => {
278
344
279
345
describe ( 'getCurrentPopupId' , ( ) => {
280
346
it ( 'retrieves the currentPopupId saved in the appState' , ( ) => {
281
- const popupId = 'popup1' ;
347
+ const popupId = 54321 ;
282
348
283
349
appStateController . setCurrentPopupId ( popupId ) ;
284
350
expect ( appStateController . getCurrentPopupId ( ) ) . toBe ( popupId ) ;
@@ -287,7 +353,7 @@ describe('AppStateController', () => {
287
353
288
354
describe ( 'setFirstTimeUsedNetwork' , ( ) => {
289
355
it ( 'updates the array of the first time used networks' , ( ) => {
290
- const chainId = '0x1' ;
356
+ const chainId : string = '0x1' ;
291
357
292
358
appStateController . setFirstTimeUsedNetwork ( chainId ) ;
293
359
expect ( appStateController . store . getState ( ) . usedNetworks [ chainId ] ) . toBe (
@@ -298,7 +364,11 @@ describe('AppStateController', () => {
298
364
299
365
describe ( 'setLastInteractedConfirmationInfo' , ( ) => {
300
366
it ( 'sets information about last confirmation user has interacted with' , ( ) => {
301
- const lastInteractedConfirmationInfo = {
367
+ const lastInteractedConfirmationInfo : {
368
+ id : string ;
369
+ chainId : string ;
370
+ timestamp : number ;
371
+ } = {
302
372
id : '123' ,
303
373
chainId : '0x1' ,
304
374
timestamp : new Date ( ) . getTime ( ) ,
@@ -344,7 +414,10 @@ describe('AppStateController', () => {
344
414
'updateState' ,
345
415
) ;
346
416
347
- const mockParams = { url : 'https://example.com' , oldRefreshToken : 'old' } ;
417
+ const mockParams : { url : string ; oldRefreshToken : string } = {
418
+ url : 'https://example.com' ,
419
+ oldRefreshToken : 'old' ,
420
+ } ;
348
421
349
422
appStateController . showInteractiveReplacementTokenBanner ( mockParams ) ;
350
423
@@ -363,7 +436,10 @@ describe('AppStateController', () => {
363
436
'updateState' ,
364
437
) ;
365
438
366
- const mockParams = { fromAddress : '0x' , custodyId : 'custodyId' } ;
439
+ const mockParams : { fromAddress : string ; custodyId : string } = {
440
+ fromAddress : '0x' ,
441
+ custodyId : 'custodyId' ,
442
+ } ;
367
443
368
444
appStateController . setCustodianDeepLink ( mockParams ) ;
369
445
@@ -382,7 +458,7 @@ describe('AppStateController', () => {
382
458
'updateState' ,
383
459
) ;
384
460
385
- const mockParams = 'some message' ;
461
+ const mockParams : string = 'some message' ;
386
462
387
463
appStateController . setNoteToTraderMessage ( mockParams ) ;
388
464
0 commit comments