@@ -675,6 +675,78 @@ void main() {
675675 expect (formKey.currentState? .fields, contains (secondDropdownName));
676676 });
677677 });
678+
679+ group ('AutovalidateMode.onUserInteractionIfError -' , () {
680+ // The mode landed via flutter/flutter#175515. The runtime lookup keeps the
681+ // package compatible with older stable versions: there the tests just pass
682+ // without exercising the mode.
683+ final onUserInteractionIfError = AutovalidateMode .values
684+ .asNameMap ()['onUserInteractionIfError' ];
685+
686+ testWidgets ('form level: validates only after the first failed validate' , (
687+ WidgetTester tester,
688+ ) async {
689+ if (onUserInteractionIfError == null ) {
690+ return ;
691+ }
692+ const widgetName = 'name' ;
693+ final testWidget = FormBuilderTextField (
694+ name: widgetName,
695+ validator: (value) =>
696+ value == null || value.isEmpty ? 'required' : null ,
697+ );
698+ await tester.pumpWidget (
699+ buildTestableFieldWidget (
700+ testWidget,
701+ autovalidateMode: onUserInteractionIfError,
702+ ),
703+ );
704+
705+ await tester.enterText (find.byWidget (testWidget), 'a' );
706+ await tester.pumpAndSettle ();
707+ await tester.enterText (find.byWidget (testWidget), '' );
708+ await tester.pumpAndSettle ();
709+ expect (find.text ('required' ), findsNothing);
710+
711+ expect (formSave (), isFalse);
712+ await tester.pumpAndSettle ();
713+ expect (find.text ('required' ), findsOneWidget);
714+
715+ await tester.enterText (find.byWidget (testWidget), 'ok' );
716+ await tester.pumpAndSettle ();
717+ expect (find.text ('required' ), findsNothing);
718+ });
719+
720+ testWidgets ('field level: validates only after the first failed validate' , (
721+ WidgetTester tester,
722+ ) async {
723+ if (onUserInteractionIfError == null ) {
724+ return ;
725+ }
726+ const widgetName = 'name' ;
727+ final testWidget = FormBuilderTextField (
728+ name: widgetName,
729+ autovalidateMode: onUserInteractionIfError,
730+ validator: (value) =>
731+ value == null || value.isEmpty ? 'required' : null ,
732+ );
733+ await tester.pumpWidget (buildTestableFieldWidget (testWidget));
734+
735+ await tester.enterText (find.byWidget (testWidget), 'a' );
736+ await tester.pumpAndSettle ();
737+ await tester.enterText (find.byWidget (testWidget), '' );
738+ await tester.pumpAndSettle ();
739+ expect (find.text ('required' ), findsNothing);
740+
741+ expect (formKey.currentState! .fields[widgetName]! .validate (), isFalse);
742+ await tester.pumpAndSettle ();
743+ expect (find.text ('required' ), findsOneWidget);
744+
745+ await tester.enterText (find.byWidget (testWidget), 'ok' );
746+ await tester.pumpAndSettle ();
747+ expect (find.text ('required' ), findsNothing);
748+ });
749+ });
678750}
679751
680752// simple stateful widget that can hide and show its child with the intent of
0 commit comments