@@ -3156,6 +3156,32 @@ describe('form api', () => {
3156
3156
await form . handleSubmit ( )
3157
3157
} )
3158
3158
3159
+ it ( 'should call onSubmitInvalid when submitting while canSubmit is false (e.g., onMount error present)' , async ( ) => {
3160
+ const onInvalid = vi . fn ( )
3161
+
3162
+ const form = new FormApi ( {
3163
+ defaultValues : { name : '' } ,
3164
+ validators : {
3165
+ onMount : ( { value } ) => ( ! value . name ? 'Name required' : undefined ) ,
3166
+ } ,
3167
+ onSubmitInvalid : ( { value, formApi } ) => {
3168
+ onInvalid ( value , formApi )
3169
+ } ,
3170
+ } )
3171
+
3172
+ form . mount ( )
3173
+
3174
+ // Mount a field to participate in touched/dirty state
3175
+ new FieldApi ( { form, name : 'name' } ) . mount ( )
3176
+
3177
+ // With an onMount error present, the form is invalid and cannot submit
3178
+ expect ( form . state . canSubmit ) . toBe ( false )
3179
+
3180
+ await form . handleSubmit ( )
3181
+
3182
+ expect ( onInvalid ) . toHaveBeenCalledTimes ( 1 )
3183
+ } )
3184
+
3159
3185
it ( 'should pass the handleSubmit default meta data to onSubmitInvalid' , async ( ) => {
3160
3186
const form = new FormApi ( {
3161
3187
onSubmitMeta : { dinosaur : 'Frank' } as { dinosaur : string } ,
@@ -3955,6 +3981,83 @@ it('should accept formId and return it', () => {
3955
3981
expect ( form . formId ) . toEqual ( 'age' )
3956
3982
} )
3957
3983
3984
+ it ( 'should call onSubmitInvalid when submitted with onMount error' , async ( ) => {
3985
+ const onInvalidSpy = vi . fn ( )
3986
+
3987
+ const form = new FormApi ( {
3988
+ defaultValues : { name : '' } ,
3989
+ validators : {
3990
+ onMount : ( ) => ( { name : 'Name is required' } ) ,
3991
+ } ,
3992
+ onSubmitInvalid : ( ) => onInvalidSpy ( ) ,
3993
+ } )
3994
+ form . mount ( )
3995
+
3996
+ const field = new FieldApi ( { form, name : 'name' } )
3997
+ field . mount ( )
3998
+
3999
+ expect ( form . state . canSubmit ) . toBe ( false )
4000
+
4001
+ await form . handleSubmit ( )
4002
+
4003
+ expect ( onInvalidSpy ) . toHaveBeenCalledTimes ( 1 )
4004
+ } )
4005
+
4006
+ it ( 'should not run submit validation when canSubmit is false' , async ( ) => {
4007
+ const onSubmitValidatorSpy = vi
4008
+ . fn ( )
4009
+ . mockImplementation ( ( ) => 'Submit validation failed' )
4010
+ const onInvalidSpy = vi . fn ( )
4011
+
4012
+ const form = new FormApi ( {
4013
+ defaultValues : { name : '' } ,
4014
+ validators : {
4015
+ onMount : ( ) => 'Name required' ,
4016
+ onSubmit : ( ) => onSubmitValidatorSpy ,
4017
+ } ,
4018
+ onSubmitInvalid : ( ) => onInvalidSpy ( ) ,
4019
+ } )
4020
+ form . mount ( )
4021
+
4022
+ const field = new FieldApi ( { form, name : 'name' } )
4023
+ field . mount ( )
4024
+
4025
+ expect ( form . state . canSubmit ) . toBe ( false )
4026
+
4027
+ await form . handleSubmit ( )
4028
+
4029
+ expect ( onSubmitValidatorSpy ) . not . toHaveBeenCalled ( )
4030
+ expect ( onInvalidSpy ) . toHaveBeenCalledTimes ( 1 )
4031
+ } )
4032
+
4033
+ it ( 'should respect canSubmitWhenInvalid option and run validation even when canSubmit is false' , async ( ) => {
4034
+ const onSubmitValidatorSpy = vi
4035
+ . fn ( )
4036
+ . mockImplementation ( ( ) => 'Submit validation failed' )
4037
+ const onInvalidSpy = vi . fn ( )
4038
+
4039
+ const form = new FormApi ( {
4040
+ defaultValues : { name : '' } ,
4041
+ canSubmitWhenInvalid : true ,
4042
+ validators : {
4043
+ onMount : ( ) => 'Name required' ,
4044
+ onSubmit : ( ) => onSubmitValidatorSpy ( ) ,
4045
+ } ,
4046
+ onSubmitInvalid : ( ) => onInvalidSpy ( ) ,
4047
+ } )
4048
+ form . mount ( )
4049
+
4050
+ const field = new FieldApi ( { form, name : 'name' } )
4051
+ field . mount ( )
4052
+
4053
+ expect ( form . state . canSubmit ) . toBe ( true )
4054
+
4055
+ await form . handleSubmit ( )
4056
+
4057
+ expect ( onSubmitValidatorSpy ) . toHaveBeenCalledTimes ( 1 )
4058
+ expect ( onInvalidSpy ) . toHaveBeenCalledTimes ( 1 )
4059
+ } )
4060
+
3958
4061
it ( 'should generate a formId if not provided' , ( ) => {
3959
4062
const form = new FormApi ( {
3960
4063
defaultValues : { age : 0 } ,
0 commit comments