Fix local text value and selection not updating when delta is sent to… (#31966)

* Fix local text value and selection not updating when delta is sent to framework

* readd new line

* Add test

* whitespace

* whitespace

* formatting

Co-authored-by: Renzo Olivares <roliv@google.com>
diff --git a/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm
index a9485ec..6a7c98c 100644
--- a/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm
+++ b/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm
@@ -436,6 +436,7 @@
 
   [_channel invokeMethod:kUpdateEditStateWithDeltasResponseMethod
                arguments:@[ self.clientID, deltas ]];
+  [self updateTextAndSelection];
 }
 
 - (void)updateTextAndSelection {
diff --git a/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm
index b4866f2..34970d2 100644
--- a/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm
+++ b/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm
@@ -404,6 +404,67 @@
   return true;
 }
 
+- (bool)testLocalTextAndSelectionUpdateAfterDelta {
+  id engineMock = OCMClassMock([FlutterEngine class]);
+  id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
+  OCMStub(  // NOLINT(google-objc-avoid-throwing-exception)
+      [engineMock binaryMessenger])
+      .andReturn(binaryMessengerMock);
+
+  FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
+                                                                                nibName:@""
+                                                                                 bundle:nil];
+
+  FlutterTextInputPlugin* plugin =
+      [[FlutterTextInputPlugin alloc] initWithViewController:viewController];
+
+  [plugin handleMethodCall:[FlutterMethodCall
+                               methodCallWithMethodName:@"TextInput.setClient"
+                                              arguments:@[
+                                                @(1), @{
+                                                  @"inputAction" : @"action",
+                                                  @"enableDeltaModel" : @"true",
+                                                  @"inputType" : @{@"name" : @"inputName"},
+                                                }
+                                              ]]
+                    result:^(id){
+                    }];
+  [plugin insertText:@"text to insert"];
+
+  NSDictionary* deltaToFramework = @{
+    @"oldText" : @"",
+    @"deltaText" : @"text to insert",
+    @"deltaStart" : @(0),
+    @"deltaEnd" : @(0),
+    @"selectionBase" : @(14),
+    @"selectionExtent" : @(14),
+    @"selectionAffinity" : @"TextAffinity.upstream",
+    @"selectionIsDirectional" : @(false),
+    @"composingBase" : @(-1),
+    @"composingExtent" : @(-1),
+  };
+  NSDictionary* expectedState = @{
+    @"deltas" : @[ deltaToFramework ],
+  };
+
+  NSData* updateCall = [[FlutterJSONMethodCodec sharedInstance]
+      encodeMethodCall:[FlutterMethodCall
+                           methodCallWithMethodName:@"TextInputClient.updateEditingStateWithDeltas"
+                                          arguments:@[ @(1), expectedState ]]];
+
+  @try {
+    OCMVerify(  // NOLINT(google-objc-avoid-throwing-exception)
+        [binaryMessengerMock sendOnChannel:@"flutter/textinput" message:updateCall]);
+  } @catch (...) {
+    return false;
+  }
+
+  bool localTextAndSelectionUpdated = [plugin.string isEqualToString:@"text to insert"] &&
+                                      NSEqualRanges(plugin.selectedRange, NSMakeRange(14, 0));
+
+  return localTextAndSelectionUpdated;
+}
+
 @end
 
 namespace flutter::testing {
@@ -439,6 +500,10 @@
   ASSERT_TRUE([[FlutterInputPluginTestObjc alloc] testOperationsThatTriggerDelta]);
 }
 
+TEST(FlutterTextInputPluginTest, TestLocalTextAndSelectionUpdateAfterDelta) {
+  ASSERT_TRUE([[FlutterInputPluginTestObjc alloc] testLocalTextAndSelectionUpdateAfterDelta]);
+}
+
 TEST(FlutterTextInputPluginTest, CanWorkWithFlutterTextField) {
   FlutterEngine* engine = CreateTestEngine();
   NSString* fixtures = @(testing::GetFixturesPath());