Add support for single-element screenshots in the Dart webdriver client.

PiperOrigin-RevId: 250772976
diff --git a/lib/src/async/web_driver.dart b/lib/src/async/web_driver.dart
index 45a5fb6..460e14f 100644
--- a/lib/src/async/web_driver.dart
+++ b/lib/src/async/web_driver.dart
@@ -194,12 +194,24 @@
       _handler.core.buildScreenshotRequest(),
       _handler.core.parseScreenshotResponse);
 
+  /// Take a screenshot of the specified element as PNG and return it as
+  /// base64-encoded string.
+  Future<String> captureElementScreenshotAsBase64(WebElement element) =>
+      _client.send(_handler.core.buildElementScreenshotRequest(element.id),
+          _handler.core.parseScreenshotResponse);
+
   /// Take a screenshot of the current page as PNG as list of uint8.
   Future<List<int>> captureScreenshotAsList() async {
     var base64Encoded = captureScreenshotAsBase64();
     return base64.decode(await base64Encoded);
   }
 
+  /// Take a screenshot of the specified element as PNG as list of uint8.
+  Future<List<int>> captureElementScreenshotAsList(WebElement element) async {
+    var base64Encoded = captureElementScreenshotAsBase64(element);
+    return base64.decode(await base64Encoded);
+  }
+
   /// Take a screenshot of the current page as PNG as stream of uint8.
   ///
   /// Don't use this method. Prefer [captureScreenshotAsBase64] or
diff --git a/lib/src/common/webdriver_handler.dart b/lib/src/common/webdriver_handler.dart
index b217937..a2ffa04 100644
--- a/lib/src/common/webdriver_handler.dart
+++ b/lib/src/common/webdriver_handler.dart
@@ -1,5 +1,6 @@
 import 'dart:math';
 
+import 'package:webdriver/async_core.dart';
 import 'package:webdriver/src/common/cookie.dart';
 import 'package:webdriver/src/common/log.dart';
 import 'package:webdriver/src/common/mouse.dart';
@@ -91,6 +92,9 @@
   /// Builds request for 'Take Screenshot'.
   WebDriverRequest buildScreenshotRequest();
 
+  /// Builds request for 'Take Screenshot of Element'.
+  WebDriverRequest buildElementScreenshotRequest(String elementId);
+
   /// Parses response for 'Take Screenshot' to get a base64 encoded image.
   String parseScreenshotResponse(WebDriverResponse response);
 
diff --git a/lib/src/handler/json_wire/core.dart b/lib/src/handler/json_wire/core.dart
index 3485e65..4de1af5 100644
--- a/lib/src/handler/json_wire/core.dart
+++ b/lib/src/handler/json_wire/core.dart
@@ -31,6 +31,10 @@
       WebDriverRequest.getRequest('screenshot');
 
   @override
+  WebDriverRequest buildElementScreenshotRequest(String elementId) =>
+      new WebDriverRequest.getRequest('${elementPrefix(elementId)}screenshot');
+
+  @override
   String parseScreenshotResponse(WebDriverResponse response) =>
       parseJsonWireResponse(response);
 
diff --git a/lib/src/handler/w3c/core.dart b/lib/src/handler/w3c/core.dart
index 94ed27e..bf852e8 100644
--- a/lib/src/handler/w3c/core.dart
+++ b/lib/src/handler/w3c/core.dart
@@ -31,6 +31,10 @@
       WebDriverRequest.getRequest('screenshot');
 
   @override
+  WebDriverRequest buildElementScreenshotRequest(String elementId) =>
+      new WebDriverRequest.getRequest('${elementPrefix(elementId)}screenshot');
+
+  @override
   String parseScreenshotResponse(WebDriverResponse response) =>
       parseW3cResponse(response);
 
diff --git a/lib/src/sync/web_driver.dart b/lib/src/sync/web_driver.dart
index 5a64fdf..6ffe382 100644
--- a/lib/src/sync/web_driver.dart
+++ b/lib/src/sync/web_driver.dart
@@ -206,12 +206,24 @@
       _handler.core.buildScreenshotRequest(),
       _handler.core.parseScreenshotResponse);
 
