Skip to content

Commit 9d952f6

Browse files
committed
feat(accounts-controller): add new typed options for InternalAccount(s)
1 parent b10198c commit 9d952f6

File tree

5 files changed

+334
-200
lines changed

5 files changed

+334
-200
lines changed

packages/accounts-controller/src/AccountsController.test.ts

Lines changed: 109 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { Messenger } from '@metamask/base-controller';
2-
import { InfuraNetworkType } from '@metamask/controller-utils';
32
import type {
43
AccountAssetListUpdatedEventPayload,
54
AccountBalancesUpdatedEventPayload,
65
AccountTransactionsUpdatedEventPayload,
6+
EntropySourceId,
77
} from '@metamask/keyring-api';
88
import {
99
BtcAccountType,
1010
BtcScope,
1111
EthAccountType,
1212
EthScope,
13+
KeyringAccountEntropyTypeOption,
1314
} from '@metamask/keyring-api';
1415
import { KeyringTypes } from '@metamask/keyring-controller';
1516
import type { InternalAccount } from '@metamask/keyring-internal-api';
@@ -158,49 +159,60 @@ function mockUUIDWithNormalAccounts(accounts: InternalAccount[]) {
158159
mockUUID.mockImplementation(mockAccountUUIDs.mock.bind(mockAccountUUIDs));
159160
}
160161

