From 67d8556baa9656b2e91c8dc886b86d5cf8d03cf1 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Thu, 1 Apr 2021 20:29:03 -0700 Subject: [PATCH] `enterText` to move the caret to the end (#79506) --- .../test/material/text_field_test.dart | 48 +++++++++++++------ .../flutter_test/lib/src/test_text_input.dart | 4 ++ .../flutter_test/lib/src/widget_tester.dart | 7 ++- .../test/test_text_input_test.dart | 18 +++++++ 4 files changed, 60 insertions(+), 17 deletions(-) diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 971bfb0101..9c29d8559d 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -848,18 +848,24 @@ void main() { ); testWidgets('cursor layout has correct width', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController.fromValue( + const TextEditingValue(selection: TextSelection.collapsed(offset: 0)), + ); + final FocusNode focusNode = FocusNode(); EditableText.debugDeterministicCursor = true; await tester.pumpWidget( overlay( - child: const RepaintBoundary( + child: RepaintBoundary( child: TextField( cursorWidth: 15.0, + controller: controller, + focusNode: focusNode, ), ), ) ); - await tester.enterText(find.byType(TextField), ' '); - await skipPastScrollingAnimation(tester); + focusNode.requestFocus(); + await tester.pump(); await expectLater( find.byType(TextField), @@ -869,19 +875,25 @@ void main() { }); testWidgets('cursor layout has correct radius', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController.fromValue( + const TextEditingValue(selection: TextSelection.collapsed(offset: 0)), + ); + final FocusNode focusNode = FocusNode(); EditableText.debugDeterministicCursor = true; await tester.pumpWidget( overlay( - child: const RepaintBoundary( + child: RepaintBoundary( child: TextField( cursorWidth: 15.0, - cursorRadius: Radius.circular(3.0), + cursorRadius: const Radius.circular(3.0), + controller: controller, + focusNode: focusNode, ), ), ) ); - await tester.enterText(find.byType(TextField), ' '); - await skipPastScrollingAnimation(tester); + focusNode.requestFocus(); + await tester.pump(); await expectLater( find.byType(TextField), @@ -891,19 +903,25 @@ void main() { }); testWidgets('cursor layout has correct height', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController.fromValue( + const TextEditingValue(selection: TextSelection.collapsed(offset: 0)), + ); + final FocusNode focusNode = FocusNode(); EditableText.debugDeterministicCursor = true; await tester.pumpWidget( overlay( - child: const RepaintBoundary( + child: RepaintBoundary( child: TextField( cursorWidth: 15.0, cursorHeight: 30.0, + controller: controller, + focusNode: focusNode, ), ), ) ); - await tester.enterText(find.byType(TextField), ' '); - await skipPastScrollingAnimation(tester); + focusNode.requestFocus(); + await tester.pump(); await expectLater( find.byType(TextField), @@ -1115,8 +1133,8 @@ void main() { await tester.tapAt(ePos); await tester.pump(); - expect(controller.selection.baseOffset, -1); - expect(controller.selection.extentOffset, -1); + expect(controller.selection.baseOffset, testValue.length); + expect(controller.selection.isCollapsed, isTrue); }); testWidgets('Can long press to select', (WidgetTester tester) async { @@ -1584,8 +1602,7 @@ void main() { await tester.pump(); expect(controller.selection.isCollapsed, true); - expect(controller.selection.baseOffset, -1); - expect(controller.selection.extentOffset, -1); + expect(controller.selection.baseOffset, testValue.length); }); testWidgets('Can select text by dragging with a mouse', (WidgetTester tester) async { @@ -5218,7 +5235,8 @@ void main() { const String testValue = 'x'; await tester.enterText(find.byType(TextField), testValue); await skipPastScrollingAnimation(tester); - expect(controller.selection.baseOffset, -1); + expect(controller.selection.isCollapsed, true); + expect(controller.selection.baseOffset, testValue.length); // Tap the selection handle to bring up the "paste / select all" menu. await tester.tapAt(textOffsetToPosition(tester, 0)); diff --git a/packages/flutter_test/lib/src/test_text_input.dart b/packages/flutter_test/lib/src/test_text_input.dart index aedf388324..80fea768c5 100644 --- a/packages/flutter_test/lib/src/test_text_input.dart +++ b/packages/flutter_test/lib/src/test_text_input.dart @@ -166,10 +166,14 @@ class TestTextInput { } /// Simulates the user typing the given text. + /// + /// Calling this method replaces the content of the connected input field with + /// `text`, and places the caret at the end of the text. void enterText(String text) { assert(isRegistered); updateEditingValue(TextEditingValue( text: text, + selection: TextSelection.collapsed(offset: text.length), )); } diff --git a/packages/flutter_test/lib/src/widget_tester.dart b/packages/flutter_test/lib/src/widget_tester.dart index 3098ee958c..e5ca5d920f 100644 --- a/packages/flutter_test/lib/src/widget_tester.dart +++ b/packages/flutter_test/lib/src/widget_tester.dart @@ -1040,13 +1040,16 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker }); } - /// Give the text input widget specified by [finder] the focus and - /// enter [text] as if it been provided by the onscreen keyboard. + /// Give the text input widget specified by [finder] the focus and replace its + /// content with [text], as if it had been provided by the onscreen keyboard. /// /// The widget specified by [finder] must be an [EditableText] or have /// an [EditableText] descendant. For example `find.byType(TextField)` /// or `find.byType(TextFormField)`, or `find.byType(EditableText)`. /// + /// When the returned future completes, the text input widget's text will be + /// exactly `text`, and the caret will be placed at the end of `text`. + /// /// To just give [finder] the focus without entering any text, /// see [showKeyboard]. Future enterText(Finder finder, String text) async { diff --git a/packages/flutter_test/test/test_text_input_test.dart b/packages/flutter_test/test/test_text_input_test.dart index dfcc6024c2..7dc4c1be22 100644 --- a/packages/flutter_test/test/test_text_input_test.dart +++ b/packages/flutter_test/test/test_text_input_test.dart @@ -7,6 +7,24 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { + testWidgets('enterText works', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: TextField(), + ), + ), + ); + + final EditableTextState state = tester.state(find.byType(EditableText)); + expect(state.textEditingValue.text, ''); + + await tester.enterText(find.byType(EditableText), 'let there be text'); + expect(state.textEditingValue.text, 'let there be text'); + expect(state.textEditingValue.selection.isCollapsed, isTrue); + expect(state.textEditingValue.selection.baseOffset, 17); + }); + testWidgets('receiveAction() forwards exception when exception occurs during action processing', (WidgetTester tester) async { // Setup a widget that can receive focus so that we can open the keyboard. const Widget widget = MaterialApp(