Skip to content

Commit 6635a06

Browse files
committed
convert AppStateController to typescript
1 parent 874f704 commit 6635a06

File tree

12 files changed

+993
-693
lines changed

12 files changed

+993
-693
lines changed

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ module.exports = {
307307
{
308308
files: [
309309
'**/__snapshots__/*.snap',
310-
'app/scripts/controllers/app-state.test.js',
310+
'app/scripts/controllers/app-state-controller.test.ts',
311311
'app/scripts/controllers/mmi-controller.test.ts',
312312
'app/scripts/metamask-controller.actions.test.js',
313313
'app/scripts/detect-multiple-instances.test.js',

app/scripts/controllers/app-state.test.js renamed to app/scripts/controllers/app-state-controller.test.ts

Lines changed: 122 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,58 @@
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+
>;
633

734
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+
});
1051
return new AppStateController({
1152
addUnlockListener: jest.fn(),
1253
isUnlocked: jest.fn(() => true),
1354
initState,
1455
onInactiveTimeout: jest.fn(),
15-
showUnlockRequest: jest.fn(),
1656
preferencesStore: {
1757
subscribe: jest.fn(),
1858
getState: jest.fn(() => ({
@@ -21,33 +61,44 @@ describe('AppStateController', () => {
2161
},
2262
})),
2363
},
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+
},
2971
},
3072
});
3173
};
3274

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+
3384
beforeEach(() => {
34-
appStateController = createAppStateController({ store: mockStore });
85+
appStateController = createAppStateController();
3586
});
3687

