@@ -11,9 +11,35 @@ import {
1111 decodeArgLegacy ,
1212 decodeAllArgs ,
1313 decomposeArgHex ,
14+ normalizeFieldName ,
1415} from "../../lib/codec" ;
1516import { createMockDedotClient } from "../helpers/mock-client" ;
1617
18+ // ---------------------------------------------------------------------------
19+ // normalizeFieldName
20+ // ---------------------------------------------------------------------------
21+ describe ( "normalizeFieldName" , ( ) => {
22+ it ( "converts snake_case to camelCase" , ( ) => {
23+ expect ( normalizeFieldName ( "ref_time" ) ) . toBe ( "refTime" ) ;
24+ expect ( normalizeFieldName ( "proof_size" ) ) . toBe ( "proofSize" ) ;
25+ expect ( normalizeFieldName ( "storage_deposit_limit" ) ) . toBe ( "storageDepositLimit" ) ;
26+ } ) ;
27+
28+ it ( "preserves already camelCase names" , ( ) => {
29+ expect ( normalizeFieldName ( "refTime" ) ) . toBe ( "refTime" ) ;
30+ expect ( normalizeFieldName ( "proofSize" ) ) . toBe ( "proofSize" ) ;
31+ } ) ;
32+
33+ it ( "handles hash prefix replacement" , ( ) => {
34+ expect ( normalizeFieldName ( "#field_name" ) ) . toBe ( "fieldName" ) ;
35+ } ) ;
36+
37+ it ( "handles single word names" , ( ) => {
38+ expect ( normalizeFieldName ( "value" ) ) . toBe ( "value" ) ;
39+ expect ( normalizeFieldName ( "dest" ) ) . toBe ( "dest" ) ;
40+ } ) ;
41+ } ) ;
42+
1743// ---------------------------------------------------------------------------
1844// encodeArg
1945// ---------------------------------------------------------------------------
@@ -827,6 +853,82 @@ describe("decomposeArgHex", () => {
827853 }
828854 } ) ;
829855
856+ it ( "normalizes snake_case metadata field names to camelCase for value lookup" , ( ) => {
857+ // This is the exact scenario from gas estimation auto-fill:
858+ // Metadata has snake_case fields (ref_time, proof_size) but the auto-filled
859+ // value object uses camelCase (refTime, proofSize) matching Dedot's convention.
860+ const tryEncode = jest . fn ( ) . mockReturnValue ( new Uint8Array ( [ 0x01 ] ) ) ;
861+ const client = createMockDedotClient ( {
862+ registry : {
863+ findCodec : jest . fn ( ) . mockReturnValue ( {
864+ tryEncode,
865+ tryDecode : jest . fn ( ) ,
866+ } ) ,
867+ findType : jest . fn ( ) . mockReturnValue ( {
868+ typeDef : {
869+ type : "Struct" ,
870+ value : {
871+ fields : [
872+ { name : "ref_time" , typeId : 10 } ,
873+ { name : "proof_size" , typeId : 20 } ,
874+ ] ,
875+ } ,
876+ } ,
877+ } ) ,
878+ } ,
879+ } ) ;
880+ // Value uses camelCase keys (as produced by gas estimation auto-fill)
881+ const result = decomposeArgHex ( client , 1 , {
882+ refTime : "117234441" ,
883+ proofSize : "135850" ,
884+ } ) ;
885+ expect ( result . kind ) . toBe ( "compound" ) ;
886+ if ( result . kind === "compound" ) {
887+ expect ( result . compoundType ) . toBe ( "Struct" ) ;
888+ expect ( result . children ) . toHaveLength ( 2 ) ;
889+ // Labels should be normalized to camelCase
890+ expect ( result . children [ 0 ] . label ) . toBe ( "refTime" ) ;
891+ expect ( result . children [ 1 ] . label ) . toBe ( "proofSize" ) ;
892+ // Encoder should have been called with coerced values (BigInt), not undefined
893+ expect ( tryEncode ) . toHaveBeenCalledWith ( BigInt ( "117234441" ) ) ;
894+ expect ( tryEncode ) . toHaveBeenCalledWith ( BigInt ( "135850" ) ) ;
895+ }
896+ } ) ;
897+
898+ it ( "handles already-camelCase metadata field names without double-normalizing" , ( ) => {
899+ const tryEncode = jest . fn ( ) . mockReturnValue ( new Uint8Array ( [ 0x01 ] ) ) ;
900+ const client = createMockDedotClient ( {
901+ registry : {
902+ findCodec : jest . fn ( ) . mockReturnValue ( {
903+ tryEncode,
904+ tryDecode : jest . fn ( ) ,
905+ } ) ,
906+ findType : jest . fn ( ) . mockReturnValue ( {
907+ typeDef : {
908+ type : "Struct" ,
909+ value : {
910+ fields : [
911+ { name : "refTime" , typeId : 10 } ,
912+ { name : "proofSize" , typeId : 20 } ,
913+ ] ,
914+ } ,
915+ } ,
916+ } ) ,
917+ } ,
918+ } ) ;
919+ const result = decomposeArgHex ( client , 1 , {
920+ refTime : "100" ,
921+ proofSize : "200" ,
922+ } ) ;
923+ expect ( result . kind ) . toBe ( "compound" ) ;
924+ if ( result . kind === "compound" ) {
925+ expect ( result . children [ 0 ] . label ) . toBe ( "refTime" ) ;
926+ expect ( result . children [ 1 ] . label ) . toBe ( "proofSize" ) ;
927+ expect ( tryEncode ) . toHaveBeenCalledWith ( BigInt ( "100" ) ) ;
928+ expect ( tryEncode ) . toHaveBeenCalledWith ( BigInt ( "200" ) ) ;
929+ }
930+ } ) ;
931+
830932 it ( "decomposes Enum single-field variant" , ( ) => {
831933 const tryEncode = jest . fn ( ) . mockReturnValue ( new Uint8Array ( [ 0x01 ] ) ) ;
832934 const client = createMockDedotClient ( {
0 commit comments