@@ -105,6 +105,9 @@ function getMessenger(
105105 'KeyringController:stateChange' ,
106106 'KeyringController:unlock' ,
107107 'AccountTreeController:selectedAccountGroupChange' ,
108+ 'AccountTreeController:accountGroupCreated' ,
109+ 'AccountTreeController:accountGroupUpdated' ,
110+ 'AccountTreeController:accountGroupRemoved' ,
108111 ] ,
109112 } ) ;
110113 return messenger ;
@@ -202,11 +205,57 @@ function buildSnap(id: string, hasKeyring: boolean): TruncatedSnap {
202205/**
203206 * Builds a minimal `AccountGroupObject` for tests.
204207 *
208+ * @param id - The group ID.
205209 * @param accounts - The list of account IDs in the group.
206210 * @returns A minimal `AccountGroupObject`.
207211 */
208- function buildGroup ( accounts : string [ ] ) : AccountGroupObject {
209- return { accounts } as unknown as AccountGroupObject ;
212+ function buildGroup (
213+ id : AccountGroupId ,
214+ accounts : string [ ] ,
215+ ) : AccountGroupObject {
216+ return { id, accounts } as unknown as AccountGroupObject ;
217+ }
218+
219+ /**
220+ * Publishes an AccountTreeController accountGroupCreated event on the root
221+ * messenger.
222+ *
223+ * @param rootMessenger - The root messenger.
224+ * @param group - The created account group.
225+ */
226+ function publishAccountGroupCreated (
227+ rootMessenger : RootMessenger ,
228+ group : AccountGroupObject ,
229+ ) : void {
230+ rootMessenger . publish ( 'AccountTreeController:accountGroupCreated' , group ) ;
231+ }
232+
233+ /**
234+ * Publishes an AccountTreeController accountGroupUpdated event on the root
235+ * messenger.
236+ *
237+ * @param rootMessenger - The root messenger.
238+ * @param group - The updated account group.
239+ */
240+ function publishAccountGroupUpdated (
241+ rootMessenger : RootMessenger ,
242+ group : AccountGroupObject ,
243+ ) : void {
244+ rootMessenger . publish ( 'AccountTreeController:accountGroupUpdated' , group ) ;
245+ }
246+
247+ /**
248+ * Publishes an AccountTreeController accountGroupRemoved event on the root
249+ * messenger.
250+ *
251+ * @param rootMessenger - The root messenger.
252+ * @param groupId - The removed account group ID.
253+ */
254+ function publishAccountGroupRemoved (
255+ rootMessenger : RootMessenger ,
256+ groupId : AccountGroupId ,
257+ ) : void {
258+ rootMessenger . publish ( 'AccountTreeController:accountGroupRemoved' , groupId ) ;
210259}
211260
212261/**
@@ -642,7 +691,7 @@ describe('SnapAccountService', () => {
642691 const setSelectedAccounts = jest . fn ( ) . mockResolvedValue ( undefined ) ;
643692 mockLegacySnapKeyring ( mocks , { setSelectedAccounts } ) ;
644693 mocks . AccountTreeController . getAccountGroupObject . mockReturnValue (
645- buildGroup ( MOCK_ACCOUNTS ) ,
694+ buildGroup ( MOCK_GROUP_ID , MOCK_ACCOUNTS ) ,
646695 ) ;
647696 expect ( service ) . toBeDefined ( ) ;
648697
@@ -694,7 +743,7 @@ describe('SnapAccountService', () => {
694743 const setSelectedAccounts = jest . fn ( ) . mockRejectedValue ( error ) ;
695744 mockLegacySnapKeyring ( mocks , { setSelectedAccounts } ) ;
696745 mocks . AccountTreeController . getAccountGroupObject . mockReturnValue (
697- buildGroup ( MOCK_ACCOUNTS ) ,
746+ buildGroup ( MOCK_GROUP_ID , MOCK_ACCOUNTS ) ,
698747 ) ;
699748 const consoleErrorSpy = jest
700749 . spyOn ( console , 'error' )
@@ -706,7 +755,7 @@ describe('SnapAccountService', () => {
706755
707756 expect ( setSelectedAccounts ) . toHaveBeenCalledWith ( MOCK_ACCOUNTS ) ;
708757 expect ( consoleErrorSpy ) . toHaveBeenCalledWith (
709- 'Error handling selected account group change :' ,
758+ 'Error forwarding selected accounts :' ,
710759 error ,
711760 ) ;
712761
@@ -729,7 +778,7 @@ describe('SnapAccountService', () => {
729778 MOCK_GROUP_ID ,
730779 ) ;
731780 mocks . AccountTreeController . getAccountGroupObject . mockReturnValue (
732- buildGroup ( MOCK_ACCOUNTS ) ,
781+ buildGroup ( MOCK_GROUP_ID , MOCK_ACCOUNTS ) ,
733782 ) ;
734783 expect ( service ) . toBeDefined ( ) ;
735784
@@ -770,7 +819,7 @@ describe('SnapAccountService', () => {
770819 MOCK_GROUP_ID ,
771820 ) ;
772821 mocks . AccountTreeController . getAccountGroupObject . mockReturnValue (
773- buildGroup ( MOCK_ACCOUNTS ) ,
822+ buildGroup ( MOCK_GROUP_ID , MOCK_ACCOUNTS ) ,
774823 ) ;
775824 const consoleErrorSpy = jest
776825 . spyOn ( console , 'error' )
@@ -782,11 +831,116 @@ describe('SnapAccountService', () => {
782831
783832 expect ( setSelectedAccounts ) . toHaveBeenCalledWith ( MOCK_ACCOUNTS ) ;
784833 expect ( consoleErrorSpy ) . toHaveBeenCalledWith (
785- 'Error forwarding selected account group on unlock :' ,
834+ 'Error forwarding selected accounts :' ,
786835 error ,
787836 ) ;
788837
789838 consoleErrorSpy . mockRestore ( ) ;
790839 } ) ;
791840 } ) ;
841+
842+ describe . each ( [
843+ [ 'accountGroupCreated' , publishAccountGroupCreated ] as const ,
844+ [ 'accountGroupUpdated' , publishAccountGroupUpdated ] as const ,
845+ ] ) ( 'on AccountTreeController:%s' , ( _eventName , publishEvent ) => {
846+ const MOCK_GROUP_ID = 'keyring:01JABC/group-1' as AccountGroupId ;
847+ const OTHER_GROUP_ID = 'keyring:01JABC/group-2' as AccountGroupId ;
848+ const MOCK_ACCOUNTS = [
849+ '00000000-0000-0000-0000-000000000001' ,
850+ '00000000-0000-0000-0000-000000000002' ,
851+ ] ;
852+
853+ it ( 'forwards the accounts from the event payload when the affected group is the selected one' , async ( ) => {
854+ const { service, rootMessenger, mocks } = setup ( ) ;
855+ const setSelectedAccounts = jest . fn ( ) . mockResolvedValue ( undefined ) ;
856+ mockLegacySnapKeyring ( mocks , { setSelectedAccounts } ) ;
857+ mocks . AccountTreeController . getSelectedAccountGroup . mockReturnValue (
858+ MOCK_GROUP_ID ,
859+ ) ;
860+ expect ( service ) . toBeDefined ( ) ;
861+
862+ publishEvent ( rootMessenger , buildGroup ( MOCK_GROUP_ID , MOCK_ACCOUNTS ) ) ;
863+ await flushMicrotasks ( ) ;
864+
865+ expect (
866+ mocks . AccountTreeController . getAccountGroupObject ,
867+ ) . not . toHaveBeenCalled ( ) ;
868+ expect ( setSelectedAccounts ) . toHaveBeenCalledWith ( MOCK_ACCOUNTS ) ;
869+ } ) ;
870+
871+ it ( 'does nothing when the affected group is not the selected one' , async ( ) => {
872+ const { service, rootMessenger, mocks } = setup ( ) ;
873+ const setSelectedAccounts = jest . fn ( ) . mockResolvedValue ( undefined ) ;
874+ mockLegacySnapKeyring ( mocks , { setSelectedAccounts } ) ;
875+ mocks . AccountTreeController . getSelectedAccountGroup . mockReturnValue (
876+ OTHER_GROUP_ID ,
877+ ) ;
878+ expect ( service ) . toBeDefined ( ) ;
879+
880+ publishEvent ( rootMessenger , buildGroup ( MOCK_GROUP_ID , MOCK_ACCOUNTS ) ) ;
881+ await flushMicrotasks ( ) ;
882+
883+ expect (
884+ mocks . AccountTreeController . getAccountGroupObject ,
885+ ) . not . toHaveBeenCalled ( ) ;
886+ expect ( setSelectedAccounts ) . not . toHaveBeenCalled ( ) ;
887+ } ) ;
888+
889+ it ( 'does nothing when no account group is selected' , async ( ) => {
890+ const { service, rootMessenger, mocks } = setup ( ) ;
891+ const setSelectedAccounts = jest . fn ( ) . mockResolvedValue ( undefined ) ;
892+ mockLegacySnapKeyring ( mocks , { setSelectedAccounts } ) ;
893+ mocks . AccountTreeController . getSelectedAccountGroup . mockReturnValue ( '' ) ;
894+ expect ( service ) . toBeDefined ( ) ;
895+
896+ publishEvent ( rootMessenger , buildGroup ( MOCK_GROUP_ID , MOCK_ACCOUNTS ) ) ;
897+ await flushMicrotasks ( ) ;
898+
899+ expect (
900+ mocks . AccountTreeController . getAccountGroupObject ,
901+ ) . not . toHaveBeenCalled ( ) ;
902+ expect ( setSelectedAccounts ) . not . toHaveBeenCalled ( ) ;
903+ } ) ;
904+ } ) ;
905+
906+ describe ( 'on AccountTreeController:accountGroupRemoved' , ( ) => {
907+ const MOCK_GROUP_ID = 'keyring:01JABC/group-1' as AccountGroupId ;
908+ const OTHER_GROUP_ID = 'keyring:01JABC/group-2' as AccountGroupId ;
909+
910+ it ( 'clears the selected accounts when the removed group is the selected one' , async ( ) => {
911+ const { service, rootMessenger, mocks } = setup ( ) ;
912+ const setSelectedAccounts = jest . fn ( ) . mockResolvedValue ( undefined ) ;
913+ mockLegacySnapKeyring ( mocks , { setSelectedAccounts } ) ;
914+ mocks . AccountTreeController . getSelectedAccountGroup . mockReturnValue (
915+ MOCK_GROUP_ID ,
916+ ) ;
917+ expect ( service ) . toBeDefined ( ) ;
918+
919+ publishAccountGroupRemoved ( rootMessenger , MOCK_GROUP_ID ) ;
920+ await flushMicrotasks ( ) ;
921+
922+ expect (
923+ mocks . AccountTreeController . getAccountGroupObject ,
924+ ) . not . toHaveBeenCalled ( ) ;
925+ expect ( setSelectedAccounts ) . toHaveBeenCalledWith ( [ ] ) ;
926+ } ) ;
927+
928+ it ( 'does nothing when the removed group is not the selected one' , async ( ) => {
929+ const { service, rootMessenger, mocks } = setup ( ) ;
930+ const setSelectedAccounts = jest . fn ( ) . mockResolvedValue ( undefined ) ;
931+ mockLegacySnapKeyring ( mocks , { setSelectedAccounts } ) ;
932+ mocks . AccountTreeController . getSelectedAccountGroup . mockReturnValue (
933+ OTHER_GROUP_ID ,
934+ ) ;
935+ expect ( service ) . toBeDefined ( ) ;
936+
937+ publishAccountGroupRemoved ( rootMessenger , MOCK_GROUP_ID ) ;
938+ await flushMicrotasks ( ) ;
939+
940+ expect (
941+ mocks . AccountTreeController . getAccountGroupObject ,
942+ ) . not . toHaveBeenCalled ( ) ;
943+ expect ( setSelectedAccounts ) . not . toHaveBeenCalled ( ) ;
944+ } ) ;
945+ } ) ;
792946} ) ;
0 commit comments