+  /// Take a screenshot of the specified element as PNG and return it as
+  /// base64-encoded string.
+  String captureElementScreenshotAsBase64(WebElement element) => _client.send(
+      _handler.core.buildElementScreenshotRequest(element.id),
+      _handler.core.parseScreenshotResponse);
+
   /// Take a screenshot of the current page as PNG as list of uint8.
   List<int> captureScreenshotAsList() {
     final base64Encoded = captureScreenshotAsBase64();
     return base64.decode(base64Encoded);
   }
 
+  /// Take a screenshot of the specified element as PNG as list of uint8.
+  List<int> captureElementScreenshotAsList(WebElement element) {
+    final base64Encoded = captureElementScreenshotAsBase64(element);
+    return base64.decode(base64Encoded);
+  }
+
   /// Inject a snippet of JavaScript into the page for execution in the context
   /// of the currently selected frame. The executed script is assumed to be
   /// asynchronous and must signal that is done by invoking the provided
diff --git a/test/async_web_driver_test.dart b/test/async_web_driver_test.dart
index 3c26d9e..6eab0fb 100644
--- a/test/async_web_driver_test.dart
+++ b/test/async_web_driver_test.dart
@@ -172,12 +172,26 @@
         expect(screenshot, everyElement(const TypeMatcher<int>()));
       });
 
+      test('captureElementScreenshotAsList', () async {
+        var element = await driver.findElement(const By.tagName('tr'));
+        var screenshot = await driver.captureElementScreenshotAsList(element);
+        expect(screenshot, hasLength(isPositive));
+        expect(screenshot, everyElement(const TypeMatcher<int>()));
+      });
+
       test('captureScreenshotAsBase64', () async {
         var screenshot = await driver.captureScreenshotAsBase64();
         expect(screenshot, hasLength(isPositive));
         expect(screenshot, const TypeMatcher<String>());
       });
 
+      test('captureElementScreenshotAsBase64', () async {
+        var element = await driver.findElement(const By.tagName('tr'));
+        var screenshot = await driver.captureElementScreenshotAsBase64(element);
+        expect(screenshot, hasLength(isPositive));
+        expect(screenshot, const TypeMatcher<String>());
+      });
+
       test('future based event listeners work with script timeouts', () async {
         driver.addEventListener((WebDriverCommandEvent e) async {
           return await Future.delayed(
diff --git a/test/sync/web_driver.dart b/test/sync/web_driver.dart
index 0e0010b..fd13bb9 100644
--- a/test/sync/web_driver.dart
+++ b/test/sync/web_driver.dart
@@ -160,24 +160,32 @@
         expect(e.text, 'new text');
       });
 
-      test('captureScreenshot', () {
-        var screenshot = driver.captureScreenshotAsList().toList();
-        expect(screenshot, hasLength(isPositive));
-        expect(screenshot, everyElement(const isInstanceOf<int>()));
-      });
-
       test('captureScreenshotAsList', () {
         var screenshot = driver.captureScreenshotAsList();
         expect(screenshot, hasLength(isPositive));
         expect(screenshot, everyElement(const isInstanceOf<int>()));
       });
 
+      test('captureElementScreenshotAsList', () {
+        var element = driver.findElement(const By.tagName('tr'));
+        var screenshot = driver.captureElementScreenshotAsList(element);
+        expect(screenshot, hasLength(isPositive));
+        expect(screenshot, everyElement(const isInstanceOf<int>()));
+      });
+
       test('captureScreenshotAsBase64', () {
         var screenshot = driver.captureScreenshotAsBase64();
         expect(screenshot, hasLength(isPositive));
         expect(screenshot, const isInstanceOf<String>());
       });
 
+      test('captureElementScreenshotAsBase64', () {
+        var element = driver.findElement(const By.tagName('tr'));
+        var screenshot = driver.captureElementScreenshotAsBase64(element);
+        expect(screenshot, hasLength(isPositive));
+        expect(screenshot, const isInstanceOf<String>());
+      });
+
       test('event listeners work with script timeouts', () {
         try {
           driver.timeouts.setScriptTimeout(const Duration(seconds: 1));