Revert "Refactor text editing test APIs (Mark III) (#80003)" (#81316)

This reverts commit 285b475124216c79198ff2d92e673d1dd10280a0.
diff --git a/dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart b/dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart
index 36e5753..ef84b1b 100644
--- a/dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart
+++ b/dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart
@@ -20,6 +20,9 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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);
diff --git a/packages/flutter/lib/src/services/system_channels.dart b/packages/flutter/lib/src/services/system_channels.dart
index 4ab2b27..43e6bf2 100644
--- a/packages/flutter/lib/src/services/system_channels.dart
+++ b/packages/flutter/lib/src/services/system_channels.dart
@@ -120,11 +120,6 @@
   /// 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 @@
   /// 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 @@
   ///    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
diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart
index 5bd3358..bac572f 100644
--- a/packages/flutter/lib/src/services/text_input.dart
+++ b/packages/flutter/lib/src/services/text_input.dart
@@ -1327,11 +1327,9 @@
 
     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 @@
     }
 
     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>));
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index e321ab2..498550e 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -2112,7 +2112,7 @@
     if (_hasFocus) {
       _openInputConnection();
     } else {
-      widget.focusNode.requestFocus(); // This eventually calls _openInputConnection also, see _handleFocusChanged.
+      widget.focusNode.requestFocus();
     }
   }
 
diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart
index 655c0fd..4a22d99 100644
--- a/packages/flutter_test/lib/src/binding.dart
+++ b/packages/flutter_test/lib/src/binding.dart
@@ -195,15 +195,9 @@
 
   /// 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 @@
   @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 @@
   ///
   /// [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 @@
       binding.setupHttpOverrides();
     }
     _testTextInput = TestTextInput(onCleared: _resetFocusedEditable);
+    if (registerTestTextInput) {
+      _testTextInput.register();
+    }
   }
 
   @override
@@ -532,20 +515,12 @@
   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 @@
       // 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);
diff --git a/packages/flutter_test/lib/src/test_text_input.dart b/packages/flutter_test/lib/src/test_text_input.dart
index 63b5979..c20fd56 100644
--- a/packages/flutter_test/lib/src/test_text_input.dart
+++ b/packages/flutter_test/lib/src/test_text_input.dart
@@ -14,18 +14,6 @@
 ///
 /// 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 @@
   /// 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 @@
         setClientArgs = methodCall.arguments as Map<String, dynamic>;
         break;
       case 'TextInput.clearClient':
-        _client = null;
+        _client = 0;
         _isVisible = false;
         onCleared?.call();
         break;
@@ -145,69 +115,87 @@
     }
   }
 
-  /// 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;
+    return _isVisible;
   }
-
-  /// 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),
-    ));
-  }
+  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 @@
     });
   }
 
-  /// 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;
   }
 }
diff --git a/packages/flutter_test/lib/src/widget_tester.dart b/packages/flutter_test/lib/src/widget_tester.dart
index 224bea5..e5ca5d9 100644
--- a/packages/flutter_test/lib/src/widget_tester.dart
+++ b/packages/flutter_test/lib/src/widget_tester.dart
@@ -149,6 +149,7 @@
           () async {
             binding.reset();
             debugResetSemanticsIdCounter();
+            tester.resetTestTextInput();
             Object? memento;
             try {
               memento = await variant.setUp(value);
@@ -1001,14 +1002,19 @@
   ///
   /// 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 @@
           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 @@
   ///
   /// 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);
diff --git a/packages/flutter_test/test/bindings_test.dart b/packages/flutter_test/test/bindings_test.dart
index bc98524..15e1431 100644
--- a/packages/flutter_test/test/bindings_test.dart
+++ b/packages/flutter_test/test/bindings_test.dart
@@ -11,8 +11,6 @@
 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 @@
 
   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;
   });
 }