This reverts commit 285b475124216c79198ff2d92e673d1dd10280a0.
This commit is contained in:
parent
5b0eea8a26
commit
cbdd9c4787
@ -20,6 +20,9 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Focus on a TextFormField.
|
||||
final Finder finder = find.byKey(const Key('input'));
|
||||
expect(finder, findsOneWidget);
|
||||
@ -45,6 +48,9 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Focus on a TextFormField.
|
||||
final Finder finder = find.byKey(const Key('empty-input'));
|
||||
expect(finder, findsOneWidget);
|
||||
@ -70,6 +76,9 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// This text will show no-enter initially. It will have 'enter-pressed'
|
||||
// after `onFieldSubmitted` of TextField is triggered.
|
||||
final Finder textFinder = find.byKey(const Key('text'));
|
||||
@ -103,6 +112,9 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Focus on a TextFormField.
|
||||
final Finder finder = find.byKey(const Key('input'));
|
||||
expect(finder, findsOneWidget);
|
||||
@ -135,6 +147,9 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Focus on a TextFormField.
|
||||
final Finder finder = find.byKey(const Key('input'));
|
||||
expect(finder, findsOneWidget);
|
||||
@ -182,6 +197,9 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Select something from the selectable text.
|
||||
final Finder finder = find.byKey(const Key('selectable'));
|
||||
expect(finder, findsOneWidget);
|
||||
|
@ -120,11 +120,6 @@ class SystemChannels {
|
||||
/// they apply, so that stale messages referencing past transactions can be
|
||||
/// ignored.
|
||||
///
|
||||
/// In debug builds, messages sent with a client ID of -1 are always accepted.
|
||||
/// This allows tests to smuggle messages without having to mock the engine's
|
||||
/// text handling (for example, allowing the engine to still handle the text
|
||||
/// input messages in an integration test).
|
||||
///
|
||||
/// The methods described below are wrapped in a more convenient form by the
|
||||
/// [TextInput] and [TextInputConnection] class.
|
||||
///
|
||||
@ -157,15 +152,9 @@ class SystemChannels {
|
||||
/// is a transaction identifier. Calls for stale transactions should be ignored.
|
||||
///
|
||||
/// * `TextInputClient.updateEditingState`: The user has changed the contents
|
||||
/// of the text control. The second argument is an object with seven keys,
|
||||
/// in the form expected by [TextEditingValue.fromJSON].
|
||||
///
|
||||
/// * `TextInputClient.updateEditingStateWithTag`: One or more text controls
|
||||
/// were autofilled by the platform's autofill service. The first argument
|
||||
/// (the client ID) is ignored, the second argument is a map of tags to
|
||||
/// objects in the form expected by [TextEditingValue.fromJSON]. See
|
||||
/// [AutofillScope.getAutofillClient] for details on the interpretation of
|
||||
/// the tag.
|
||||
/// of the text control. The second argument is a [String] containing a
|
||||
/// JSON-encoded object with seven keys, in the form expected by
|
||||
/// [TextEditingValue.fromJSON].
|
||||
///
|
||||
/// * `TextInputClient.performAction`: The user has triggered an action. The
|
||||
/// second argument is a [String] consisting of the stringification of one
|
||||
@ -176,8 +165,7 @@ class SystemChannels {
|
||||
/// one. The framework should call `TextInput.setClient` and
|
||||
/// `TextInput.setEditingState` again with its most recent information. If
|
||||
/// there is no existing state on the framework side, the call should
|
||||
/// fizzle. (This call is made without a client ID; indeed, without any
|
||||
/// arguments at all.)
|
||||
/// fizzle.
|
||||
///
|
||||
/// * `TextInputClient.onConnectionClosed`: The text input connection closed
|
||||
/// on the platform side. For example the application is moved to
|
||||
|
@ -1327,11 +1327,9 @@ class TextInput {
|
||||
|
||||
final List<dynamic> args = methodCall.arguments as List<dynamic>;
|
||||
|
||||
// The updateEditingStateWithTag request (autofill) can come up even to a
|
||||
// text field that doesn't have a connection.
|
||||
if (method == 'TextInputClient.updateEditingStateWithTag') {
|
||||
assert(_currentConnection!._client != null);
|
||||
final TextInputClient client = _currentConnection!._client;
|
||||
assert(client != null);
|
||||
final AutofillScope? scope = client.currentAutofillScope;
|
||||
final Map<String, dynamic> editingValue = args[1] as Map<String, dynamic>;
|
||||
for (final String tag in editingValue.keys) {
|
||||
@ -1345,22 +1343,9 @@ class TextInput {
|
||||
}
|
||||
|
||||
final int client = args[0] as int;
|
||||
if (client != _currentConnection!._id) {
|
||||
// If the client IDs don't match, the incoming message was for a different
|
||||
// client.
|
||||
bool debugAllowAnyway = false;
|
||||
assert(() {
|
||||
// In debug builds we allow "-1" as a magical client ID that ignores
|
||||
// this verification step so that tests can always get through, even
|
||||
// when they are not mocking the engine side of text input.
|
||||
if (client == -1)
|
||||
debugAllowAnyway = true;
|
||||
return true;
|
||||
}());
|
||||
if (!debugAllowAnyway)
|
||||
return;
|
||||
}
|
||||
|
||||
// The incoming message was for a different client.
|
||||
if (client != _currentConnection!._id)
|
||||
return;
|
||||
switch (method) {
|
||||
case 'TextInputClient.updateEditingState':
|
||||
_currentConnection!._client.updateEditingValue(TextEditingValue.fromJSON(args[1] as Map<String, dynamic>));
|
||||
|
@ -2112,7 +2112,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
if (_hasFocus) {
|
||||
_openInputConnection();
|
||||
} else {
|
||||
widget.focusNode.requestFocus(); // This eventually calls _openInputConnection also, see _handleFocusChanged.
|
||||
widget.focusNode.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,15 +195,9 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
|
||||
/// Called by the test framework at the beginning of a widget test to
|
||||
/// prepare the binding for the next test.
|
||||
///
|
||||
/// If [registerTestTextInput] returns true when this method is called,
|
||||
/// the [testTextInput] is configured to simulate the keyboard.
|
||||
void reset() {
|
||||
_restorationManager = null;
|
||||
resetGestureBinding();
|
||||
testTextInput.reset();
|
||||
if (registerTestTextInput)
|
||||
_testTextInput.register();
|
||||
}
|
||||
|
||||
@override
|
||||
@ -243,8 +237,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
@protected
|
||||
bool get overrideHttpClient => true;
|
||||
|
||||
/// Determines whether the binding automatically registers [testTextInput] as
|
||||
/// a fake keyboard implementation.
|
||||
/// Determines whether the binding automatically registers [testTextInput].
|
||||
///
|
||||
/// Unit tests make use of this to mock out text input communication for
|
||||
/// widgets. An integration test would set this to false, to test real IME
|
||||
@ -252,19 +245,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
///
|
||||
/// [TestTextInput.isRegistered] reports whether the text input mock is
|
||||
/// registered or not.
|
||||
///
|
||||
/// Some of the properties and methods on [testTextInput] are only valid if
|
||||
/// [registerTestTextInput] returns true when a test starts. If those
|
||||
/// members are accessed when using a binding that sets this flag to false,
|
||||
/// they will throw.
|
||||
///
|
||||
/// If this property returns true when a test ends, the [testTextInput] is
|
||||
/// unregistered.
|
||||
///
|
||||
/// This property should not change the value it returns during the lifetime
|
||||
/// of the binding. Changing the value of this property risks very confusing
|
||||
/// behavior as the [TestTextInput] may be inconsistently registered or
|
||||
/// unregistered.
|
||||
@protected
|
||||
bool get registerTestTextInput => true;
|
||||
|
||||
@ -339,6 +319,9 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
binding.setupHttpOverrides();
|
||||
}
|
||||
_testTextInput = TestTextInput(onCleared: _resetFocusedEditable);
|
||||
if (registerTestTextInput) {
|
||||
_testTextInput.register();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@ -532,20 +515,12 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
TestTextInput get testTextInput => _testTextInput;
|
||||
late TestTextInput _testTextInput;
|
||||
|
||||
/// The [State] of the current [EditableText] client of the onscreen keyboard.
|
||||
///
|
||||
/// Setting this property to a new value causes the given [EditableTextState]
|
||||
/// to focus itself and request the keyboard to establish a
|
||||
/// [TextInputConnection].
|
||||
///
|
||||
/// Callers must pump an additional frame after setting this property to
|
||||
/// complete the focus change.
|
||||
/// The current client of the onscreen keyboard. Callers must pump
|
||||
/// an additional frame after setting this property to complete the
|
||||
/// focus change.
|
||||
///
|
||||
/// Instead of setting this directly, consider using
|
||||
/// [WidgetTester.showKeyboard].
|
||||
//
|
||||
// TODO(ianh): We should just remove this property and move the call to
|
||||
// requestKeyboard to the WidgetTester.showKeyboard method.
|
||||
EditableTextState? get focusedEditable => _focusedEditable;
|
||||
EditableTextState? _focusedEditable;
|
||||
set focusedEditable(EditableTextState? value) {
|
||||
@ -824,8 +799,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
// alone so that we don't cause more spurious errors.
|
||||
runApp(Container(key: UniqueKey(), child: _postTestMessage)); // Unmount any remaining widgets.
|
||||
await pump();
|
||||
if (registerTestTextInput)
|
||||
_testTextInput.unregister();
|
||||
invariantTester();
|
||||
_verifyAutoUpdateGoldensUnset(autoUpdateGoldensBeforeTest && !isBrowser);
|
||||
_verifyReportTestExceptionUnset(reportTestExceptionBeforeTest);
|
||||
|
@ -14,18 +14,6 @@ export 'package:flutter/services.dart' show TextEditingValue, TextInputAction;
|
||||
///
|
||||
/// Typical app tests will not need to use this class directly.
|
||||
///
|
||||
/// The [TestWidgetsFlutterBinding] class registers a [TestTextInput] instance
|
||||
/// ([TestWidgetsFlutterBinding.testTextInput]) as a stub keyboard
|
||||
/// implementation if its [TestWidgetsFlutterBinding.registerTestTextInput]
|
||||
/// property returns true when a test starts, and unregisters it when the test
|
||||
/// ends (unless it ends with a failure).
|
||||
///
|
||||
/// See [register], [unregister], and [isRegistered] for details.
|
||||
///
|
||||
/// The [enterText], [updateEditingValue], [receiveAction], and
|
||||
/// [closeConnection] methods can be used even when the [TestTextInput] is not
|
||||
/// registered. All other methods will assert if [isRegistered] is false.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetTester.enterText], which uses this class to simulate keyboard input.
|
||||
@ -48,76 +36,58 @@ 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);
|
||||
|
||||
/// Removes this object as a mock handler for [SystemChannels.textInput].
|
||||
///
|
||||
/// After calling this method, the channel will exchange messages with the
|
||||
/// Flutter engine. Use this with [FlutterDriver] tests that need to display
|
||||
/// on-screen keyboard provided by the operating system.
|
||||
void unregister() => SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
/// Log for method calls.
|
||||
///
|
||||
/// For all registered channels, handled calls are added to the list. Can
|
||||
/// be cleaned using `log.clear()`.
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
/// Installs this object as a mock handler for [SystemChannels.textInput].
|
||||
///
|
||||
/// Called by the binding at the top of a test when
|
||||
/// [TestWidgetsFlutterBinding.registerTestTextInput] is true.
|
||||
void register() => SystemChannels.textInput.setMockMethodCallHandler(_handleTextInputCall);
|
||||
|
||||
/// Removes this object as a mock handler for [SystemChannels.textInput].
|
||||
///
|
||||
/// After calling this method, the channel will exchange messages with the
|
||||
/// Flutter engine instead of the stub.
|
||||
///
|
||||
/// Called by the binding at the end of a (successful) test when
|
||||
/// [TestWidgetsFlutterBinding.registerTestTextInput] is true.
|
||||
void unregister() => SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
/// Whether this [TestTextInput] is registered with [SystemChannels.textInput].
|
||||
///
|
||||
/// The binding uses the [register] and [unregister] methods to control this
|
||||
/// value when [TestWidgetsFlutterBinding.registerTestTextInput] is true.
|
||||
/// Use [register] and [unregister] methods to control this value.
|
||||
bool get isRegistered => SystemChannels.textInput.checkMockMethodCallHandler(_handleTextInputCall);
|
||||
|
||||
int? _client;
|
||||
|
||||
/// Whether there are any active clients listening to text input.
|
||||
bool get hasAnyClients {
|
||||
assert(isRegistered);
|
||||
return _client != null && _client! > 0;
|
||||
return _client > 0;
|
||||
}
|
||||
|
||||
/// The last set of arguments supplied to the `TextInput.setClient` and
|
||||
/// `TextInput.updateConfig` methods of this stub implementation.
|
||||
int _client = 0;
|
||||
|
||||
/// Arguments supplied to the TextInput.setClient method call.
|
||||
Map<String, dynamic>? setClientArgs;
|
||||
|
||||
/// The last set of arguments that [TextInputConnection.setEditingState] sent
|
||||
/// to this stub implementation (i.e. the arguments set to
|
||||
/// `TextInput.setEditingState`).
|
||||
/// to the embedder.
|
||||
///
|
||||
/// This is a map representation of a [TextEditingValue] object. For example,
|
||||
/// it will have a `text` entry whose value matches the most recent
|
||||
/// [TextEditingValue.text] that was sent to the embedder.
|
||||
Map<String, dynamic>? editingState;
|
||||
|
||||
/// Whether the onscreen keyboard is visible to the user.
|
||||
///
|
||||
/// Specifically, this reflects the last call to `TextInput.show` or
|
||||
/// `TextInput.hide` received by the stub implementation.
|
||||
bool get isVisible {
|
||||
assert(isRegistered);
|
||||
return _isVisible;
|
||||
}
|
||||
bool _isVisible = false;
|
||||
|
||||
/// Resets any internal state of this object.
|
||||
///
|
||||
/// This method is invoked by the testing framework between tests. It should
|
||||
/// not ordinarily be called by tests directly.
|
||||
void reset() {
|
||||
log.clear();
|
||||
_client = null;
|
||||
setClientArgs = null;
|
||||
editingState = null;
|
||||
_isVisible = false;
|
||||
}
|
||||
|
||||
Future<dynamic> _handleTextInputCall(MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
switch (methodCall.method) {
|
||||
@ -129,7 +99,7 @@ class TestTextInput {
|
||||
setClientArgs = methodCall.arguments as Map<String, dynamic>;
|
||||
break;
|
||||
case 'TextInput.clearClient':
|
||||
_client = null;
|
||||
_client = 0;
|
||||
_isVisible = false;
|
||||
onCleared?.call();
|
||||
break;
|
||||
@ -145,69 +115,87 @@ class TestTextInput {
|
||||
}
|
||||
}
|
||||
|
||||
/// Simulates the user hiding the onscreen keyboard.
|
||||
///
|
||||
/// This does nothing but set the internal flag.
|
||||
void hide() {
|
||||
/// Whether the onscreen keyboard is visible to the user.
|
||||
bool get isVisible {
|
||||
assert(isRegistered);
|
||||
_isVisible = false;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// This can be called even if the [TestTextInput] has not been [register]ed.
|
||||
///
|
||||
/// If this is used to inject text when there is a real IME connection, for
|
||||
/// example when using the [integration_test] library, there is a risk that
|
||||
/// the real IME will become confused as to the current state of input.
|
||||
void enterText(String text) {
|
||||
updateEditingValue(TextEditingValue(
|
||||
text: text,
|
||||
selection: TextSelection.collapsed(offset: text.length),
|
||||
));
|
||||
return _isVisible;
|
||||
}
|
||||
bool _isVisible = false;
|
||||
|
||||
/// Simulates the user changing the [TextEditingValue] to the given value.
|
||||
///
|
||||
/// This can be called even if the [TestTextInput] has not been [register]ed.
|
||||
///
|
||||
/// If this is used to inject text when there is a real IME connection, for
|
||||
/// example when using the [integration_test] library, there is a risk that
|
||||
/// the real IME will become confused as to the current state of input.
|
||||
void updateEditingValue(TextEditingValue value) {
|
||||
assert(isRegistered);
|
||||
// Not using the `expect` function because in the case of a FlutterDriver
|
||||
// test this code does not run in a package:test test zone.
|
||||
if (_client == 0)
|
||||
throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
|
||||
_binaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.textInput.name,
|
||||
SystemChannels.textInput.codec.encodeMethodCall(
|
||||
MethodCall(
|
||||
'TextInputClient.updateEditingState',
|
||||
<dynamic>[_client ?? -1, value.toJSON()],
|
||||
<dynamic>[_client, value.toJSON()],
|
||||
),
|
||||
),
|
||||
(ByteData? data) { /* response from framework is discarded */ },
|
||||
);
|
||||
}
|
||||
|
||||
/// Simulates the user closing the text input connection.
|
||||
///
|
||||
/// For example:
|
||||
/// - User pressed the home button and sent the application to background.
|
||||
/// - User closed the virtual keyboard.
|
||||
void closeConnection() {
|
||||
assert(isRegistered);
|
||||
// Not using the `expect` function because in the case of a FlutterDriver
|
||||
// test this code does not run in a package:test test zone.
|
||||
if (_client == 0)
|
||||
throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
|
||||
_binaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.textInput.name,
|
||||
SystemChannels.textInput.codec.encodeMethodCall(
|
||||
MethodCall(
|
||||
'TextInputClient.onConnectionClosed',
|
||||
<dynamic>[_client,]
|
||||
),
|
||||
),
|
||||
(ByteData? data) { /* response from framework is discarded */ },
|
||||
);
|
||||
}
|
||||
|
||||
/// 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),
|
||||
));
|
||||
}
|
||||
|
||||
/// Simulates the user pressing one of the [TextInputAction] buttons.
|
||||
/// Does not check that the [TextInputAction] performed is an acceptable one
|
||||
/// based on the `inputAction` [setClientArgs].
|
||||
///
|
||||
/// This can be called even if the [TestTextInput] has not been [register]ed.
|
||||
///
|
||||
/// If this is used to inject an action when there is a real IME connection,
|
||||
/// for example when using the [integration_test] library, there is a risk
|
||||
/// that the real IME will become confused as to the current state of input.
|
||||
Future<void> receiveAction(TextInputAction action) async {
|
||||
assert(isRegistered);
|
||||
return TestAsyncUtils.guard(() {
|
||||
// Not using the `expect` function because in the case of a FlutterDriver
|
||||
// test this code does not run in a package:test test zone.
|
||||
if (_client == 0) {
|
||||
throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
|
||||
}
|
||||
|
||||
final Completer<void> completer = Completer<void>();
|
||||
|
||||
_binaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.textInput.name,
|
||||
SystemChannels.textInput.codec.encodeMethodCall(
|
||||
MethodCall(
|
||||
'TextInputClient.performAction',
|
||||
<dynamic>[_client ?? -1, action.toString()],
|
||||
<dynamic>[_client, action.toString()],
|
||||
),
|
||||
),
|
||||
(ByteData? data) {
|
||||
@ -231,28 +219,9 @@ class TestTextInput {
|
||||
});
|
||||
}
|
||||
|
||||
/// Simulates the user closing the text input connection.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// * User pressed the home button and sent the application to background.
|
||||
/// * User closed the virtual keyboard.
|
||||
///
|
||||
/// This can be called even if the [TestTextInput] has not been [register]ed.
|
||||
///
|
||||
/// If this is used to inject text when there is a real IME connection, for
|
||||
/// example when using the [integration_test] library, there is a risk that
|
||||
/// the real IME will become confused as to the current state of input.
|
||||
void closeConnection() {
|
||||
_binaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.textInput.name,
|
||||
SystemChannels.textInput.codec.encodeMethodCall(
|
||||
MethodCall(
|
||||
'TextInputClient.onConnectionClosed',
|
||||
<dynamic>[_client ?? -1],
|
||||
),
|
||||
),
|
||||
(ByteData? data) { /* response from framework is discarded */ },
|
||||
);
|
||||
/// Simulates the user hiding the onscreen keyboard.
|
||||
void hide() {
|
||||
assert(isRegistered);
|
||||
_isVisible = false;
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +149,7 @@ void testWidgets(
|
||||
() async {
|
||||
binding.reset();
|
||||
debugResetSemanticsIdCounter();
|
||||
tester.resetTestTextInput();
|
||||
Object? memento;
|
||||
try {
|
||||
memento = await variant.setUp(value);
|
||||
@ -1001,14 +1002,19 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
///
|
||||
/// Typical app tests will not need to use this value. To add text to widgets
|
||||
/// like [TextField] or [TextFormField], call [enterText].
|
||||
///
|
||||
/// Some of the properties and methods on this value are only valid if the
|
||||
/// binding's [TestWidgetsFlutterBinding.registerTestTextInput] flag is set to
|
||||
/// true as a test is starting (meaning that the keyboard is to be simulated
|
||||
/// by the test framework). If those members are accessed when using a binding
|
||||
/// that sets this flag to false, they will throw.
|
||||
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.
|
||||
///
|
||||
@ -1029,9 +1035,6 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
matchRoot: true,
|
||||
),
|
||||
);
|
||||
// Setting focusedEditable causes the binding to call requestKeyboard()
|
||||
// on the EditableTextState, which itself eventually calls TextInput.attach
|
||||
// to establish the connection.
|
||||
binding.focusedEditable = editable;
|
||||
await pump();
|
||||
});
|
||||
@ -1049,12 +1052,6 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
///
|
||||
/// To just give [finder] the focus without entering any text,
|
||||
/// see [showKeyboard].
|
||||
///
|
||||
/// To enter text into other widgets (e.g. a custom widget that maintains a
|
||||
/// TextInputConnection the way that a [EditableText] does), first ensure that
|
||||
/// that widget has an open connection (e.g. by using [tap] to to focus it),
|
||||
/// then call `testTextInput.enterText` directly (see
|
||||
/// [TestTextInput.enterText]).
|
||||
Future<void> enterText(Finder finder, String text) async {
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
await showKeyboard(finder);
|
||||
|
@ -11,8 +11,6 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:test_api/test_api.dart' as test_package;
|
||||
|
||||
void main() {
|
||||
final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding();
|
||||
|
||||
group(TestViewConfiguration, () {
|
||||
test('is initialized with top-level window if one is not provided', () {
|
||||
// The code below will throw without the default.
|
||||
@ -22,32 +20,15 @@ void main() {
|
||||
|
||||
group(AutomatedTestWidgetsFlutterBinding, () {
|
||||
test('allows setting defaultTestTimeout to 5 minutes', () {
|
||||
final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding();
|
||||
binding.defaultTestTimeout = const test_package.Timeout(Duration(minutes: 5));
|
||||
expect(binding.defaultTestTimeout.duration, const Duration(minutes: 5));
|
||||
});
|
||||
});
|
||||
|
||||
// The next three tests must run in order -- first using `test`, then `testWidgets`, then `test` again.
|
||||
|
||||
int order = 0;
|
||||
|
||||
test('Initializes httpOverrides and testTextInput', () async {
|
||||
assert(order == 0);
|
||||
expect(binding.testTextInput, isNotNull);
|
||||
expect(binding.testTextInput.isRegistered, isFalse);
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
|
||||
expect(binding.testTextInput.isRegistered, true);
|
||||
expect(HttpOverrides.current, isNotNull);
|
||||
order += 1;
|
||||
});
|
||||
|
||||
testWidgets('Registers testTextInput', (WidgetTester tester) async {
|
||||
assert(order == 1);
|
||||
expect(tester.testTextInput.isRegistered, isTrue);
|
||||
order += 1;
|
||||
});
|
||||
|
||||
test('Unregisters testTextInput', () async {
|
||||
assert(order == 2);
|
||||
expect(binding.testTextInput.isRegistered, isFalse);
|
||||
order += 1;
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user