@@ -202,6 +202,55 @@ describe("DynamicJsonForm String Fields", () => {
202202 fireEvent . change ( select , { target : { value : "amber" } } ) ;
203203 expect ( onChange ) . toHaveBeenCalledWith ( "amber" ) ;
204204 } ) ;
205+
206+ it ( "should render anyOf with const/title for labeled options and show description" , ( ) => {
207+ const onChange = jest . fn ( ) ;
208+ const schema : JsonSchemaType = {
209+ type : "string" ,
210+ title : "Heroes" ,
211+ description : "Choose a hero" ,
212+ anyOf : [
213+ { const : "hero-1" , title : "Superman" } ,
214+ { const : "hero-2" , title : "Batman" } ,
215+ ] ,
216+ } ;
217+ render ( < DynamicJsonForm schema = { schema } value = "" onChange = { onChange } /> ) ;
218+
219+ // Description should be visible above the select
220+ expect ( screen . getByText ( "Choose a hero" ) ) . toBeInTheDocument ( ) ;
221+ const select = screen . getByRole ( "combobox" ) ;
222+ const options = screen . getAllByRole ( "option" ) ;
223+ expect ( options ) . toHaveLength ( 3 ) ;
224+ expect ( options [ 1 ] ) . toHaveProperty ( "textContent" , "Superman" ) ;
225+ expect ( options [ 2 ] ) . toHaveProperty ( "textContent" , "Batman" ) ;
226+
227+ fireEvent . change ( select , { target : { value : "hero-2" } } ) ;
228+ expect ( onChange ) . toHaveBeenCalledWith ( "hero-2" ) ;
229+ } ) ;
230+
231+ it ( "should render legacy enum with enumNames as labels" , ( ) => {
232+ const onChange = jest . fn ( ) ;
233+ const schema : JsonSchemaType = {
234+ type : "string" ,
235+ title : "Pets" ,
236+ description : "Choose a pet" ,
237+ enum : [ "pet-1" , "pet-2" , "pet-3" ] ,
238+ enumNames : [ "Cat" , "Dog" , "Bird" ] ,
239+ } as unknown as JsonSchemaType ; // enumNames is legacy extension
240+
241+ render ( < DynamicJsonForm schema = { schema } value = "" onChange = { onChange } /> ) ;
242+
243+ // Description should be visible above the select
244+ expect ( screen . getByText ( "Choose a pet" ) ) . toBeInTheDocument ( ) ;
245+ const options = screen . getAllByRole ( "option" ) ;
246+ expect ( options [ 1 ] ) . toHaveProperty ( "textContent" , "Cat" ) ;
247+ expect ( options [ 2 ] ) . toHaveProperty ( "textContent" , "Dog" ) ;
248+ expect ( options [ 3 ] ) . toHaveProperty ( "textContent" , "Bird" ) ;
249+
250+ const select = screen . getByRole ( "combobox" ) ;
251+ fireEvent . change ( select , { target : { value : "pet-2" } } ) ;
252+ expect ( onChange ) . toHaveBeenCalledWith ( "pet-2" ) ;
253+ } ) ;
205254 } ) ;
206255
207256 describe ( "Validation Attributes" , ( ) => {
@@ -535,8 +584,8 @@ describe("DynamicJsonForm Object Fields", () => {
535584 < DynamicJsonForm schema = { schema } value = { { } } onChange = { jest . fn ( ) } /> ,
536585 ) ;
537586
538- const nameLabel = screen . getByText ( "name " ) ;
539- const optionalLabel = screen . getByText ( "optional " ) ;
587+ const nameLabel = screen . getByText ( "Name " ) ;
588+ const optionalLabel = screen . getByText ( "Optional " ) ;
540589
541590 const nameInput = nameLabel . closest ( "div" ) ?. querySelector ( "input" ) ;
542591 const optionalInput = optionalLabel
@@ -567,30 +616,46 @@ describe("DynamicJsonForm Complex Fields", () => {
567616 } ;
568617
569618 describe ( "Basic Operations" , ( ) => {
570- it ( "should render textbox and autoformat button, but no switch-to-form button " , ( ) => {
619+ it ( "should allow switching to JSON mode and show copy/format buttons " , ( ) => {
571620 renderForm ( ) ;
621+
622+ // Initially renders as a form with a Switch to JSON button
623+ const switchToJson = screen . getByRole ( "button" , {
624+ name : / s w i t c h t o j s o n / i,
625+ } ) ;
626+ expect ( switchToJson ) . toBeInTheDocument ( ) ;
627+
628+ // Switch to JSON mode
629+ fireEvent . click ( switchToJson ) ;
630+
631+ // Now a textarea and JSON helpers should be visible
572632 const input = screen . getByRole ( "textbox" ) ;
573633 expect ( input ) . toHaveProperty ( "type" , "textarea" ) ;
574- const buttons = screen . getAllByRole ( "button" ) ;
575- expect ( buttons ) . toHaveLength ( 2 ) ; // Copy JSON + Format JSON
576634 const copyButton = screen . getByRole ( "button" , { name : / c o p y j s o n / i } ) ;
577635 const formatButton = screen . getByRole ( "button" , { name : / f o r m a t j s o n / i } ) ;
578636 expect ( copyButton ) . toBeTruthy ( ) ;
579637 expect ( formatButton ) . toBeTruthy ( ) ;
638+ // And a Switch to Form button should appear
639+ expect (
640+ screen . getByRole ( "button" , { name : / s w i t c h t o f o r m / i } ) ,
641+ ) . toBeInTheDocument ( ) ;
580642 } ) ;
581643
582- it ( "should pass changed values to onChange" , ( ) => {
644+ it ( "should pass changed values to onChange in JSON mode " , ( ) => {
583645 const onChange = jest . fn ( ) ;
584646 renderForm ( { onChange } ) ;
585647
648+ // Switch to JSON mode first
649+ fireEvent . click ( screen . getByRole ( "button" , { name : / s w i t c h t o j s o n / i } ) ) ;
650+
586651 const input = screen . getByRole ( "textbox" ) ;
587652 fireEvent . change ( input , {
588653 target : { value : `{ "nested": "i am string" }` } ,
589654 } ) ;
590655
591656 // The onChange handler is debounced when using the JSON view, so we need to wait a little bit
592- waitFor ( ( ) => {
593- expect ( onChange ) . toHaveBeenCalledWith ( `{ " nested" : "i am string" }` ) ;
657+ return waitFor ( ( ) => {
658+ expect ( onChange ) . toHaveBeenCalledWith ( { nested : "i am string" } ) ;
594659 } ) ;
595660 } ) ;
596661 } ) ;
@@ -626,6 +691,10 @@ describe("DynamicJsonForm Copy JSON Functionality", () => {
626691 it ( "should render Copy JSON button when in JSON mode" , ( ) => {
627692 renderFormInJsonMode ( ) ;
628693
694+ // Switch to JSON mode to reveal copy/format buttons
695+ const switchBtn = screen . getByRole ( "button" , { name : / s w i t c h t o j s o n / i } ) ;
696+ fireEvent . click ( switchBtn ) ;
697+
629698 const copyButton = screen . getByRole ( "button" , { name : "Copy JSON" } ) ;
630699 expect ( copyButton ) . toBeTruthy ( ) ;
631700 } ) ;
@@ -653,6 +722,10 @@ describe("DynamicJsonForm Copy JSON Functionality", () => {
653722
654723 renderFormInJsonMode ( { value : testValue } ) ;
655724
725+ // Switch to JSON mode first
726+ const switchBtn = screen . getByRole ( "button" , { name : / s w i t c h t o j s o n / i } ) ;
727+ fireEvent . click ( switchBtn ) ;
728+
656729 const copyButton = screen . getByRole ( "button" , { name : "Copy JSON" } ) ;
657730 fireEvent . click ( copyButton ) ;
658731
@@ -768,6 +841,10 @@ describe("DynamicJsonForm Validation Functionality", () => {
768841 it ( "should return valid for valid JSON in JSON mode" , ( ) => {
769842 renderFormWithRef ( ) ;
770843
844+ // Switch to JSON mode to enable textarea editing/validation
845+ const switchBtn = screen . getByRole ( "button" , { name : / s w i t c h t o j s o n / i } ) ;
846+ fireEvent . click ( switchBtn ) ;
847+
771848 const validateButton = screen . getByTestId ( "validate-button" ) ;
772849 fireEvent . click ( validateButton ) ;
773850
@@ -778,6 +855,10 @@ describe("DynamicJsonForm Validation Functionality", () => {
778855 it ( "should return invalid for malformed JSON in JSON mode" , async ( ) => {
779856 renderFormWithRef ( ) ;
780857
858+ // Switch to JSON mode first
859+ const switchBtn = screen . getByRole ( "button" , { name : / s w i t c h t o j s o n / i } ) ;
860+ fireEvent . click ( switchBtn ) ;
861+
781862 // Enter invalid JSON
782863 const textarea = screen . getByRole ( "textbox" ) ;
783864 fireEvent . change ( textarea , { target : { value : '{ "invalid": json }' } } ) ;
@@ -799,6 +880,10 @@ describe("DynamicJsonForm Validation Functionality", () => {
799880 it ( "should return valid for empty JSON in JSON mode" , ( ) => {
800881 renderFormWithRef ( ) ;
801882
883+ // Switch to JSON mode first
884+ const switchBtn = screen . getByRole ( "button" , { name : / s w i t c h t o j s o n / i } ) ;
885+ fireEvent . click ( switchBtn ) ;
886+
802887 // Clear the textarea
803888 const textarea = screen . getByRole ( "textbox" ) ;
804889 fireEvent . change ( textarea , { target : { value : "" } } ) ;
@@ -813,6 +898,10 @@ describe("DynamicJsonForm Validation Functionality", () => {
813898 it ( "should set error state when validation fails" , async ( ) => {
814899 renderFormWithRef ( ) ;
815900
901+ // Switch to JSON mode first
902+ const switchBtn = screen . getByRole ( "button" , { name : / s w i t c h t o j s o n / i } ) ;
903+ fireEvent . click ( switchBtn ) ;
904+
816905 // Enter invalid JSON
817906 const textarea = screen . getByRole ( "textbox" ) ;
818907 fireEvent . change ( textarea , {
0 commit comments