Skip to content

Commit

Permalink
Fix and Test Conditional Validator Behavior in FormField (flutter#132714
Browse files Browse the repository at this point in the history
)

In the FormField widget, if a validator is initially set (and validation fails), then subsequently the validator is set to null, the form incorrectly retains its error state. This is not expected behavior as removing the validator should clear any validation errors.
  • Loading branch information
EdgarJan authored and christopherfujino committed Sep 27, 2023
1 parent 68e4ba4 commit 02d9ad7
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/flutter/lib/src/widgets/form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,8 @@ class FormFieldState<T> extends State<FormField<T>> with RestorationMixin {
void _validate() {
if (widget.validator != null) {
_errorText.value = widget.validator!(_value);
} else {
_errorText.value = null;
}
}

Expand Down
67 changes: 67 additions & 0 deletions packages/flutter/test/widgets/form_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -945,4 +945,71 @@ void main() {
fieldKey.currentState!.reset();
expect(fieldKey.currentState!.hasInteractedByUser, isFalse);
});

testWidgets('Validator is nullified and error text behaves accordingly',
(WidgetTester tester) async {
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
bool useValidator = false;
late StateSetter setState;

String? validator(String? value) {
if (value == null || value.isEmpty) {
return 'test_error';
}
return null;
}

Widget builder() {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setter) {
setState = setter;
return MaterialApp(
home: MediaQuery(
data: const MediaQueryData(),
child: Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Material(
child: Form(
key: formKey,
child: TextFormField(
validator: useValidator ? validator : null,
),
),
),
),
),
),
);
},
);
}

await tester.pumpWidget(builder());

// Start with no validator.
await tester.enterText(find.byType(TextFormField), '');
await tester.pump();
formKey.currentState!.validate();
await tester.pump();
expect(find.text('test_error'), findsNothing);

// Now use the validator.
setState(() {
useValidator = true;
});
await tester.pump();
formKey.currentState!.validate();
await tester.pump();
expect(find.text('test_error'), findsOneWidget);

// Remove the validator again and expect the error to disappear.
setState(() {
useValidator = false;
});
await tester.pump();
formKey.currentState!.validate();
await tester.pump();
expect(find.text('test_error'), findsNothing);
});
}

0 comments on commit 02d9ad7

Please sign in to comment.