Unverified Commit 3217906e authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Handle setting TextEditingController text to null (#68638)

parent dc432d78
...@@ -340,14 +340,14 @@ class _TextFormFieldState extends FormFieldState<String> { ...@@ -340,14 +340,14 @@ class _TextFormFieldState extends FormFieldState<String> {
super.didChange(value); super.didChange(value);
if (_effectiveController!.text != value) if (_effectiveController!.text != value)
_effectiveController!.text = value; _effectiveController!.text = value ?? '';
} }
@override @override
void reset() { void reset() {
super.reset(); super.reset();
setState(() { setState(() {
_effectiveController!.text = widget.initialValue; _effectiveController!.text = widget.initialValue ?? '';
}); });
} }
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async'; import 'dart:async';
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'dart:ui' show import 'dart:ui' show
......
...@@ -154,7 +154,7 @@ class TextEditingController extends ValueNotifier<TextEditingValue> { ...@@ -154,7 +154,7 @@ class TextEditingController extends ValueNotifier<TextEditingValue> {
/// [TextEditingController]; however, one should not also set [selection] /// [TextEditingController]; however, one should not also set [selection]
/// in a separate statement. To change both the [text] and the [selection] /// in a separate statement. To change both the [text] and the [selection]
/// change the controller's [value]. /// change the controller's [value].
set text(String? newText) { set text(String newText) {
value = value.copyWith( value = value.copyWith(
text: newText, text: newText,
selection: const TextSelection.collapsed(offset: -1), selection: const TextSelection.collapsed(offset: -1),
......
...@@ -406,6 +406,56 @@ void main() { ...@@ -406,6 +406,56 @@ void main() {
expect(find.text('initialValue'), findsOneWidget); expect(find.text('initialValue'), findsOneWidget);
}); });
// Regression test for https://github.com/flutter/flutter/issues/34847.
testWidgets('didChange resets the text field\'s value to empty when passed null', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: TextFormField(
initialValue: null,
),
),
),
)
);
await tester.enterText(find.byType(TextFormField), 'changedValue');
await tester.pump();
expect(find.text('changedValue'), findsOneWidget);
final FormFieldState<String> state = tester.state<FormFieldState<String>>(find.byType(TextFormField));
state.didChange(null);
expect(find.text('changedValue'), findsNothing);
expect(find.text(''), findsOneWidget);
});
// Regression test for https://github.com/flutter/flutter/issues/34847.
testWidgets('reset resets the text field\'s value to empty when intialValue is null', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: TextFormField(
initialValue: null,
),
),
),
)
);
await tester.enterText(find.byType(TextFormField), 'changedValue');
await tester.pump();
expect(find.text('changedValue'), findsOneWidget);
final FormFieldState<String> state = tester.state<FormFieldState<String>>(find.byType(TextFormField));
state.reset();
expect(find.text('changedValue'), findsNothing);
expect(find.text(''), findsOneWidget);
});
// Regression test for https://github.com/flutter/flutter/issues/54472. // Regression test for https://github.com/flutter/flutter/issues/54472.
testWidgets('didChange changes text fields value', (WidgetTester tester) async { testWidgets('didChange changes text fields value', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
......
...@@ -5566,77 +5566,114 @@ void main() { ...@@ -5566,77 +5566,114 @@ void main() {
expect(focusNode.hasFocus, false); expect(focusNode.hasFocus, false);
}); });
testWidgets('TextEditingController.clear() behavior test', (WidgetTester tester) async { group('TextEditingController', () {
// Regression test for https://github.com/flutter/flutter/issues/66316 testWidgets('TextEditingController.text set to empty string clears field', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[]; final TextEditingController controller = TextEditingController();
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async { await tester.pumpWidget(
log.add(methodCall); MaterialApp(
home: MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Material(
child: EditableText(
controller: controller,
focusNode: focusNode,
style: textStyle,
cursorColor: Colors.red,
backgroundCursorColor: Colors.red,
keyboardType: TextInputType.multiline,
onChanged: (String value) { },
),
),
),
),
),
),
);
controller.text = '...';
await tester.pump();
expect(find.text('...'), findsOneWidget);
controller.text = '';
await tester.pump();
expect(find.text('...'), findsNothing);
}); });
final TextEditingController controller = TextEditingController();
final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node'); testWidgets('TextEditingController.clear() behavior test', (WidgetTester tester) async {
Widget builder() { // Regression test for https://github.com/flutter/flutter/issues/66316
return StatefulBuilder( final List<MethodCall> log = <MethodCall>[];
builder: (BuildContext context, StateSetter setter) { SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
return MaterialApp( log.add(methodCall);
home: MediaQuery( });
data: const MediaQueryData(devicePixelRatio: 1.0), final TextEditingController controller = TextEditingController();
child: Directionality(
textDirection: TextDirection.ltr, final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node');
child: Center( Widget builder() {
child: Material( return StatefulBuilder(
child: EditableText( builder: (BuildContext context, StateSetter setter) {
controller: controller, return MaterialApp(
focusNode: focusNode, home: MediaQuery(
style: textStyle, data: const MediaQueryData(devicePixelRatio: 1.0),
cursorColor: Colors.red, child: Directionality(
backgroundCursorColor: Colors.red, textDirection: TextDirection.ltr,
keyboardType: TextInputType.multiline, child: Center(
onChanged: (String value) { }, child: Material(
child: EditableText(
controller: controller,
focusNode: focusNode,
style: textStyle,
cursorColor: Colors.red,
backgroundCursorColor: Colors.red,
keyboardType: TextInputType.multiline,
onChanged: (String value) { },
),
), ),
), ),
), ),
), ),
), );
); },
}, );
); }
}
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
await tester.tap(find.byType(EditableText)); await tester.tap(find.byType(EditableText));
await tester.pump(); await tester.pump();
// The keyboard is shown after tap the EditableText. // The keyboard is shown after tap the EditableText.
expect(focusNode.hasFocus, true); expect(focusNode.hasFocus, true);
log.clear(); log.clear();
final EditableTextState state = tester.firstState(find.byType(EditableText)); final EditableTextState state = tester.firstState(find.byType(EditableText));
state.updateEditingValue(const TextEditingValue( state.updateEditingValue(const TextEditingValue(
text: 'a', text: 'a',
)); ));
await tester.pump(); await tester.pump();
// Nothing called when only the remote changes. // Nothing called when only the remote changes.
expect(log.length, 0); expect(log.length, 0);
controller.clear(); controller.clear();
expect(log.length, 1); expect(log.length, 1);
expect( expect(
log[0], log[0],
isMethodCall('TextInput.setEditingState', arguments: <String, dynamic>{ isMethodCall('TextInput.setEditingState', arguments: <String, dynamic>{
'text': '', 'text': '',
'selectionBase': 0, 'selectionBase': 0,
'selectionExtent': 0, 'selectionExtent': 0,
'selectionAffinity': 'TextAffinity.downstream', 'selectionAffinity': 'TextAffinity.downstream',
'selectionIsDirectional': false, 'selectionIsDirectional': false,
'composingBase': -1, 'composingBase': -1,
'composingExtent': -1, 'composingExtent': -1,
}), }),
); );
});
}); });
testWidgets('autofocus:true on first frame does not throw', (WidgetTester tester) async { testWidgets('autofocus:true on first frame does not throw', (WidgetTester tester) async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment