Fix null safety issue with parent/parents with WebElement

Made WebElement.parent nullable
Updated dependency on sync_http to null safety

Closes https://github.com/google/webdriver.dart/pull/235

PiperOrigin-RevId: 353180052
diff --git a/lib/src/common/webdriver_handler.dart b/lib/src/common/webdriver_handler.dart
index 62f6306..2cc39cd 100644
--- a/lib/src/common/webdriver_handler.dart
+++ b/lib/src/common/webdriver_handler.dart
@@ -219,8 +219,13 @@
   /// Builds request for finding a single element.
   WebDriverRequest buildFindElementRequest(By by, [String? contextId]);
 
+  /// Parses response got for finding element to get the element id or `null`
+  /// if the element does not exist.
+  String? parseFindElementResponseCore(WebDriverResponse response);
+
   /// Parses response got for finding element to get the element id.
-  String parseFindElementResponse(WebDriverResponse response);
+  String parseFindElementResponse(WebDriverResponse response) =>
+      parseFindElementResponseCore(response)!;
 
   /// Builds request for finding the current active element.
   WebDriverRequest buildFindActiveElementRequest();
diff --git a/lib/src/handler/json_wire/element_finder.dart b/lib/src/handler/json_wire/element_finder.dart
index d35add5..6a6e726 100644
--- a/lib/src/handler/json_wire/element_finder.dart
+++ b/lib/src/handler/json_wire/element_finder.dart
@@ -40,6 +40,6 @@
       WebDriverRequest.getRequest('element/active');
 
   @override
-  String parseFindElementResponse(WebDriverResponse response) =>
-      (parseJsonWireResponse(response) ?? {})[jsonWireElementStr] as String;
+  String? parseFindElementResponseCore(WebDriverResponse response) =>
+      (parseJsonWireResponse(response) ?? {})[jsonWireElementStr] as String?;
 }
diff --git a/lib/src/handler/w3c/element_finder.dart b/lib/src/handler/w3c/element_finder.dart
index 02578b5..d91a81f 100644
--- a/lib/src/handler/w3c/element_finder.dart
+++ b/lib/src/handler/w3c/element_finder.dart
@@ -65,6 +65,6 @@
       WebDriverRequest.getRequest('element/active');
 
   @override
-  String parseFindElementResponse(WebDriverResponse response) =>
-      (parseW3cResponse(response) ?? {})[w3cElementStr] as String;
+  String? parseFindElementResponseCore(WebDriverResponse response) =>
+      (parseW3cResponse(response) ?? {})[w3cElementStr] as String?;
 }
diff --git a/lib/src/sync/web_element.dart b/lib/src/sync/web_element.dart
index 5f3ffe5..122b91d 100644
--- a/lib/src/sync/web_element.dart
+++ b/lib/src/sync/web_element.dart
@@ -66,32 +66,40 @@
     this.index,
   ]);
 
-  WebElement get parent => WebElement(
-        driver,
-        _client,
-        _handler,
-        _client.send(
-          _handler.element.buildPropertyRequest(id, 'parentElement'),
-          _handler.elementFinder.parseFindElementResponse,
-        ),
+  WebElement? get parent {
+    final parentId = _parentId;
+    if (parentId == null) {
+      return null;
+    }
+    return WebElement(
+      driver,
+      _client,
+      _handler,
+      parentId,
+    );
+  }
+
+  String? get _parentId => _client.send(
+        _handler.element.buildPropertyRequest(id, 'parentElement'),
+        _handler.elementFinder.parseFindElementResponseCore,
       );
 
-  static final _parentCache = <String, String>{};
+  static final _parentCache = <String, String?>{};
 
   /// Gets a chain of parent elements, including the element itself.
   List<String> get parents {
-    var p = this;
+    WebElement? p = this;
     final result = <String>[];
-    while (p.id != null) {
+    while (p != null) {
       var id = p.id;
       if (_parentCache.containsKey(id)) {
         break;
       }
       result.add(id);
-      _parentCache[id] = (p = p.parent).id;
+      _parentCache[id] = (p = p.parent)?.id;
     }
 
-    if (p.id != null) {
+    if (p != null) {
       // Hit cache in the previous loop.
       String? id = p.id;
       while (id != null) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 48d7f72..ea65396 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -17,11 +17,7 @@
   path: ^1.8.0-nullsafety.0
   pedantic: ^1.10.0-nullsafety.0
   stack_trace: ^1.10.0-nullsafety.0
-  sync_http: '>=0.1.1 <0.3.0'
+  sync_http: ^0.3.0-nullsafety.0
 
 dev_dependencies:
   test: ^1.16.0-nullsafety.0
-
-dependency_overrides:
-  sync_http:
-    git: https://github.com/dart-lang/sync_http
diff --git a/test/sync/web_element.dart b/test/sync/web_element.dart
index b46e713..ed035c8 100644
--- a/test/sync/web_element.dart
+++ b/test/sync/web_element.dart
@@ -228,5 +228,9 @@
           'HTML:\n'
           '<input type="text">');
     });
+
+    test('parents', () {
+      expect(inner.parents, hasLength(4));
+    });
   }, timeout: const Timeout(Duration(minutes: 2)));
 }