3788
describe('setOutdatedBrowserWarningLastShown', () => {
3889
it('sets the last shown time', () => {
3990
appStateController = createAppStateController();
40-
const date = new Date();
91+
const timestamp: number = Date.now();
4192

42-
appStateController.setOutdatedBrowserWarningLastShown(date);
93+
appStateController.setOutdatedBrowserWarningLastShown(timestamp);
4394

4495
expect(
4596
appStateController.store.getState().outdatedBrowserWarningLastShown,
46-
).toStrictEqual(date);
97+
).toStrictEqual(timestamp);
4798
});
4899

49100
it('sets outdated browser warning last shown timestamp', () => {
50-
const lastShownTimestamp = Date.now();
101+
const lastShownTimestamp: number = Date.now();
51102
appStateController = createAppStateController();
52103
const updateStateSpy = jest.spyOn(
53104
appStateController.store,
@@ -67,10 +118,8 @@ describe('AppStateController', () => {
67118

68119
describe('getUnlockPromise', () => {
69120
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);
74123
const waitForUnlockSpy = jest.spyOn(appStateController, 'waitForUnlock');
75124

76125
appStateController.getUnlockPromise(true);
@@ -80,9 +129,7 @@ describe('AppStateController', () => {
80129

81130
it('resolves immediately if the extension is already unlocked', async () => {
82131
appStateController = createAppStateController();
83-
const isUnlockedMock = jest
84-
.spyOn(appStateController, 'isUnlocked')
85-
.mockReturnValue(true);
132+
const isUnlockedMock = createIsUnlockedMock(true);
86133

87134
await expect(
88135
appStateController.getUnlockPromise(false),
@@ -95,20 +142,27 @@ describe('AppStateController', () => {
95142
describe('waitForUnlock', () => {
96143
it('resolves immediately if already unlocked', async () => {
97144
const emitSpy = jest.spyOn(appStateController, 'emit');
98-
const resolveFn = jest.fn();
145+
const resolveFn: () => void = jest.fn();
99146
appStateController.waitForUnlock(resolveFn, false);
100147
expect(emitSpy).toHaveBeenCalledWith('updateBadge');
101-
expect(appStateController.messagingSystem.call).toHaveBeenCalledTimes(0);
148+
expect(controllerMessenger.call).toHaveBeenCalledTimes(0);
102149
});
103150

104151
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);
106160

107-
const resolveFn = jest.fn();
161+
const resolveFn: () => void = jest.fn();
108162
appStateController.waitForUnlock(resolveFn, true);
109163

110-
expect(appStateController.messagingSystem.call).toHaveBeenCalledTimes(1);
111-
expect(appStateController.messagingSystem.call).toHaveBeenCalledWith(
164+
expect(controllerMessenger.call).toHaveBeenCalledTimes(1);
165+
expect(controllerMessenger.call).toHaveBeenCalledWith(
112166
'ApprovalController:addRequest',
113167
expect.objectContaining({
114168
id: expect.any(String),
@@ -122,22 +176,29 @@ describe('AppStateController', () => {
122176

123177
describe('handleUnlock', () => {
124178
beforeEach(() => {
125-
jest.spyOn(appStateController, 'isUnlocked').mockReturnValue(false);
179+
createIsUnlockedMock(false);
126180
});
127181
afterEach(() => {
128182
jest.clearAllMocks();
129183
});
130184
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+
);
131192
const emitSpy = jest.spyOn(appStateController, 'emit');
132-
const resolveFn = jest.fn();
193+
const resolveFn: () => void = jest.fn();
133194
appStateController.waitForUnlock(resolveFn, true);
134195

135196
appStateController.handleUnlock();
136197

137198
expect(emitSpy).toHaveBeenCalled();
138199
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(
141202
'ApprovalController:acceptRequest',
142203
expect.any(String),
143204
);
@@ -173,7 +234,7 @@ describe('AppStateController', () => {
173234

174235
describe('setRecoveryPhraseReminderLastShown', () => {
175236
it('sets the last shown time of recovery phrase reminder', () => {
176-
const timestamp = Date.now();
237+
const timestamp: number = Date.now();
177238
appStateController.setRecoveryPhraseReminderLastShown(timestamp);
178239

179240
expect(
@@ -184,7 +245,10 @@ describe('AppStateController', () => {
184245

185246
describe('setLastActiveTime', () => {
186247
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+
);
188252
appStateController.setLastActiveTime();
189253

190254
expect(spy).toHaveBeenCalled();
@@ -205,7 +269,8 @@ describe('AppStateController', () => {
205269

206270
describe('addPollingToken', () => {
207271
it('adds a pollingToken for a given environmentType', () => {
208-
const pollingTokenType = 'popupGasPollTokens';
272+
const pollingTokenType =
273+
POLLING_TOKEN_ENVIRONMENT_TYPES[ENVIRONMENT_TYPE_POPUP];
209274
appStateController.addPollingToken('token1', pollingTokenType);
210275
expect(appStateController.store.getState()[pollingTokenType]).toContain(
211276
'token1',
@@ -215,7 +280,8 @@ describe('AppStateController', () => {
215280

216281
describe('removePollingToken', () => {
217282
it('removes a pollingToken for a given environmentType', () => {
218-
const pollingTokenType = 'popupGasPollTokens';
283+
const pollingTokenType =
284+
POLLING_TOKEN_ENVIRONMENT_TYPES[ENVIRONMENT_TYPE_POPUP];
219285
appStateController.addPollingToken('token1', pollingTokenType);
220286
appStateController.removePollingToken('token1', pollingTokenType);
221287
expect(
@@ -269,7 +335,7 @@ describe('AppStateController', () => {
269335

270336
describe('setCurrentPopupId', () => {
271337
it('sets the currentPopupId in the appState', () => {
272-
const popupId = 'popup1';
338+
const popupId = 12345;
273339

274340
appStateController.setCurrentPopupId(popupId);
275341
expect(appStateController.store.getState().currentPopupId).toBe(popupId);
@@ -278,7 +344,7 @@ describe('AppStateController', () => {
278344

279345
describe('getCurrentPopupId', () => {
280346
it('retrieves the currentPopupId saved in the appState', () => {
281-
const popupId = 'popup1';
347+
const popupId = 54321;
282348

283349
appStateController.setCurrentPopupId(popupId);
284350
expect(appStateController.getCurrentPopupId()).toBe(popupId);
@@ -287,7 +353,7 @@ describe('AppStateController', () => {
287353

288354
describe('setFirstTimeUsedNetwork', () => {
289355
it('updates the array of the first time used networks', () => {
290-
const chainId = '0x1';
356+
const chainId: string = '0x1';
291357

292358
appStateController.setFirstTimeUsedNetwork(chainId);
293359
expect(appStateController.store.getState().usedNetworks[chainId]).toBe(
@@ -298,7 +364,11 @@ describe('AppStateController', () => {
298364

299365
describe('setLastInteractedConfirmationInfo', () => {
300366
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+
} = {
302372
id: '123',
303373
chainId: '0x1',
304374
timestamp: new Date().getTime(),
@@ -344,7 +414,10 @@ describe('AppStateController', () => {
344414
'updateState',
345415
);
346416

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+
};
348421

349422
appStateController.showInteractiveReplacementTokenBanner(mockParams);
350423

@@ -363,7 +436,10 @@ describe('AppStateController', () => {
363436
'updateState',
364437
);
365438

366-
const mockParams = { fromAddress: '0x', custodyId: 'custodyId' };
439+
const mockParams: { fromAddress: string; custodyId: string } = {
440+
fromAddress: '0x',
441+
custodyId: 'custodyId',
442+
};
367443

368444
appStateController.setCustodianDeepLink(mockParams);
369445

@@ -382,7 +458,7 @@ describe('AppStateController', () => {
382458
'updateState',
383459
);
384460

385-
const mockParams = 'some message';
461+
const mockParams: string = 'some message';
386462

387463
appStateController.setNoteToTraderMessage(mockParams);
388464

0 commit comments

Comments
 (0)