@@ -511,14 +511,18 @@ describe("WalletDeveloperControlled", () => {
511511 } ) ;
512512
513513 describe ( "getProjectWallet" , ( ) => {
514- it ( "fetches wallet by ID from API" , async ( ) => {
515- const mockWalletInfo = {
514+ it ( "fetches wallet by ID from API and normalizes flat response to nested chains shape " , async ( ) => {
515+ const flatBackendResponse = {
516516 id : "test-wallet-id" ,
517517 projectId : "test-project-id" ,
518+ key : mockEncryptedData ,
519+ pubKeyHash : "mock-cardano-pub-key-hash" ,
520+ stakeCredentialHash : "mock-cardano-stake-hash" ,
521+ tags : [ "treasury" ] ,
518522 } ;
519523 mockAxiosInstance . get . mockResolvedValue ( {
520524 status : 200 ,
521- data : mockWalletInfo ,
525+ data : flatBackendResponse ,
522526 } ) ;
523527 const wallet = new WalletDeveloperControlled ( { sdk : mockSdk } ) ;
524528
@@ -527,7 +531,37 @@ describe("WalletDeveloperControlled", () => {
527531 expect ( mockAxiosInstance . get ) . toHaveBeenCalledWith (
528532 "api/project-wallet/test-project-id/test-wallet-id" ,
529533 ) ;
530- expect ( result ) . toEqual ( mockWalletInfo ) ;
534+ expect ( result ) . toEqual ( {
535+ id : "test-wallet-id" ,
536+ projectId : "test-project-id" ,
537+ key : mockEncryptedData ,
538+ tags : [ "treasury" ] ,
539+ chains : {
540+ cardano : {
541+ pubKeyHash : "mock-cardano-pub-key-hash" ,
542+ stakeCredentialHash : "mock-cardano-stake-hash" ,
543+ } ,
544+ } ,
545+ } ) ;
546+ } ) ;
547+
548+ it ( "defaults tags to empty array when missing from backend" , async ( ) => {
549+ mockAxiosInstance . get . mockResolvedValue ( {
550+ status : 200 ,
551+ data : {
552+ id : "wid" ,
553+ projectId : "test-project-id" ,
554+ key : mockEncryptedData ,
555+ pubKeyHash : "pkh" ,
556+ stakeCredentialHash : null ,
557+ } ,
558+ } ) ;
559+ const wallet = new WalletDeveloperControlled ( { sdk : mockSdk } ) ;
560+
561+ const result = await wallet . getProjectWallet ( "wid" ) ;
562+
563+ expect ( result . tags ) . toEqual ( [ ] ) ;
564+ expect ( result . chains . cardano ?. stakeCredentialHash ) . toBeNull ( ) ;
531565 } ) ;
532566
533567 it ( "throws if wallet not found" , async ( ) => {
@@ -608,6 +642,97 @@ describe("WalletDeveloperControlled", () => {
608642 } ) ;
609643 } ) ;
610644
645+ describe ( "getProjectWalletsByTag" , ( ) => {
646+ it ( "fetches wallets by tag and normalizes each flat response to nested chains shape" , async ( ) => {
647+ const flatBackendResponse = [
648+ {
649+ id : "wallet-1" ,
650+ projectId : "test-project-id" ,
651+ key : mockEncryptedData ,
652+ pubKeyHash : "pkh-1" ,
653+ stakeCredentialHash : "sch-1" ,
654+ tags : [ "treasury" ] ,
655+ } ,
656+ {
657+ id : "wallet-2" ,
658+ projectId : "test-project-id" ,
659+ key : mockEncryptedData ,
660+ pubKeyHash : "pkh-2" ,
661+ stakeCredentialHash : null ,
662+ tags : [ "treasury" ] ,
663+ } ,
664+ ] ;
665+ mockAxiosInstance . get . mockResolvedValue ( {
666+ status : 200 ,
667+ data : flatBackendResponse ,
668+ } ) ;
669+ const wallet = new WalletDeveloperControlled ( { sdk : mockSdk } ) ;
670+
671+ const result = await wallet . getProjectWalletsByTag ( "treasury" ) ;
672+
673+ expect ( mockAxiosInstance . get ) . toHaveBeenCalledWith (
674+ "api/project-wallet/test-project-id/tag/treasury" ,
675+ ) ;
676+ expect ( result ) . toHaveLength ( 2 ) ;
677+ expect ( result [ 0 ] ) . toEqual ( {
678+ id : "wallet-1" ,
679+ projectId : "test-project-id" ,
680+ key : mockEncryptedData ,
681+ tags : [ "treasury" ] ,
682+ chains : {
683+ cardano : { pubKeyHash : "pkh-1" , stakeCredentialHash : "sch-1" } ,
684+ } ,
685+ } ) ;
686+ expect ( result [ 1 ] ?. chains . cardano ?. stakeCredentialHash ) . toBeNull ( ) ;
687+ expect ( result [ 0 ] ?. chains . spark ) . toBeUndefined ( ) ;
688+ } ) ;
689+
690+ it ( "URL-encodes tags with special characters" , async ( ) => {
691+ mockAxiosInstance . get . mockResolvedValue ( { status : 200 , data : [ ] } ) ;
692+ const wallet = new WalletDeveloperControlled ( { sdk : mockSdk } ) ;
693+
694+ await wallet . getProjectWalletsByTag ( "team/alpha beta" ) ;
695+
696+ expect ( mockAxiosInstance . get ) . toHaveBeenCalledWith (
697+ "api/project-wallet/test-project-id/tag/team%2Falpha%20beta" ,
698+ ) ;
699+ } ) ;
700+
701+ it ( "returns empty array when no wallets match" , async ( ) => {
702+ mockAxiosInstance . get . mockResolvedValue ( { status : 200 , data : [ ] } ) ;
703+ const wallet = new WalletDeveloperControlled ( { sdk : mockSdk } ) ;
704+
705+ const result = await wallet . getProjectWalletsByTag ( "nonexistent" ) ;
706+
707+ expect ( result ) . toEqual ( [ ] ) ;
708+ } ) ;
709+
710+ it ( "throws if tag is empty string" , async ( ) => {
711+ const wallet = new WalletDeveloperControlled ( { sdk : mockSdk } ) ;
712+
713+ await expect ( wallet . getProjectWalletsByTag ( "" ) ) . rejects . toThrow (
714+ "tag is required" ,
715+ ) ;
716+ } ) ;
717+
718+ it ( "throws if tag is whitespace only" , async ( ) => {
719+ const wallet = new WalletDeveloperControlled ( { sdk : mockSdk } ) ;
720+
721+ await expect ( wallet . getProjectWalletsByTag ( " " ) ) . rejects . toThrow (
722+ "tag is required" ,
723+ ) ;
724+ } ) ;
725+
726+ it ( "throws if API call fails" , async ( ) => {
727+ mockAxiosInstance . get . mockResolvedValue ( { status : 500 } ) ;
728+ const wallet = new WalletDeveloperControlled ( { sdk : mockSdk } ) ;
729+
730+ await expect (
731+ wallet . getProjectWalletsByTag ( "treasury" ) ,
732+ ) . rejects . toThrow ( "Failed to get project wallets by tag" ) ;
733+ } ) ;
734+ } ) ;
735+
611736 describe ( "getAllProjectWallets" , ( ) => {
612737 it ( "fetches all wallets across pages" , async ( ) => {
613738 const wallet = new WalletDeveloperControlled ( { sdk : mockSdk } ) ;
0 commit comments