mirror of
https://github.com/encounter/flutter.git
synced 2026-03-30 11:10:35 -07:00
Reland text state (#47464)
This commit is contained in:
committed by
Flutter GitHub Bot
parent
bd25f70c66
commit
4ad8271bf5
@@ -2961,7 +2961,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(tester.testTextInput.editingState['text'], isEmpty);
|
||||
expect(tester.testTextInput.editingState, isNull);
|
||||
|
||||
// Initial state with null controller.
|
||||
await tester.tap(find.byType(TextField));
|
||||
|
||||
@@ -3928,10 +3928,6 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('input imm channel calls are ordered correctly', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
const String testText = 'flutter is the best!';
|
||||
final TextEditingController controller = TextEditingController(text: testText);
|
||||
final EditableText et = EditableText(
|
||||
@@ -3956,15 +3952,108 @@ void main() {
|
||||
));
|
||||
|
||||
await tester.showKeyboard(find.byType(EditableText));
|
||||
expect(log.length, 7);
|
||||
// TextInput.show should be before TextInput.setEditingState
|
||||
final List<String> logOrder = <String>['TextInput.setClient', 'TextInput.show', 'TextInput.setEditableSizeAndTransform', 'TextInput.setStyle', 'TextInput.setEditingState', 'TextInput.setEditingState', 'TextInput.show'];
|
||||
expect(tester.testTextInput.log.length, 7);
|
||||
int index = 0;
|
||||
for (MethodCall m in log) {
|
||||
for (MethodCall m in tester.testTextInput.log) {
|
||||
expect(m.method, logOrder[index]);
|
||||
index++;
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('setEditingState is not called when text changes', (WidgetTester tester) async {
|
||||
// We shouldn't get a message here because this change is owned by the platform side.
|
||||
const String testText = 'flutter is the best!';
|
||||
final TextEditingController controller = TextEditingController(text: testText);
|
||||
final EditableText et = EditableText(
|
||||
showSelectionHandles: true,
|
||||
maxLines: 2,
|
||||
controller: controller,
|
||||
focusNode: FocusNode(),
|
||||
cursorColor: Colors.red,
|
||||
backgroundCursorColor: Colors.blue,
|
||||
style: Typography(platform: TargetPlatform.android).black.subhead.copyWith(fontFamily: 'Roboto'),
|
||||
keyboardType: TextInputType.text,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: SizedBox(
|
||||
width: 100,
|
||||
child: et,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
await tester.enterText(find.byType(EditableText), '...');
|
||||
|
||||
final List<String> logOrder = <String>[
|
||||
'TextInput.setClient',
|
||||
'TextInput.show',
|
||||
'TextInput.setEditableSizeAndTransform',
|
||||
'TextInput.setStyle',
|
||||
'TextInput.setEditingState',
|
||||
'TextInput.setEditingState',
|
||||
'TextInput.show',
|
||||
];
|
||||
expect(tester.testTextInput.log.length, logOrder.length);
|
||||
int index = 0;
|
||||
for (MethodCall m in tester.testTextInput.log) {
|
||||
expect(m.method, logOrder[index]);
|
||||
index++;
|
||||
}
|
||||
expect(tester.testTextInput.editingState['text'], 'flutter is the best!');
|
||||
});
|
||||
|
||||
testWidgets('setEditingState is called when text changes on controller', (WidgetTester tester) async {
|
||||
// We should get a message here because this change is owned by the framework side.
|
||||
const String testText = 'flutter is the best!';
|
||||
final TextEditingController controller = TextEditingController(text: testText);
|
||||
final EditableText et = EditableText(
|
||||
showSelectionHandles: true,
|
||||
maxLines: 2,
|
||||
controller: controller,
|
||||
focusNode: FocusNode(),
|
||||
cursorColor: Colors.red,
|
||||
backgroundCursorColor: Colors.blue,
|
||||
style: Typography(platform: TargetPlatform.android).black.subhead.copyWith(fontFamily: 'Roboto'),
|
||||
keyboardType: TextInputType.text,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: SizedBox(
|
||||
width: 100,
|
||||
child: et,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
await tester.showKeyboard(find.byType(EditableText));
|
||||
controller.text += '...';
|
||||
await tester.idle();
|
||||
|
||||
final List<String> logOrder = <String>[
|
||||
'TextInput.setClient',
|
||||
'TextInput.show',
|
||||
'TextInput.setEditableSizeAndTransform',
|
||||
'TextInput.setStyle',
|
||||
'TextInput.setEditingState',
|
||||
'TextInput.setEditingState',
|
||||
'TextInput.show',
|
||||
'TextInput.setEditingState',
|
||||
];
|
||||
expect(tester.testTextInput.log.length, logOrder.length);
|
||||
int index = 0;
|
||||
for (MethodCall m in tester.testTextInput.log) {
|
||||
expect(m.method, logOrder[index]);
|
||||
index++;
|
||||
}
|
||||
expect(tester.testTextInput.editingState['text'], 'flutter is the best!...');
|
||||
});
|
||||
}
|
||||
|
||||
class MockTextSelectionControls extends Mock implements TextSelectionControls {
|
||||
|
||||
@@ -39,6 +39,18 @@ class TestTextInput {
|
||||
/// The messenger which sends the bytes for this channel, not null.
|
||||
BinaryMessenger get _binaryMessenger => ServicesBinding.instance.defaultBinaryMessenger;
|
||||
|
||||
/// Resets any internal state of this object and calls [register].
|
||||
///
|
||||
/// This method is invoked by the testing framework between tests. It should
|
||||
/// not ordinarily be called by tests directly.
|
||||
void resetAndRegister() {
|
||||
log.clear();
|
||||
editingState = null;
|
||||
setClientArgs = null;
|
||||
_client = 0;
|
||||
_isVisible = false;
|
||||
register();
|
||||
}
|
||||
/// Installs this object as a mock handler for [SystemChannels.textInput].
|
||||
void register() {
|
||||
SystemChannels.textInput.setMockMethodCallHandler(_handleTextInputCall);
|
||||
@@ -64,6 +76,7 @@ class TestTextInput {
|
||||
/// Whether this [TestTextInput] is registered with [SystemChannels.textInput].
|
||||
///
|
||||
/// Use [register] and [unregister] methods to control this value.
|
||||
// TODO(dnfield): This is unreliable. https://github.com/flutter/flutter/issues/47180
|
||||
bool get isRegistered => _isRegistered;
|
||||
bool _isRegistered = false;
|
||||
|
||||
|
||||
@@ -121,6 +121,7 @@ void testWidgets(
|
||||
return binding.runTest(
|
||||
() async {
|
||||
debugResetSemanticsIdCounter();
|
||||
tester.resetTestTextInput();
|
||||
await callback(tester);
|
||||
semanticsHandle?.dispose();
|
||||
},
|
||||
@@ -692,6 +693,17 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
/// like [TextField] or [TextFormField], call [enterText].
|
||||
TestTextInput get testTextInput => binding.testTextInput;
|
||||
|
||||
/// Ensures that [testTextInput] is registered and [TestTextInput.log] is
|
||||
/// reset.
|
||||
///
|
||||
/// This is called by the testing framework before test runs, so that if a
|
||||
/// previous test has set its own handler on [SystemChannels.textInput], the
|
||||
/// [testTextInput] regains control and the log is fresh for the new test.
|
||||
/// It should not typically need to be called by tests.
|
||||
void resetTestTextInput() {
|
||||
testTextInput.resetAndRegister();
|
||||
}
|
||||
|
||||
/// Give the text input widget specified by [finder] the focus, as if the
|
||||
/// onscreen keyboard had appeared.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user