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> {
super.didChange(value);
if (_effectiveController!.text != value)
_effectiveController!.text = value;
_effectiveController!.text = value ?? '';
}
@override
void reset() {
super.reset();
setState(() {
_effectiveController!.text = widget.initialValue;
_effectiveController!.text = widget.initialValue ?? '';
});
}
......
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io' show Platform;
import 'dart:ui' show
......
......@@ -154,7 +154,7 @@ class TextEditingController extends ValueNotifier<TextEditingValue> {
/// [TextEditingController]; however, one should not also set [selection]
/// in a separate statement. To change both the [text] and the [selection]
/// change the controller's [value].
set text(String? newText) {
set text(String newText) {
value = value.copyWith(
text: newText,
selection: const TextSelection.collapsed(offset: -1),
......
......@@ -406,6 +406,56 @@ void main() {
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.
testWidgets('didChange changes text fields value', (WidgetTester tester) async {
await tester.pumpWidget(
......
......@@ -5566,77 +5566,114 @@ void main() {
expect(focusNode.hasFocus, false);
});
testWidgets('TextEditingController.clear() behavior test', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/66316
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
log.add(methodCall);
group('TextEditingController', () {
testWidgets('TextEditingController.text set to empty string clears field', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
await tester.pumpWidget(
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');
Widget builder() {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setter) {
return 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) { },
testWidgets('TextEditingController.clear() behavior test', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/66316
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
log.add(methodCall);
});
final TextEditingController controller = TextEditingController();
final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node');
Widget builder() {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setter) {
return 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) { },
),
),
),
),
),
),
);
},
);
}
);
},
);
}
await tester.pumpWidget(builder());
await tester.tap(find.byType(EditableText));
await tester.pump();
await tester.pumpWidget(builder());
await tester.tap(find.byType(EditableText));
await tester.pump();
// The keyboard is shown after tap the EditableText.
expect(focusNode.hasFocus, true);
// The keyboard is shown after tap the EditableText.
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(
text: 'a',
));
await tester.pump();
state.updateEditingValue(const TextEditingValue(
text: 'a',
));
await tester.pump();
// Nothing called when only the remote changes.
expect(log.length, 0);
// Nothing called when only the remote changes.
expect(log.length, 0);
controller.clear();
controller.clear();
expect(log.length, 1);
expect(
log[0],
isMethodCall('TextInput.setEditingState', arguments: <String, dynamic>{
'text': '',
'selectionBase': 0,
'selectionExtent': 0,
'selectionAffinity': 'TextAffinity.downstream',
'selectionIsDirectional': false,
'composingBase': -1,
'composingExtent': -1,
}),
);
expect(log.length, 1);
expect(
log[0],
isMethodCall('TextInput.setEditingState', arguments: <String, dynamic>{
'text': '',
'selectionBase': 0,
'selectionExtent': 0,
'selectionAffinity': 'TextAffinity.downstream',
'selectionIsDirectional': false,
'composingBase': -1,
'composingExtent': -1,
}),
);
});
});
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