@@ -290,6 +290,146 @@ describe("ConfigClient", () => {
290290 } ) ;
291291 } ) ;
292292
293+ describe ( "setNumber()" , ( ) => {
294+ it ( "calls setField with numberValue" , async ( ) => {
295+ configStub . setField . mockImplementation (
296+ ( _req : unknown , _meta : unknown , _opts : unknown , cb : ( ...args : unknown [ ] ) => void ) => {
297+ cb ( null , { configVersion : { version : 1 } } ) ;
298+ } ,
299+ ) ;
300+
301+ await client . setNumber ( "tenant-1" , "payments.fee" , 0.05 ) ;
302+
303+ const callArgs = configStub . setField . mock . calls [ 0 ] ;
304+ expect ( callArgs ?. [ 0 ] ) . toEqual ( {
305+ tenantId : "tenant-1" ,
306+ fieldPath : "payments.fee" ,
307+ value : { numberValue : 0.05 } ,
308+ expectedChecksum : undefined ,
309+ } ) ;
310+ } ) ;
311+
312+ it ( "passes expectedChecksum" , async ( ) => {
313+ configStub . setField . mockImplementation (
314+ ( _req : unknown , _meta : unknown , _opts : unknown , cb : ( ...args : unknown [ ] ) => void ) => {
315+ cb ( null , { configVersion : { version : 1 } } ) ;
316+ } ,
317+ ) ;
318+
319+ await client . setNumber ( "tenant-1" , "payments.fee" , 42 , { expectedChecksum : "cs1" } ) ;
320+
321+ const callArgs = configStub . setField . mock . calls [ 0 ] ;
322+ expect ( callArgs ?. [ 0 ] . expectedChecksum ) . toBe ( "cs1" ) ;
323+ } ) ;
324+ } ) ;
325+
326+ describe ( "setBool()" , ( ) => {
327+ it ( "calls setField with boolValue" , async ( ) => {
328+ configStub . setField . mockImplementation (
329+ ( _req : unknown , _meta : unknown , _opts : unknown , cb : ( ...args : unknown [ ] ) => void ) => {
330+ cb ( null , { configVersion : { version : 1 } } ) ;
331+ } ,
332+ ) ;
333+
334+ await client . setBool ( "tenant-1" , "feature.enabled" , true ) ;
335+
336+ const callArgs = configStub . setField . mock . calls [ 0 ] ;
337+ expect ( callArgs ?. [ 0 ] ) . toEqual ( {
338+ tenantId : "tenant-1" ,
339+ fieldPath : "feature.enabled" ,
340+ value : { boolValue : true } ,
341+ expectedChecksum : undefined ,
342+ } ) ;
343+ } ) ;
344+
345+ it ( "sends false correctly" , async ( ) => {
346+ configStub . setField . mockImplementation (
347+ ( _req : unknown , _meta : unknown , _opts : unknown , cb : ( ...args : unknown [ ] ) => void ) => {
348+ cb ( null , { configVersion : { version : 1 } } ) ;
349+ } ,
350+ ) ;
351+
352+ await client . setBool ( "tenant-1" , "feature.enabled" , false ) ;
353+
354+ const callArgs = configStub . setField . mock . calls [ 0 ] ;
355+ expect ( callArgs ?. [ 0 ] . value ) . toEqual ( { boolValue : false } ) ;
356+ } ) ;
357+ } ) ;
358+
359+ describe ( "setTime()" , ( ) => {
360+ it ( "calls setField with timeValue" , async ( ) => {
361+ configStub . setField . mockImplementation (
362+ ( _req : unknown , _meta : unknown , _opts : unknown , cb : ( ...args : unknown [ ] ) => void ) => {
363+ cb ( null , { configVersion : { version : 1 } } ) ;
364+ } ,
365+ ) ;
366+
367+ const d = new Date ( "2024-01-15T12:00:00Z" ) ;
368+ await client . setTime ( "tenant-1" , "expiry.date" , d ) ;
369+
370+ const callArgs = configStub . setField . mock . calls [ 0 ] ;
371+ expect ( callArgs ?. [ 0 ] ) . toEqual ( {
372+ tenantId : "tenant-1" ,
373+ fieldPath : "expiry.date" ,
374+ value : { timeValue : d } ,
375+ expectedChecksum : undefined ,
376+ } ) ;
377+ } ) ;
378+ } ) ;
379+
380+ describe ( "setDuration()" , ( ) => {
381+ it ( "calls setField with stringValue for duration string" , async ( ) => {
382+ configStub . setField . mockImplementation (
383+ ( _req : unknown , _meta : unknown , _opts : unknown , cb : ( ...args : unknown [ ] ) => void ) => {
384+ cb ( null , { configVersion : { version : 1 } } ) ;
385+ } ,
386+ ) ;
387+
388+ await client . setDuration ( "tenant-1" , "cache.ttl" , "1h30m" ) ;
389+
390+ const callArgs = configStub . setField . mock . calls [ 0 ] ;
391+ expect ( callArgs ?. [ 0 ] ) . toEqual ( {
392+ tenantId : "tenant-1" ,
393+ fieldPath : "cache.ttl" ,
394+ value : { stringValue : "1h30m" } ,
395+ expectedChecksum : undefined ,
396+ } ) ;
397+ } ) ;
398+ } ) ;
399+
400+ describe ( "setMany() typed values" , ( ) => {
401+ it ( "converts mixed types to typed proto values" , async ( ) => {
402+ configStub . setFields . mockImplementation (
403+ ( _req : unknown , _meta : unknown , _opts : unknown , cb : ( ...args : unknown [ ] ) => void ) => {
404+ cb ( null , { configVersion : { version : 2 } } ) ;
405+ } ,
406+ ) ;
407+
408+ const d = new Date ( "2024-06-01T00:00:00Z" ) ;
409+ await client . setMany ( "tenant-1" , {
410+ "payments.fee" : 0.05 ,
411+ "feature.enabled" : true ,
412+ "app.name" : "myapp" ,
413+ "expiry.date" : d ,
414+ } ) ;
415+
416+ const callArgs = configStub . setFields . mock . calls [ 0 ] ;
417+ const updates : Array < { fieldPath : string ; value : unknown } > = callArgs ?. [ 0 ] . updates ;
418+ expect ( updates . find ( ( u ) => u . fieldPath === "payments.fee" ) ?. value ) . toEqual ( {
419+ numberValue : 0.05 ,
420+ } ) ;
421+ expect ( updates . find ( ( u ) => u . fieldPath === "feature.enabled" ) ?. value ) . toEqual ( {
422+ boolValue : true ,
423+ } ) ;
424+ expect ( updates . find ( ( u ) => u . fieldPath === "app.name" ) ?. value ) . toEqual ( {
425+ stringValue : "myapp" ,
426+ } ) ;
427+ expect ( updates . find ( ( u ) => u . fieldPath === "expiry.date" ) ?. value ) . toEqual ( {
428+ timeValue : d ,
429+ } ) ;
430+ } ) ;
431+ } ) ;
432+
293433 describe ( "expectedChecksum plumbing" , ( ) => {
294434 it ( "set() passes expectedChecksum to proto" , async ( ) => {
295435 configStub . setField . mockImplementation (
0 commit comments