161-
/**
162-
* Sets the `lastSelected` property of the given `account` to `expect.any(Number)`.
163-
*
164-
* @param account - The account to modify.
165-
* @returns The modified account.
166-
*/
167-
function setLastSelectedAsAny(account: InternalAccount): InternalAccount {
168-
const deepClonedAccount = JSON.parse(
169-
JSON.stringify({
170-
...account,
171-
metadata: {
172-
...account.metadata,
173-
lastSelected: expect.any(Number),
162+
class MockExpectedInternalAccountBuilder {
163+
readonly #account: InternalAccount;
164+
165+
constructor(account: InternalAccount) {
166+
this.#account = JSON.parse(JSON.stringify(account)) as InternalAccount;
167+
}
168+
169+
static from(account: InternalAccount) {
170+
return new MockExpectedInternalAccountBuilder(account);
171+
}
172+
173+
setExpectedLastSelectedAsAny(): MockExpectedInternalAccountBuilder {
174+
this.#account.metadata.lastSelected = expect.any(Number);
175+
this.#account.metadata.importTime = expect.any(Number);
176+
177+
return this;
178+
}
179+
180+
setExpectedEntropyOptions(
181+
keyringId: EntropySourceId,
182+
): MockExpectedInternalAccountBuilder {
183+
this.#account.options = {
184+
...this.#account.options,
185+
entropySource: keyringId,
186+
groupIndex: expect.any(Number),
187+
derivationPath: expect.any(String),
188+
// New type `KeyringAccount` options.
189+
entropy: {
190+
type: KeyringAccountEntropyTypeOption.Mnemonic,
191+
id: keyringId,
192+
groupIndex: expect.any(Number),
193+
derivationPath: expect.any(String),
174194
},
175-
}),
176-
) as InternalAccount;
195+
};
196+
return this;
197+
}
177198

178-
deepClonedAccount.metadata.lastSelected = expect.any(Number);
179-
deepClonedAccount.metadata.importTime = expect.any(Number);
180-
return deepClonedAccount;
199+
get(): InternalAccount {
200+
return this.#account;
201+
}
181202
}
182203

183204
/**
184-
* Sets the `entropySource` property of the given `account` to the specified
185-
* keyringId value.
205+
* Sets the `lastSelected` property of the given `account` to `expect.any(Number)`.
186206
*
187207
* @param account - The account to modify.
188-
* @param keyringId - The keyring ID to set as entropySource.
189208
* @returns The modified account.
190209
*/
191-
function populateEntropySource(
210+
function setExpectedLastSelectedAsAny(
192211
account: InternalAccount,
193-
keyringId: string,
194212
): InternalAccount {
195-
return JSON.parse(
196-
JSON.stringify({
197-
...account,
198-
options: {
199-
...account.options,
200-
entropySource: keyringId,
201-
},
202-
}),
203-
) as InternalAccount;
213+
return MockExpectedInternalAccountBuilder.from(account)
214+
.setExpectedLastSelectedAsAny()
215+
.get();
204216
}
205217

206218
/**
@@ -678,7 +690,10 @@ describe('AccountsController', () => {
678690

679691
expect(accounts).toStrictEqual([
680692
mockAccount,
681-
setLastSelectedAsAny(populateEntropySource(mockAccount2, 'mock-id')),
693+
MockExpectedInternalAccountBuilder.from(mockAccount2)
694+
.setExpectedLastSelectedAsAny()
695+
.setExpectedEntropyOptions('mock-id')
696+
.get(),
682697
]);
683698
});
684699

@@ -744,8 +759,8 @@ describe('AccountsController', () => {
744759

745760
expect(accounts).toStrictEqual([
746761
mockAccount,
747-
setLastSelectedAsAny(mockAccount4),
748-
setLastSelectedAsAny(
762+
setExpectedLastSelectedAsAny(mockAccount4),
763+
setExpectedLastSelectedAsAny(
749764
createExpectedInternalAccount({
750765
id: 'mock-id3',
751766
name: 'Snap Account 2',
@@ -819,7 +834,7 @@ describe('AccountsController', () => {
819834

820835
expect(accounts).toStrictEqual([
821836
mockAccount,
822-
setLastSelectedAsAny(mockAccount4),
837+
setExpectedLastSelectedAsAny(mockAccount4),
823838
]);
824839
});
825840

@@ -878,7 +893,9 @@ describe('AccountsController', () => {
878893

879894
const accounts = accountsController.listMultichainAccounts();
880895

881-
expect(accounts).toStrictEqual([setLastSelectedAsAny(mockAccount)]);
896+
expect(accounts).toStrictEqual([
897+
setExpectedLastSelectedAsAny(mockAccount),
898+
]);
882899
});
883900

884901
it('increment the default account number when adding an account', async () => {
@@ -927,17 +944,17 @@ describe('AccountsController', () => {
927944
expect(accounts).toStrictEqual([
928945
mockAccount,
929946
mockAccount2,
930-
setLastSelectedAsAny(
947+
MockExpectedInternalAccountBuilder.from(
931948
createExpectedInternalAccount({
932949
id: 'mock-id3',
933950
name: 'Account 3',
934951
address: mockAccount3.address,
935952
keyringType: KeyringTypes.hd,
936-
options: {
937-
entropySource: 'mock-id',
938-
},
939953
}),
940-
),
954+
)
955+
.setExpectedLastSelectedAsAny()
956+
.setExpectedEntropyOptions('mock-id')
957+
.get(),
941958
]);
942959
});
943960

@@ -993,18 +1010,20 @@ describe('AccountsController', () => {
9931010

9941011
const accounts = accountsController.listMultichainAccounts();
9951012

996-
expect(accounts.map(setLastSelectedAsAny)).toStrictEqual([
1013+
expect(accounts.map(setExpectedLastSelectedAsAny)).toStrictEqual([
9971014
mockAccount,
9981015
mockAccount2WithCustomName,
999-
createExpectedInternalAccount({
1000-
id: 'mock-id3',
1001-
name: 'Account 3',
1002-
address: mockAccount3.address,
1003-
keyringType: KeyringTypes.hd,
1004-
options: {
1005-
entropySource: 'mock-id',
1006-
},
1007-
}),
1016+
MockExpectedInternalAccountBuilder.from(
1017+
createExpectedInternalAccount({
1018+
id: 'mock-id3',
1019+
name: 'Account 3',
1020+
address: mockAccount3.address,
1021+
keyringType: KeyringTypes.hd,
1022+
}),
1023+
)
1024+
.setExpectedLastSelectedAsAny()
1025+
.setExpectedEntropyOptions('mock-id')
1026+
.get(),
10081027
]);
10091028
});
10101029

@@ -1106,7 +1125,10 @@ describe('AccountsController', () => {
11061125

11071126
expect(accounts).toStrictEqual([
11081127
mockAccount,
1109-
setLastSelectedAsAny(populateEntropySource(mockAccount2, 'mock-id')),
1128+
MockExpectedInternalAccountBuilder.from(mockAccount2)
1129+
.setExpectedLastSelectedAsAny()
1130+
.setExpectedEntropyOptions('mock-id')
1131+
.get(),
11101132
]);
11111133
expect(accountsController.getSelectedAccount().id).toBe(mockAccount.id);
11121134
});
@@ -1155,7 +1177,10 @@ describe('AccountsController', () => {
11551177
// 2. AccountsController:stateChange
11561178
3,
11571179
'AccountsController:accountAdded',
1158-
setLastSelectedAsAny(populateEntropySource(mockAccount2, 'mock-id')),
1180+
MockExpectedInternalAccountBuilder.from(mockAccount2)
1181+
.setExpectedLastSelectedAsAny()
1182+
.setExpectedEntropyOptions('mock-id')
1183+
.get(),
11591184
);
11601185
});
11611186
});
@@ -1200,9 +1225,11 @@ describe('AccountsController', () => {
12001225

12011226
const accounts = accountsController.listMultichainAccounts();
12021227

1203-
expect(accounts).toStrictEqual([setLastSelectedAsAny(mockAccount2)]);
1228+
expect(accounts).toStrictEqual([
1229+
setExpectedLastSelectedAsAny(mockAccount2),
1230+
]);
12041231
expect(accountsController.getSelectedAccount()).toStrictEqual(
1205-
setLastSelectedAsAny(mockAccount2),
1232+
setExpectedLastSelectedAsAny(mockAccount2),
12061233
);
12071234
});
12081235

@@ -1255,11 +1282,11 @@ describe('AccountsController', () => {
12551282
const accounts = accountsController.listMultichainAccounts();
12561283

12571284
expect(accounts).toStrictEqual([
1258-
setLastSelectedAsAny(mockAccount),
1259-
setLastSelectedAsAny(mockAccount2),
1285+
setExpectedLastSelectedAsAny(mockAccount),
1286+
setExpectedLastSelectedAsAny(mockAccount2),
12601287
]);
12611288
expect(accountsController.getSelectedAccount()).toStrictEqual(
1262-
setLastSelectedAsAny(mockAccount2),
1289+
setExpectedLastSelectedAsAny(mockAccount2),
12631290
);
12641291
});
12651292

@@ -1319,11 +1346,11 @@ describe('AccountsController', () => {
13191346
const accounts = accountsController.listMultichainAccounts();
13201347

13211348
expect(accounts).toStrictEqual([
1322-
setLastSelectedAsAny(mockAccount),
1349+
setExpectedLastSelectedAsAny(mockAccount),
13231350
mockAccount2WithoutLastSelected,
13241351
]);
13251352
expect(accountsController.getSelectedAccount()).toStrictEqual(
1326-
setLastSelectedAsAny(mockAccount),
1353+
setExpectedLastSelectedAsAny(mockAccount),
13271354
);
13281355
});
13291356

@@ -1469,9 +1496,7 @@ describe('AccountsController', () => {
14691496
name: 'Account 1',
14701497
address: '0x456',
14711498
keyringType: KeyringTypes.hd,
1472-
options: {
1473-
entropySource: 'mock-id',
1474-
},
1499+
// Entropy options are added automatically by the controller.
14751500
});
14761501

14771502
mockUUIDWithNormalAccounts([
@@ -1512,7 +1537,12 @@ describe('AccountsController', () => {
15121537

15131538
const selectedAccount = accountsController.getSelectedAccount();
15141539
const accounts = accountsController.listMultichainAccounts();
1515-
const expectedAccount = setLastSelectedAsAny(mockReinitialisedAccount);
1540+
const expectedAccount = MockExpectedInternalAccountBuilder.from(
1541+
mockReinitialisedAccount,
1542+
)
1543+
.setExpectedLastSelectedAsAny()
1544+
.setExpectedEntropyOptions('mock-id')
1545+
.get();
15161546

15171547
expect(selectedAccount).toStrictEqual(expectedAccount);
15181548
expect(accounts).toStrictEqual([expectedAccount]);
@@ -1947,7 +1977,9 @@ describe('AccountsController', () => {
19471977
await accountsController.updateAccounts();
19481978

19491979
expect(
1950-
accountsController.listMultichainAccounts().map(setLastSelectedAsAny),
1980+
accountsController
1981+
.listMultichainAccounts()
1982+
.map(setExpectedLastSelectedAsAny),
19511983
).toStrictEqual(expectedAccounts);
19521984
});
19531985

@@ -2251,7 +2283,9 @@ describe('AccountsController', () => {
22512283
await accountsController.updateAccounts();
22522284

22532285
expect(
2254-
accountsController.listMultichainAccounts().map(setLastSelectedAsAny),
2286+
accountsController
2287+
.listMultichainAccounts()
2288+
.map(setExpectedLastSelectedAsAny),
22552289
).toStrictEqual(expectedAccounts);
22562290
});
22572291

@@ -2465,7 +2499,7 @@ describe('AccountsController', () => {
24652499

24662500
const result = accountsController.getAccount(mockAccount.id);
24672501

2468-
expect(result).toStrictEqual(setLastSelectedAsAny(mockAccount));
2502+
expect(result).toStrictEqual(setExpectedLastSelectedAsAny(mockAccount));
24692503
});
24702504
it('return undefined for an unknown account ID', () => {
24712505
const { accountsController } = setupAccountsController({
@@ -2793,7 +2827,7 @@ describe('AccountsController', () => {
27932827
});
27942828
const result = accountsController.getAccountExpect(mockAccount.id);
27952829

2796-
expect(result).toStrictEqual(setLastSelectedAsAny(mockAccount));
2830+
expect(result).toStrictEqual(setExpectedLastSelectedAsAny(mockAccount));
27972831
});
27982832

27992833
it('throw an error for an unknown account ID', () => {
@@ -2866,7 +2900,6 @@ describe('AccountsController', () => {
28662900
expect(
28672901
accountsController.state.internalAccounts.selectedAccount,
28682902
).toStrictEqual(mockNonEvmAccount.id);
2869-
console.log(accountsController.state.internalAccounts.selectedAccount);
28702903

28712904
expect(messengerSpy.mock.calls).toHaveLength(2); // state change and then selectedAccountChange
28722905

@@ -2877,7 +2910,7 @@ describe('AccountsController', () => {
28772910

28782911
expect(messengerSpy).toHaveBeenLastCalledWith(
28792912
'AccountsController:selectedAccountChange',
2880-
setLastSelectedAsAny(mockNonEvmAccount),
2913+
setExpectedLastSelectedAsAny(mockNonEvmAccount),
28812914
);
28822915
});
28832916
});
@@ -3170,8 +3203,8 @@ describe('AccountsController', () => {
31703203
const accounts = accountsController.listMultichainAccounts();
31713204
expect(accounts).toStrictEqual([
31723205
mockAccount,
3173-
setLastSelectedAsAny(mockSimpleKeyring1),
3174-
setLastSelectedAsAny(mockSimpleKeyring2),
3206+
setExpectedLastSelectedAsAny(mockSimpleKeyring1),
3207+
setExpectedLastSelectedAsAny(mockSimpleKeyring2),
31753208
]);
31763209
});
31773210

@@ -3227,8 +3260,8 @@ describe('AccountsController', () => {
32273260
const accounts = accountsController.listMultichainAccounts();
32283261
expect(accounts).toStrictEqual([
32293262
mockAccount,
3230-
setLastSelectedAsAny(mockSimpleKeyring2),
3231-
setLastSelectedAsAny(mockSimpleKeyring3),
3263+
setExpectedLastSelectedAsAny(mockSimpleKeyring2),
3264+
setExpectedLastSelectedAsAny(mockSimpleKeyring3),
32323265
]);
32333266
});
32343267
});

0 commit comments

Comments
 (0)