@@ -18,6 +18,7 @@ import {ToolboxTool} from '../../src/toolbox_core/tool';
18
18
import { AxiosError } from 'axios' ;
19
19
import { CustomGlobal } from './types' ;
20
20
import { authTokenGetter } from './utils' ;
21
+ import { ZodOptional , ZodNullable , ZodTypeAny } from 'zod' ;
21
22
22
23
describe ( 'ToolboxClient E2E Tests' , ( ) => {
23
24
let commonToolboxClient : ToolboxClient ;
@@ -316,4 +317,180 @@ describe('ToolboxClient E2E Tests', () => {
316
317
}
317
318
} ) ;
318
319
} ) ;
320
+
321
+ describe ( 'Optional Params E2E Tests' , ( ) => {
322
+ let searchRowsTool : ReturnType < typeof ToolboxTool > ;
323
+
324
+ beforeAll ( async ( ) => {
325
+ searchRowsTool = await commonToolboxClient . loadTool ( 'search-rows' ) ;
326
+ } ) ;
327
+
328
+ it ( 'should correctly identify required and optional parameters in the schema' , ( ) => {
329
+ const paramSchema = searchRowsTool . getParamSchema ( ) ;
330
+ const { shape} = paramSchema ;
331
+
332
+ // Required param 'email'
333
+ expect ( shape . email . isOptional ( ) ) . toBe ( false ) ;
334
+ expect ( shape . email . isNullable ( ) ) . toBe ( false ) ;
335
+ expect ( shape . email . _def . typeName ) . toBe ( 'ZodString' ) ;
336
+
337
+ // Optional param 'data'
338
+ expect ( shape . data . isOptional ( ) ) . toBe ( true ) ;
339
+ expect ( shape . data . isNullable ( ) ) . toBe ( true ) ;
340
+ expect (
341
+ ( shape . data as ZodOptional < ZodNullable < ZodTypeAny > > ) . unwrap ( ) . unwrap ( )
342
+ . _def . typeName
343
+ ) . toBe ( 'ZodString' ) ;
344
+
345
+ // Optional param 'id'
346
+ expect ( shape . id . isOptional ( ) ) . toBe ( true ) ;
347
+ expect ( shape . id . isNullable ( ) ) . toBe ( true ) ;
348
+ expect (
349
+ ( shape . id as ZodOptional < ZodNullable < ZodTypeAny > > ) . unwrap ( ) . unwrap ( )
350
+ . _def . typeName
351
+ ) . toBe ( 'ZodNumber' ) ;
352
+ } ) ;
353
+
354
+ it ( 'should run tool with optional params omitted' , async ( ) => {
355
+ const response = await searchRowsTool ( { email :
'[email protected] ' } ) ;
356
+ expect ( typeof response ) . toBe ( 'string' ) ;
357
+ expect ( response ) . toContain ( '\\"email\\":\\"[email protected] \\"' ) ;
358
+ expect ( response ) . not . toContain ( 'row1' ) ;
359
+ expect ( response ) . toContain ( 'row2' ) ;
360
+ expect ( response ) . not . toContain ( 'row3' ) ;
361
+ expect ( response ) . not . toContain ( 'row4' ) ;
362
+ expect ( response ) . not . toContain ( 'row5' ) ;
363
+ expect ( response ) . not . toContain ( 'row6' ) ;
364
+ } ) ;
365
+
366
+ it ( 'should run tool with optional data provided' , async ( ) => {
367
+ const response = await searchRowsTool ( {
368
+
369
+ data : 'row3' ,
370
+ } ) ;
371
+ expect ( typeof response ) . toBe ( 'string' ) ;
372
+ expect ( response ) . toContain ( '\\"email\\":\\"[email protected] \\"' ) ;
373
+ expect ( response ) . not . toContain ( 'row1' ) ;
374
+ expect ( response ) . not . toContain ( 'row2' ) ;
375
+ expect ( response ) . toContain ( 'row3' ) ;
376
+ expect ( response ) . not . toContain ( 'row4' ) ;
377
+ expect ( response ) . not . toContain ( 'row5' ) ;
378
+ expect ( response ) . not . toContain ( 'row6' ) ;
379
+ } ) ;
380
+
381
+ it ( 'should run tool with optional data as null' , async ( ) => {
382
+ const response = await searchRowsTool ( {
383
+
384
+ data : null ,
385
+ } ) ;
386
+ expect ( typeof response ) . toBe ( 'string' ) ;
387
+ expect ( response ) . toContain ( '\\"email\\":\\"[email protected] \\"' ) ;
388
+ expect ( response ) . not . toContain ( 'row1' ) ;
389
+ expect ( response ) . toContain ( 'row2' ) ;
390
+ expect ( response ) . not . toContain ( 'row3' ) ;
391
+ expect ( response ) . not . toContain ( 'row4' ) ;
392
+ expect ( response ) . not . toContain ( 'row5' ) ;
393
+ expect ( response ) . not . toContain ( 'row6' ) ;
394
+ } ) ;
395
+
396
+ it ( 'should run tool with optional id provided' , async ( ) => {
397
+ const response = await searchRowsTool ( {
398
+
399
+ id : 1 ,
400
+ } ) ;
401
+ expect ( typeof response ) . toBe ( 'string' ) ;
402
+ expect ( response ) . toBe ( '{"result":"null"}' ) ;
403
+ } ) ;
404
+
405
+ it ( 'should run tool with optional id as null' , async ( ) => {
406
+ const response = await searchRowsTool ( {
407
+
408
+ id : null ,
409
+ } ) ;
410
+ expect ( typeof response ) . toBe ( 'string' ) ;
411
+ expect ( response ) . toContain ( '\\"email\\":\\"[email protected] \\"' ) ;
412
+ expect ( response ) . not . toContain ( 'row1' ) ;
413
+ expect ( response ) . toContain ( 'row2' ) ;
414
+ expect ( response ) . not . toContain ( 'row3' ) ;
415
+ expect ( response ) . not . toContain ( 'row4' ) ;
416
+ expect ( response ) . not . toContain ( 'row5' ) ;
417
+ expect ( response ) . not . toContain ( 'row6' ) ;
418
+ } ) ;
419
+
420
+ it ( 'should fail when a required param is missing' , async ( ) => {
421
+ await expect ( searchRowsTool ( { id : 5 , data : 'row5' } ) ) . rejects . toThrow (
422
+ / A r g u m e n t v a l i d a t i o n f a i l e d f o r t o o l " s e a r c h - r o w s " : \s * - e m a i l : R e q u i r e d /
423
+ ) ;
424
+ } ) ;
425
+
426
+ it ( 'should fail when a required param is null' , async ( ) => {
427
+ await expect (
428
+ searchRowsTool ( { email : null , id : 5 , data : 'row5' } )
429
+ ) . rejects . toThrow (
430
+ / A r g u m e n t v a l i d a t i o n f a i l e d f o r t o o l " s e a r c h - r o w s " : \s * - e m a i l : E x p e c t e d s t r i n g , r e c e i v e d n u l l /
431
+ ) ;
432
+ } ) ;
433
+
434
+ it ( 'should run tool with all default params' , async ( ) => {
435
+ const response = await searchRowsTool ( {
436
+
437
+ id : 0 ,
438
+ data : 'row2' ,
439
+ } ) ;
440
+ expect ( typeof response ) . toBe ( 'string' ) ;
441
+ expect ( response ) . toContain ( '\\"email\\":\\"[email protected] \\"' ) ;
442
+ expect ( response ) . not . toContain ( 'row1' ) ;
443
+ expect ( response ) . toContain ( 'row2' ) ;
444
+ expect ( response ) . not . toContain ( 'row3' ) ;
445
+ expect ( response ) . not . toContain ( 'row4' ) ;
446
+ expect ( response ) . not . toContain ( 'row5' ) ;
447
+ expect ( response ) . not . toContain ( 'row6' ) ;
448
+ } ) ;
449
+
450
+ it ( 'should run tool with all valid params' , async ( ) => {
451
+ const response = await searchRowsTool ( {
452
+
453
+ id : 3 ,
454
+ data : 'row3' ,
455
+ } ) ;
456
+ expect ( typeof response ) . toBe ( 'string' ) ;
457
+ expect ( response ) . toContain ( '\\"email\\":\\"[email protected] \\"' ) ;
458
+ expect ( response ) . not . toContain ( 'row1' ) ;
459
+ expect ( response ) . not . toContain ( 'row2' ) ;
460
+ expect ( response ) . toContain ( 'row3' ) ;
461
+ expect ( response ) . not . toContain ( 'row4' ) ;
462
+ expect ( response ) . not . toContain ( 'row5' ) ;
463
+ expect ( response ) . not . toContain ( 'row6' ) ;
464
+ } ) ;
465
+
466
+ it ( 'should return null when called with a different email' , async ( ) => {
467
+ const response = await searchRowsTool ( {
468
+
469
+ id : 3 ,
470
+ data : 'row3' ,
471
+ } ) ;
472
+ expect ( typeof response ) . toBe ( 'string' ) ;
473
+ expect ( response ) . toBe ( '{"result":"null"}' ) ;
474
+ } ) ;
475
+
476
+ it ( 'should return null when called with different data' , async ( ) => {
477
+ const response = await searchRowsTool ( {
478
+
479
+ id : 3 ,
480
+ data : 'row4' ,
481
+ } ) ;
482
+ expect ( typeof response ) . toBe ( 'string' ) ;
483
+ expect ( response ) . toBe ( '{"result":"null"}' ) ;
484
+ } ) ;
485
+
486
+ it ( 'should return null when called with a different id' , async ( ) => {
487
+ const response = await searchRowsTool ( {
488
+
489
+ id : 4 ,
490
+ data : 'row3' ,
491
+ } ) ;
492
+ expect ( typeof response ) . toBe ( 'string' ) ;
493
+ expect ( response ) . toBe ( '{"result":"null"}' ) ;
494
+ } ) ;
495
+ } ) ;
319
496
} ) ;
0 commit comments