@@ -712,6 +712,138 @@ test('applies theme locally when clicking Apply button', async () => {
712712 expect ( mockThemeContext . setTemporaryTheme ) . toHaveBeenCalled ( ) ;
713713} ) ;
714714
715+ test ( 'shows Format button when modal is in edit mode' , ( ) => {
716+ render (
717+ < ThemeModal
718+ addDangerToast = { jest . fn ( ) }
719+ addSuccessToast = { jest . fn ( ) }
720+ onThemeAdd = { jest . fn ( ) }
721+ onHide = { jest . fn ( ) }
722+ show
723+ canDevelop = { false }
724+ /> ,
725+ { useRedux : true , useRouter : true } ,
726+ ) ;
727+
728+ expect ( screen . getByRole ( 'button' , { name : / f o r m a t / i } ) ) . toBeInTheDocument ( ) ;
729+ } ) ;
730+
731+ test ( 'does not show Format button for read-only system themes' , async ( ) => {
732+ render (
733+ < ThemeModal
734+ addDangerToast = { jest . fn ( ) }
735+ addSuccessToast = { jest . fn ( ) }
736+ onThemeAdd = { jest . fn ( ) }
737+ onHide = { jest . fn ( ) }
738+ show
739+ canDevelop = { false }
740+ theme = { mockSystemTheme }
741+ /> ,
742+ { useRedux : true , useRouter : true } ,
743+ ) ;
744+
745+ await screen . findByText ( 'System Theme - Read Only' ) ;
746+
747+ expect (
748+ screen . queryByRole ( 'button' , { name : / f o r m a t / i } ) ,
749+ ) . not . toBeInTheDocument ( ) ;
750+ } ) ;
751+
752+ test ( 'disables Format button when JSON is invalid' , async ( ) => {
753+ render (
754+ < ThemeModal
755+ addDangerToast = { jest . fn ( ) }
756+ addSuccessToast = { jest . fn ( ) }
757+ onThemeAdd = { jest . fn ( ) }
758+ onHide = { jest . fn ( ) }
759+ show
760+ canDevelop = { false }
761+ /> ,
762+ { useRedux : true , useRouter : true } ,
763+ ) ;
764+
765+ const jsonEditor = screen . getByTestId ( 'json-editor' ) ;
766+ userEvent . clear ( jsonEditor ) ;
767+ userEvent . type ( jsonEditor , '{invalid json' ) ;
768+
769+ await waitFor ( ( ) => {
770+ expect ( screen . getByRole ( 'button' , { name : / f o r m a t / i } ) ) . toBeDisabled ( ) ;
771+ } ) ;
772+ } ) ;
773+
774+ test ( 'enables Format button when JSON is valid' , async ( ) => {
775+ render (
776+ < ThemeModal
777+ addDangerToast = { jest . fn ( ) }
778+ addSuccessToast = { jest . fn ( ) }
779+ onThemeAdd = { jest . fn ( ) }
780+ onHide = { jest . fn ( ) }
781+ show
782+ canDevelop = { false }
783+ /> ,
784+ { useRedux : true , useRouter : true } ,
785+ ) ;
786+
787+ await addValidJsonData ( ) ;
788+
789+ await waitFor ( ( ) => {
790+ expect ( screen . getByRole ( 'button' , { name : / f o r m a t / i } ) ) . toBeEnabled ( ) ;
791+ } ) ;
792+ } ) ;
793+
794+ test ( 'Format button pretty-prints minified JSON' , async ( ) => {
795+ render (
796+ < ThemeModal
797+ addDangerToast = { jest . fn ( ) }
798+ addSuccessToast = { jest . fn ( ) }
799+ onThemeAdd = { jest . fn ( ) }
800+ onHide = { jest . fn ( ) }
801+ show
802+ canDevelop = { false }
803+ /> ,
804+ { useRedux : true , useRouter : true } ,
805+ ) ;
806+
807+ const minifiedJson = '{"token":{"colorPrimary":"#1890ff"}}' ;
808+ const jsonEditor = screen . getByTestId ( 'json-editor' ) ;
809+ userEvent . clear ( jsonEditor ) ;
810+ userEvent . type ( jsonEditor , minifiedJson ) ;
811+
812+ const formatButton = screen . getByRole ( 'button' , { name : / f o r m a t / i } ) ;
813+ userEvent . click ( formatButton ) ;
814+
815+ const expectedFormatted = JSON . stringify (
816+ { token : { colorPrimary : '#1890ff' } } ,
817+ null ,
818+ 2 ,
819+ ) ;
820+ await waitFor ( ( ) => {
821+ expect ( jsonEditor ) . toHaveValue ( expectedFormatted ) ;
822+ } ) ;
823+ } ) ;
824+
825+ test ( 'Format button is disabled when JSON editor is empty' , async ( ) => {
826+ render (
827+ < ThemeModal
828+ addDangerToast = { jest . fn ( ) }
829+ addSuccessToast = { jest . fn ( ) }
830+ onThemeAdd = { jest . fn ( ) }
831+ onHide = { jest . fn ( ) }
832+ show
833+ canDevelop = { false }
834+ /> ,
835+ { useRedux : true , useRouter : true } ,
836+ ) ;
837+
838+ // The editor initializes with `{}` — clear it to reach the empty state
839+ const jsonEditor = screen . getByTestId ( 'json-editor' ) ;
840+ userEvent . clear ( jsonEditor ) ;
841+
842+ await waitFor ( ( ) => {
843+ expect ( screen . getByRole ( 'button' , { name : / f o r m a t / i } ) ) . toBeDisabled ( ) ;
844+ } ) ;
845+ } ) ;
846+
715847test ( 'disables Apply button when JSON configuration is invalid' , async ( ) => {
716848 fetchMock . clearHistory ( ) . removeRoutes ( ) ;
717849 fetchMock . get ( 'glob:*/api/v1/theme/*' , {
0 commit comments