@@ -202,12 +202,16 @@ describe("Types", () => {
202202 expect ( ( ) =>
203203 // @ts -expect-error
204204 Schema . toData ( schema , { permissions : { canUpdate : "yes" } } ) ,
205- ) . toThrowError ( "field 'canUpdate' expected 'boolean' received 'string'" ) ;
205+ ) . toThrowError (
206+ "'test.permissions.canUpdate' expected 'boolean' received 'string'" ,
207+ ) ;
206208 // fields are validates in the order they are registered in type
207209 expect ( ( ) =>
208210 // @ts -expect-error
209211 Schema . toData ( schema , { permissions : { role : false } } ) ,
210- ) . toThrowError ( "field 'canUpdate' expected 'boolean' received 'undefined'" ) ;
212+ ) . toThrowError (
213+ "'test.permissions.canUpdate' expected 'boolean' received 'undefined'" ,
214+ ) ;
211215 // unknwon fields are rejected
212216 expect ( ( ) =>
213217 Schema . toData ( schema , {
@@ -239,7 +243,7 @@ describe("Types", () => {
239243 expect ( ( ) =>
240244 // @ts -expect-error
241245 Schema . toData ( schema , { grades : { math : "50" } } ) ,
242- ) . toThrowError ( "field ' math' expected 'number' received 'string'" ) ;
246+ ) . toThrowError ( "'test.grades. math' expected 'number' received 'string'" ) ;
243247 const data = Schema . toData ( schema , { grades : { math : 50 } } ) ;
244248 expect ( data ) . toStrictEqual ( { grades : { math : 50 } } ) ;
245249 } ) ;
@@ -255,7 +259,7 @@ describe("Types", () => {
255259 ) ;
256260 // @ts -expect-error
257261 expect ( ( ) => Schema . toData ( schema , { items : [ ] } ) ) . toThrowError (
258- "element at index ' 0' expected 'number' received 'undefined'" ,
262+ "'test.items. 0' expected 'number' received 'undefined'" ,
259263 ) ;
260264 const data = Schema . toData ( schema , { items : [ 0 , "1" ] } ) ;
261265 expect ( data ) . toStrictEqual ( { items : [ 0 , "1" ] } ) ;
@@ -278,7 +282,7 @@ describe("Types", () => {
278282 expect ( ( ) => Schema . toData ( schema , { items : [ ] } ) ) . not . toThrowError ( ) ;
279283 // @ts -expect-error
280284 expect ( ( ) => Schema . toData ( schema , { items : [ 0 , "1" ] } ) ) . toThrowError (
281- "element at index ' 1' expected 'number' received 'string'" ,
285+ "'test.items. 1' expected 'number' received 'string'" ,
282286 ) ;
283287 const data = Schema . toData ( schema , { items : [ 0 , 1 ] } ) ;
284288 expect ( data ) . toStrictEqual ( { items : [ 0 , 1 ] } ) ;
@@ -472,6 +476,130 @@ describe("Types", () => {
472476 } ) ;
473477 } ) ;
474478
479+ describe ( "error handling for nested structures" , ( ) => {
480+ test ( "deeply nested objects" , ( ) => {
481+ const schema = createSchema ( "test" , {
482+ user : object ( {
483+ profile : object ( {
484+ contact : object ( {
485+ email : string ( ) . pattern ( / ^ [ ^ \s @ ] + @ [ ^ \s @ ] + \. [ ^ \s @ ] + $ / ) ,
486+ phone : object ( {
487+ country : string ( ) . length ( 2 ) ,
488+ number : string ( ) . pattern ( / ^ \d { 10 } $ / ) ,
489+ } ) ,
490+ } ) ,
491+ } ) ,
492+ } ) ,
493+ } ) ;
494+
495+ expect ( ( ) =>
496+ Schema . toData ( schema , {
497+ user : {
498+ profile : {
499+ contact : {
500+ email : "invalid" ,
501+ phone : { country : "USA" , number : "123" } ,
502+ } ,
503+ } ,
504+ } ,
505+ } ) ,
506+ ) . toThrowError (
507+ "'test.user.profile.contact.email' string must match pattern /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/" ,
508+ ) ;
509+
510+ expect ( ( ) =>
511+ Schema . toData ( schema , {
512+ user : {
513+ profile : {
514+ contact : {
515+ email : "test@example.com" ,
516+ phone : { country : "USA" , number : "123" } ,
517+ } ,
518+ } ,
519+ } ,
520+ } ) ,
521+ ) . toThrowError (
522+ "'test.user.profile.contact.phone.country' string must be exactly 2 characters long" ,
523+ ) ;
524+ } ) ;
525+
526+ test ( "array of objects" , ( ) => {
527+ const schema = createSchema ( "test" , {
528+ users : array (
529+ object ( {
530+ name : string ( ) . nonEmpty ( ) ,
531+ age : number ( ) . min ( 0 ) ,
532+ contacts : array (
533+ object ( {
534+ type : literal ( "email" , "phone" ) ,
535+ value : string ( ) . nonEmpty ( ) ,
536+ } ) ,
537+ ) ,
538+ } ) ,
539+ ) ,
540+ } ) ;
541+
542+ expect ( ( ) =>
543+ Schema . toData ( schema , {
544+ users : [
545+ {
546+ name : "John" ,
547+ age : - 1 ,
548+ contacts : [ { type : "email" , value : "john@example.com" } ] ,
549+ } ,
550+ ] ,
551+ } ) ,
552+ ) . toThrowError (
553+ "'test.users.0.age' number must be greater than or equal to 0" ,
554+ ) ;
555+
556+ expect ( ( ) =>
557+ Schema . toData ( schema , {
558+ users : [
559+ {
560+ name : "John" ,
561+ age : 30 ,
562+ // @ts -expect-error
563+ contacts : [ { type : "invalid" , value : "john@example.com" } ] ,
564+ } ,
565+ ] ,
566+ } ) ,
567+ ) . toThrowError (
568+ "'test.users.0.contacts.0.type' unknown value 'invalid', literal may only specify known values" ,
569+ ) ;
570+ } ) ;
571+
572+ test ( "nested tuples" , ( ) => {
573+ const schema = createSchema ( "test" , {
574+ coordinates : array (
575+ tuple ( [
576+ number ( )
577+ . min ( - 90 )
578+ . max ( 90 ) , // latitude
579+ number ( )
580+ . min ( - 180 )
581+ . max ( 180 ) , // longitude
582+ array ( string ( ) . nonEmpty ( ) ) , // tags
583+ ] ) ,
584+ ) ,
585+ } ) ;
586+
587+ expect ( ( ) =>
588+ Schema . toData ( schema , {
589+ coordinates : [ [ 91 , 0 , [ "north" ] ] ] ,
590+ } ) ,
591+ ) . toThrowError (
592+ "'test.coordinates.0.0' number must be less than or equal to 90" ,
593+ ) ;
594+
595+ expect ( ( ) =>
596+ Schema . toData ( schema , {
597+ coordinates : [ [ 0 , 0 , [ "" ] ] ] ,
598+ } ) ,
599+ ) . toThrowError ( "'test.coordinates.0.2.0' string must not be empty" ) ;
600+ } ) ;
601+ } ) ;
602+
475603 describe ( "date" , ( ) => {
476604 const now = new Date ( ) ;
477605 const past = new Date ( now . getTime ( ) - 1000 * 60 * 60 * 24 * 2 ) ; // 2 days ago
0 commit comments