Merge branch 'master' of github.com:google/webdriver.dart
diff --git a/lib/async_core.dart b/lib/async_core.dart
index 8013467..28af2ae 100644
--- a/lib/async_core.dart
+++ b/lib/async_core.dart
@@ -91,7 +91,7 @@
final handler = getHandler(spec);
final session = await client.send(handler.session.buildInfoRequest(sessionId),
- handler.session.parseInfoResponse);
+ (response) => handler.session.parseInfoResponse(response, sessionId));
if (session.spec != WebDriverSpec.JsonWire &&
session.spec != WebDriverSpec.W3c) {
diff --git a/lib/async_html.dart b/lib/async_html.dart
index c3740ff..ec38faf 100644
--- a/lib/async_html.dart
+++ b/lib/async_html.dart
@@ -36,9 +36,13 @@
Future<core.WebDriver> createDriver(
{Uri uri,
Map<String, dynamic> desired,
- WebDriverSpec spec = WebDriverSpec.Auto}) =>
- core.createDriver((prefix) => AsyncXhrRequestClient(prefix),
- uri: uri, desired: desired, spec: spec);
+ WebDriverSpec spec = WebDriverSpec.Auto,
+ Map<String, String> webDriverHeaders = const {}}) =>
+ core.createDriver(
+ (prefix) => AsyncXhrRequestClient(prefix, headers: webDriverHeaders),
+ uri: uri,
+ desired: desired,
+ spec: spec);
/// Creates an async WebDriver from existing session using
/// [AsyncXhrRequestClient].
diff --git a/lib/async_io.dart b/lib/async_io.dart
index b88ad3e..a2f0508 100644
--- a/lib/async_io.dart
+++ b/lib/async_io.dart
@@ -38,9 +38,13 @@
Future<core.WebDriver> createDriver(
{Uri uri,
Map<String, dynamic> desired,
- core.WebDriverSpec spec = core.WebDriverSpec.Auto}) =>
- core.createDriver((prefix) => AsyncIoRequestClient(prefix),
- uri: uri, desired: desired, spec: spec);
+ core.WebDriverSpec spec = core.WebDriverSpec.Auto,
+ Map<String, String> webDriverHeaders = const {}}) =>
+ core.createDriver(
+ (prefix) => AsyncIoRequestClient(prefix, headers: webDriverHeaders),
+ uri: uri,
+ desired: desired,
+ spec: spec);
/// Creates an async WebDriver from existing session using
/// [AsyncIoRequestClient].
diff --git a/lib/src/async/logs.dart b/lib/src/async/logs.dart
index 58fa3ca..3611d14 100644
--- a/lib/src/async/logs.dart
+++ b/lib/src/async/logs.dart
@@ -14,6 +14,7 @@
import 'dart:async';
+import 'package:webdriver/src/common/exception.dart';
import 'package:webdriver/src/common/log.dart';
import 'package:webdriver/src/common/request_client.dart';
import 'package:webdriver/src/common/webdriver_handler.dart';
@@ -32,8 +33,8 @@
for (var entry in entries) {
yield entry;
}
- } on UnsupportedError {
- // Produces no entries for W3C/Firefox.
+ } on UnknownCommandException {
+ // Produces no entries for Firefox.
}
}
diff --git a/lib/src/async/mouse.dart b/lib/src/async/mouse.dart
index 4529e49..67d3882 100644
--- a/lib/src/async/mouse.dart
+++ b/lib/src/async/mouse.dart
@@ -18,6 +18,8 @@
import 'package:webdriver/src/common/mouse.dart';
import 'package:webdriver/src/common/request_client.dart';
import 'package:webdriver/src/common/webdriver_handler.dart';
+import 'package:webdriver/src/handler/json_wire_handler.dart';
+import 'package:webdriver/src/handler/w3c_handler.dart';
class Mouse {
final AsyncRequestClient _client;
@@ -53,8 +55,12 @@
/// If [xOffset] and [yOffset] are specified, will move the mouse that distance
/// from its current location.
///
- /// If all three are specified, will move the mouse to the offset relative to
- /// the top-left corner of the [element].
+ /// If all three are specified, the behavior will be different
+ /// for W3C and JsonWire. For W3C, it will use [element] center as the
+ /// origin, while for JsonWire, it will use [element] top left corner.
+ /// To get a consistent behavior across browsers, you can try
+ /// [moveToElementCenter] and [moveToElementTopLeft] to specify the origin you
+ /// would like to use.
///
/// All other combinations of parameters are illegal.
///
@@ -73,6 +79,47 @@
absolute: absolute),
_handler.mouse.parseMoveToResponse);
+ /// Moves to [element], with an offset of [xOffset] and [yOffset] based on the
+ /// center of [element].
+ Future<void> moveToElementCenter(WebElement element,
+ {int xOffset, int yOffset}) async {
+ if (_handler is JsonWireWebDriverHandler) {
+ final size = await element.size;
+ await moveTo(
+ element: element,
+ xOffset: (xOffset ?? 0) + size.width ~/ 2,
+ yOffset: (yOffset ?? 0) + size.height ~/ 2);
+ } else {
+ await moveTo(element: element, xOffset: xOffset, yOffset: yOffset);
+ }
+ }
+
+ /// Moves to [element], with an offset of [xOffset] and [yOffset] based on the
+ /// top left corner of [element].
+ Future<void> moveToElementTopLeft(WebElement element,
+ {int xOffset, int yOffset}) async {
+ if (_handler is W3cWebDriverHandler) {
+ final size = await element.size;
+ await moveTo(
+ element: element,
+ xOffset: (xOffset ?? 0) - size.width ~/ 2,
+ yOffset: (yOffset ?? 0) - size.height ~/ 2);
+ } else {
+ await moveTo(element: element, xOffset: xOffset, yOffset: yOffset);
+ }
+ }
+
+ /// Moves the mouse away to hide its effect, like hover over element.
+ ///
+ /// For W3C, the mouse cannot move out of the screen, the workaround would be
+ /// to move to somewhere on edge where it's not on any element. You can
+ /// configure the location with [w3cXOffset] and [w3cYOffset]. By default,
+ /// it's at (1000, 0).
+ Future<void> hide({int w3cXOffset = 1000, int w3cYOffset = 0}) =>
+ _handler is W3cWebDriverHandler
+ ? moveTo(xOffset: w3cXOffset, yOffset: w3cYOffset, absolute: true)
+ : moveTo(xOffset: -10000, yOffset: -10000);
+
@override
String toString() => '$_handler.mouse($_client)';
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/async/web_element.dart b/lib/src/async/web_element.dart
index 198b3cc..d634dba 100644
--- a/lib/src/async/web_element.dart
+++ b/lib/src/async/web_element.dart
@@ -84,6 +84,13 @@
_handler.element.buildSizeRequest(id),
_handler.element.parseSizeResponse);
+ /// The bounds of this element.
+ Future<Rectangle<int>> get rect async {
+ final location = await this.location;
+ final size = await this.size;
+ return Rectangle<int>(location.x, location.y, size.width, size.height);
+ }
+
/// The tag name for this element.
Future<String> get name => _client.send(_handler.element.buildNameRequest(id),
_handler.element.parseNameResponse);
diff --git a/lib/src/common/web_element.dart b/lib/src/common/web_element.dart
index 452f78d..3eb8b5e 100644
--- a/lib/src/common/web_element.dart
+++ b/lib/src/common/web_element.dart
@@ -1,6 +1,9 @@
+import '../handler/json_wire/utils.dart' show jsonWireElementStr;
+import '../handler/w3c/utils.dart' show w3cElementStr;
+
/// Common interface for web element, containing only the element id.
abstract class WebElement {
String get id;
- Map<String, String> toJson() => {'ELEMENT': id};
+ Map<String, String> toJson() => {jsonWireElementStr: id, w3cElementStr: id};
}
diff --git a/lib/src/common/webdriver_handler.dart b/lib/src/common/webdriver_handler.dart
index 44901e9..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';
@@ -66,7 +67,7 @@
WebDriverRequest buildInfoRequest(String id);
/// Parses response for 'Get Session Info'.
- SessionInfo parseInfoResponse(WebDriverResponse response);
+ SessionInfo parseInfoResponse(WebDriverResponse response, [String sessionId]);
}
abstract class CoreHandler {
@@ -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/infer_handler.dart b/lib/src/handler/infer_handler.dart
index ad81379..abc895f 100644
--- a/lib/src/handler/infer_handler.dart
+++ b/lib/src/handler/infer_handler.dart
@@ -112,7 +112,8 @@
WebDriverRequest.getRequest('session/$id');
@override
- SessionInfo parseInfoResponse(WebDriverResponse response) {
+ SessionInfo parseInfoResponse(WebDriverResponse response,
+ [String sessionId]) {
if (response.statusCode == 404) {
// May be W3C, as it will throw an unknown command exception.
Map body;
@@ -135,9 +136,6 @@
'produced by W3C WebDriver): ${response.body}');
}
- final sessionId = RegExp(r'/session/([0-9a-f-]*) ')
- .firstMatch(body['message'] as String)
- .group(1);
return SessionInfo(sessionId, WebDriverSpec.W3c, Capabilities.empty);
}
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/json_wire/element_finder.dart b/lib/src/handler/json_wire/element_finder.dart
index 722dc3f..c1ac3a4 100644
--- a/lib/src/handler/json_wire/element_finder.dart
+++ b/lib/src/handler/json_wire/element_finder.dart
@@ -44,6 +44,6 @@
@override
String parseFindElementResponse(WebDriverResponse response) {
- return parseJsonWireResponse(response)[jsonWireElementStr];
+ return (parseJsonWireResponse(response) ?? {})[jsonWireElementStr];
}
}
diff --git a/lib/src/handler/json_wire/session.dart b/lib/src/handler/json_wire/session.dart
index 3b043f4..4d358d7 100644
--- a/lib/src/handler/json_wire/session.dart
+++ b/lib/src/handler/json_wire/session.dart
@@ -22,7 +22,8 @@
WebDriverRequest.getRequest('session/$id');
@override
- SessionInfo parseInfoResponse(WebDriverResponse response) {
+ SessionInfo parseInfoResponse(WebDriverResponse response,
+ [String sessionId]) {
final session = parseJsonWireResponse(response, valueOnly: false);
return SessionInfo(
session['sessionId'], WebDriverSpec.JsonWire, session['value']);
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/handler/w3c/element.dart b/lib/src/handler/w3c/element.dart
index ff0212b..178a699 100644
--- a/lib/src/handler/w3c/element.dart
+++ b/lib/src/handler/w3c/element.dart
@@ -61,12 +61,12 @@
@override
WebDriverRequest buildDisplayedRequest(String elementId) {
- return buildCssPropertyRequest(elementId, 'display');
+ return WebDriverRequest.getRequest('${elementPrefix(elementId)}displayed');
}
@override
bool parseDisplayedResponse(WebDriverResponse response) {
- return parseCssPropertyResponse(response) != 'none';
+ return parseW3cResponse(response);
}
@override
diff --git a/lib/src/handler/w3c/element_finder.dart b/lib/src/handler/w3c/element_finder.dart
index eebaaf8..8e236bb 100644
--- a/lib/src/handler/w3c/element_finder.dart
+++ b/lib/src/handler/w3c/element_finder.dart
@@ -25,6 +25,10 @@
using = 'css selector';
value = by.value;
break;
+ case 'class name': // This doesn't exist in the W3C spec.
+ using = 'css selector';
+ value = '.${by.value}';
+ break;
// xpath, css selector, link text, partial link text, seem fine.
default:
using = by.using;
@@ -65,6 +69,6 @@
@override
String parseFindElementResponse(WebDriverResponse response) {
- return parseW3cResponse(response)[w3cElementStr];
+ return (parseW3cResponse(response) ?? {})[w3cElementStr];
}
}
diff --git a/lib/src/handler/w3c/session.dart b/lib/src/handler/w3c/session.dart
index d72c567..6a96261 100644
--- a/lib/src/handler/w3c/session.dart
+++ b/lib/src/handler/w3c/session.dart
@@ -27,6 +27,7 @@
WebDriverRequest.nullRequest(id);
@override
- SessionInfo parseInfoResponse(WebDriverResponse response) =>
+ SessionInfo parseInfoResponse(WebDriverResponse response,
+ [String sessionId]) =>
SessionInfo(response.body, WebDriverSpec.W3c, Capabilities.empty);
}
diff --git a/lib/src/handler/w3c_handler.dart b/lib/src/handler/w3c_handler.dart
index 932a2b0..913a778 100644
--- a/lib/src/handler/w3c_handler.dart
+++ b/lib/src/handler/w3c_handler.dart
@@ -1,5 +1,6 @@
import 'dart:convert';
+import 'package:webdriver/src/common/log.dart';
import 'package:webdriver/src/common/request.dart';
import 'package:webdriver/src/common/webdriver_handler.dart';
import 'package:webdriver/src/handler/w3c/alert.dart';
@@ -54,8 +55,7 @@
TimeoutsHandler timeouts = W3cTimeoutsHandler();
@override
- LogsHandler get logs =>
- throw UnsupportedError('Unsupported for W3cWebDriverHandler');
+ LogsHandler get logs => W3cLogsHandler();
@override
WebDriverRequest buildGeneralRequest(HttpMethod method, String uri,
@@ -71,3 +71,15 @@
@override
String toString() => 'W3C';
}
+
+class W3cLogsHandler extends LogsHandler {
+ @override
+ WebDriverRequest buildGetLogsRequest(String logType) =>
+ WebDriverRequest.postRequest('log', {'type': logType});
+
+ @override
+ List<LogEntry> parseGetLogsResponse(WebDriverResponse response) =>
+ parseW3cResponse(response)
+ .map<LogEntry>((e) => LogEntry.fromMap(e))
+ .toList();
+}
diff --git a/lib/src/request/async_io_request_client.dart b/lib/src/request/async_io_request_client.dart
index 8e0cc08..73a6109 100644
--- a/lib/src/request/async_io_request_client.dart
+++ b/lib/src/request/async_io_request_client.dart
@@ -10,10 +10,13 @@
/// Async request client using dart:io package.
class AsyncIoRequestClient extends AsyncRequestClient {
final HttpClient client = HttpClient();
+ final Map<String, String> _headers;
final Lock _lock = Lock();
- AsyncIoRequestClient(Uri prefix) : super(prefix);
+ AsyncIoRequestClient(Uri prefix, {Map<String, String> headers = const {}})
+ : _headers = headers,
+ super(prefix);
@override
Future<WebDriverResponse> sendRaw(WebDriverRequest request) async {
@@ -33,6 +36,7 @@
}
httpRequest.followRedirects = true;
+ _headers.forEach(httpRequest.headers.add);
httpRequest.headers.add(HttpHeaders.acceptHeader, 'application/json');
httpRequest.headers.add(HttpHeaders.acceptCharsetHeader, utf8.name);
httpRequest.headers.add(HttpHeaders.cacheControlHeader, 'no-cache');
diff --git a/lib/src/request/async_xhr_request_client.dart b/lib/src/request/async_xhr_request_client.dart
index e898546..8eceda6 100644
--- a/lib/src/request/async_xhr_request_client.dart
+++ b/lib/src/request/async_xhr_request_client.dart
@@ -11,8 +11,11 @@
/// On the low level, it's using XMLHttpRequest object (XHR).
class AsyncXhrRequestClient extends AsyncRequestClient {
final Lock _lock = Lock();
+ final Map<String, String> _headers;
- AsyncXhrRequestClient(Uri prefix) : super(prefix);
+ AsyncXhrRequestClient(Uri prefix, {Map<String, String> headers = const {}})
+ : _headers = headers,
+ super(prefix);
@override
Future<WebDriverResponse> sendRaw(WebDriverRequest request) async {
@@ -20,6 +23,7 @@
final headers = {
'Accept': 'application/json',
+ ..._headers,
};
HttpRequest httpRequest;
diff --git a/lib/src/request/sync_http_request_client.dart b/lib/src/request/sync_http_request_client.dart
index 8676eb9..e9dc718 100644
--- a/lib/src/request/sync_http_request_client.dart
+++ b/lib/src/request/sync_http_request_client.dart
@@ -7,7 +7,10 @@
/// Sync request client using sync_http package.
class SyncHttpRequestClient extends SyncRequestClient {
- SyncHttpRequestClient(Uri prefix) : super(prefix);
+ final Map<String, String> _headers;
+ SyncHttpRequestClient(Uri prefix, {Map<String, String> headers = const {}})
+ : _headers = headers,
+ super(prefix);
@override
WebDriverResponse sendRaw(WebDriverRequest request) {
@@ -27,6 +30,7 @@
break;
}
+ _headers.forEach(httpRequest.headers.add);
httpRequest.headers.add(HttpHeaders.acceptHeader, 'application/json');
httpRequest.headers.add(HttpHeaders.cacheControlHeader, 'no-cache');
diff --git a/lib/src/sync/logs.dart b/lib/src/sync/logs.dart
index 59962ae..4a51473 100644
--- a/lib/src/sync/logs.dart
+++ b/lib/src/sync/logs.dart
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import 'package:webdriver/src/common/exception.dart';
import 'package:webdriver/src/common/log.dart';
import 'package:webdriver/src/common/request_client.dart';
import 'package:webdriver/src/common/webdriver_handler.dart';
@@ -26,8 +27,8 @@
try {
return _client.send(_handler.logs.buildGetLogsRequest(logType),
_handler.logs.parseGetLogsResponse);
- } on UnsupportedError {
- // Produces no entries for W3C/Firefox.
+ } on UnknownCommandException {
+ // Produces no entries for Firefox.
return <LogEntry>[];
}
}
diff --git a/lib/src/sync/mouse.dart b/lib/src/sync/mouse.dart
index 51a2582..fd3db71 100644
--- a/lib/src/sync/mouse.dart
+++ b/lib/src/sync/mouse.dart
@@ -15,6 +15,8 @@
import 'package:webdriver/src/common/mouse.dart';
import 'package:webdriver/src/common/request_client.dart';
import 'package:webdriver/src/common/webdriver_handler.dart';
+import 'package:webdriver/src/handler/json_wire_handler.dart';
+import 'package:webdriver/src/handler/w3c_handler.dart';
import 'web_element.dart';
@@ -61,8 +63,12 @@
/// If [xOffset] and [yOffset] are specified, will move the mouse that
/// distance from its current location.
///
- /// If all three are specified, will move the mouse to the offset relative to
- /// the top-left corner of the [element].
+ /// If all three are specified, the behavior will be different
+ /// for W3C and JsonWire. For W3C, it will use [element] center as the
+ /// origin, while for JsonWire, it will use [element] top left corner.
+ /// To get a consistent behavior across browsers, you can try
+ /// [moveToElementCenter] and [moveToElementTopLeft] to specify the origin you
+ /// would like to use.
///
/// All other combinations of parameters are illegal.
///
@@ -79,6 +85,45 @@
_handler.mouse.parseMoveToResponse);
}
+ /// Moves to [element], with an offset of [xOffset] and [yOffset] based on the
+ /// center of [element].
+ void moveToElementCenter(WebElement element, {int xOffset, int yOffset}) {
+ if (_handler is JsonWireWebDriverHandler) {
+ final size = element.size;
+ moveTo(
+ element: element,
+ xOffset: (xOffset ?? 0) + size.width ~/ 2,
+ yOffset: (yOffset ?? 0) + size.height ~/ 2);
+ } else {
+ moveTo(element: element, xOffset: xOffset, yOffset: yOffset);
+ }
+ }
+
+ /// Moves to [element], with an offset of [xOffset] and [yOffset] based on the
+ /// top left corner of [element].
+ void moveToElementTopLeft(WebElement element, {int xOffset, int yOffset}) {
+ if (_handler is W3cWebDriverHandler) {
+ final size = element.size;
+ moveTo(
+ element: element,
+ xOffset: (xOffset ?? 0) - size.width ~/ 2,
+ yOffset: (yOffset ?? 0) - size.height ~/ 2);
+ } else {
+ moveTo(element: element, xOffset: xOffset, yOffset: yOffset);
+ }
+ }
+
+ /// Moves the mouse away to hide its effect, like hover over element.
+ ///
+ /// For W3C, the mouse cannot move out of the screen, the workaround would be
+ /// to move to somewhere on edge where it's not on any element. You can
+ /// configure the location with [w3cXOffset] and [w3cYOffset]. By default,
+ /// it's at (1000, 0).
+ void hide({int w3cXOffset = 1000, int w3cYOffset = 0}) =>
+ _handler is W3cWebDriverHandler
+ ? moveTo(xOffset: w3cXOffset, yOffset: w3cYOffset, absolute: true)
+ : moveTo(xOffset: -10000, yOffset: -10000);
+
@override
String toString() => '$_handler.mouse($_client)';
diff --git a/lib/src/sync/web_driver.dart b/lib/src/sync/web_driver.dart
index dc6ec5d..6ffe382 100644
--- a/lib/src/sync/web_driver.dart
+++ b/lib/src/sync/web_driver.dart
@@ -128,6 +128,10 @@
this,
by);
+ /// Search for an element by xpath within the entire current page.
+ /// Throws [NoSuchElementException] if a matching element is not found.
+ WebElement findElementByXpath(String by) => findElement(By.xpath(by));
+
/// An artist's rendition of the current page's source.
String get pageSource => _client.send(_handler.core.buildPageSourceRequest(),
_handler.core.parsePageSourceResponse);
@@ -202,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/lib/src/sync/web_element.dart b/lib/src/sync/web_element.dart
index 6901d91..8bb82a9 100644
--- a/lib/src/sync/web_element.dart
+++ b/lib/src/sync/web_element.dart
@@ -25,7 +25,7 @@
// ignore: uri_does_not_exist
import 'common_stub.dart'
- // ignore: uri_does_not_exist
+// ignore: uri_does_not_exist
if (dart.library.io) 'common_io.dart';
/// WebDriver representation and interactions with an HTML element.
@@ -60,6 +60,39 @@
WebElement(this.driver, this._client, this._handler, this.id,
[this.context, this.locator, this.index]);
+ WebElement get parent => WebElement(
+ driver,
+ _client,
+ _handler,
+ _client.send(_handler.element.buildPropertyRequest(id, 'parentElement'),
+ _handler.elementFinder.parseFindElementResponse));
+
+ static final _parentCache = <String, String>{};
+
+ /// Gets a chain of parent elements, including the element itself.
+ List<String> get parents {
+ var p = this;
+ final result = <String>[];
+ while (p.id != null) {
+ if (_parentCache.containsKey(p.id)) {
+ break;
+ }
+ result.add(p.id);
+ _parentCache[p.id] = (p = p.parent).id;
+ }
+
+ if (p.id != null) {
+ // Hit cache in the previous loop.
+ var id = p.id;
+ while (id != null) {
+ result.add(id);
+ id = _parentCache[id];
+ }
+ }
+
+ return result;
+ }
+
/// Click on this element.
void click() {
_client.send(_handler.element.buildClickRequest(id),
diff --git a/lib/sync_core.dart b/lib/sync_core.dart
index 336889a..456f155 100644
--- a/lib/sync_core.dart
+++ b/lib/sync_core.dart
@@ -94,7 +94,7 @@
final handler = getHandler(spec);
session = client.send(handler.session.buildInfoRequest(sessionId),
- handler.session.parseInfoResponse);
+ (response) => handler.session.parseInfoResponse(response, sessionId));
}
if (session.spec != WebDriverSpec.JsonWire &&
diff --git a/lib/sync_io.dart b/lib/sync_io.dart
index b3fdd88..9d2b896 100644
--- a/lib/sync_io.dart
+++ b/lib/sync_io.dart
@@ -31,9 +31,13 @@
core.WebDriver createDriver(
{Uri uri,
Map<String, dynamic> desired,
- core.WebDriverSpec spec = core.WebDriverSpec.Auto}) =>
- core.createDriver((prefix) => SyncHttpRequestClient(prefix),
- uri: uri, desired: desired, spec: spec);
+ core.WebDriverSpec spec = core.WebDriverSpec.Auto,
+ Map<String, String> webDriverHeaders = const {}}) =>
+ core.createDriver(
+ (prefix) => SyncHttpRequestClient(prefix, headers: webDriverHeaders),
+ uri: uri,
+ desired: desired,
+ spec: spec);
/// Creates a sync WebDriver from existing session using
/// [SyncHttpRequestClient].
diff --git a/test/async_command_event_test.dart b/test/async_command_event_test.dart
index 4daa81d..0cf17a1 100644
--- a/test/async_command_event_test.dart
+++ b/test/async_command_event_test.dart
@@ -68,5 +68,5 @@
expect(events[1].startTime.isBefore(events[1].endTime), isTrue);
expect(events[1].stackTrace, const TypeMatcher<Chain>());
});
- }, testOn: '!js');
+ }, testOn: '!js', timeout: const Timeout(Duration(minutes: 2)));
}
diff --git a/test/async_cookies_test.dart b/test/async_cookies_test.dart
index a8d87da..2ac93a6 100644
--- a/test/async_cookies_test.dart
+++ b/test/async_cookies_test.dart
@@ -20,6 +20,8 @@
import 'configs/async_io_config.dart' as config;
+final _expiryDate = DateTime.now().add(const Duration(days: 180));
+
void main() {
group('Cookies', () {
WebDriver driver;
@@ -44,9 +46,8 @@
});
test('add complex cookie and get', () async {
- var date = DateTime.utc(2020);
await driver.cookies.add(Cookie('mycookie', 'myvalue',
- path: '/', domain: '.google.com', secure: false, expiry: date));
+ path: '/', domain: '.google.com', secure: false, expiry: _expiryDate));
final cookie = await driver.cookies.getCookie('mycookie');
expect(cookie.value, 'myvalue');
@@ -55,9 +56,8 @@
test('get all cookies', () async {
await driver.cookies.add(Cookie('mycookie', 'myvalue'));
- var date = DateTime.utc(2020);
await driver.cookies.add(Cookie('mycomplexcookie', 'mycomplexvalue',
- path: '/', domain: '.google.com', secure: false, expiry: date));
+ path: '/', domain: '.google.com', secure: false, expiry: _expiryDate));
bool found = false;
await for (var cookie in driver.cookies.all) {
@@ -102,9 +102,8 @@
// So instead, we plant two cookies and test that they are actually
// removed by [deleteAll].
await driver.cookies.add(Cookie('mycookie', 'myvalue'));
- var date = DateTime.utc(2020);
await driver.cookies.add(Cookie('mycomplexcookie', 'mycomplexvalue',
- path: '/', domain: '.google.com', secure: false, expiry: date));
+ path: '/', domain: '.google.com', secure: false, expiry: _expiryDate));
await driver.cookies.deleteAll();
@@ -118,5 +117,5 @@
expect(found, isFalse);
});
- });
+ }, timeout: const Timeout(Duration(minutes: 2)));
}
diff --git a/test/async_logs_test.dart b/test/async_logs_test.dart
index bf38610..c885891 100644
--- a/test/async_logs_test.dart
+++ b/test/async_logs_test.dart
@@ -44,7 +44,12 @@
test('get logs', () async {
List<LogEntry> logs = await driver.logs.get(LogType.performance).toList();
- expect(logs.length, greaterThan(0));
+ if (driver.capabilities['browserName'] == 'firefox') {
+ expect(logs, isEmpty);
+ return;
+ }
+
+ expect(logs, isNotEmpty);
logs.forEach((entry) {
expect(entry.level, equals(LogLevel.info));
});
diff --git a/test/async_mouse_test.dart b/test/async_mouse_test.dart
index a5f4e41..0706b32 100644
--- a/test/async_mouse_test.dart
+++ b/test/async_mouse_test.dart
@@ -28,6 +28,20 @@
WebElement button;
HttpServer server;
+ Future<bool> hasAlert() async {
+ try {
+ await driver.switchTo.alert.dismiss();
+ return true;
+ } on NoSuchAlertException {
+ return false;
+ }
+ }
+
+ Future<bool> mouseOnButton() async {
+ await driver.mouse.click();
+ return await hasAlert();
+ }
+
setUp(() async {
driver = await config.createTestDriver();
server = await config.createTestServerAndGoToTestPage(driver);
@@ -41,24 +55,58 @@
test('moveTo element/click', () async {
await driver.mouse.moveTo(element: button);
- await driver.mouse.click();
- var alert = await driver.switchTo.alert;
- await alert.dismiss();
+ expect(await mouseOnButton(), true);
});
test('moveTo coordinates/click', () async {
var pos = await button.location;
await driver.mouse.moveTo(xOffset: pos.x + 5, yOffset: pos.y + 5);
- await driver.mouse.click();
- var alert = await driver.switchTo.alert;
- await alert.dismiss();
+ expect(await mouseOnButton(), true);
});
test('moveTo element coordinates/click', () async {
- await driver.mouse.moveTo(element: button, xOffset: 5, yOffset: 5);
- await driver.mouse.click();
- var alert = await driver.switchTo.alert;
- await alert.dismiss();
+ await driver.mouse.moveTo(element: button, xOffset: 15, yOffset: 15);
+ // W3C uses center and JsonWire uses top left corner.
+ expect(await mouseOnButton(), driver.spec == WebDriverSpec.JsonWire);
+ });
+
+ test('moveTo element coordinates outside of element/click', () async {
+ await driver.mouse.moveTo(element: button, xOffset: -5, yOffset: -5);
+ // W3C uses center and JsonWire uses top left corner.
+ expect(await mouseOnButton(), driver.spec == WebDriverSpec.W3c);
+ });
+
+ test('moveToElementCenter moves to correct positions', () async {
+ await driver.mouse.moveToElementCenter(button, xOffset: -5, yOffset: -5);
+ expect(await mouseOnButton(), true);
+ await driver.mouse.moveToElementCenter(button, xOffset: 15, yOffset: 15);
+ expect(await mouseOnButton(), false);
+ });
+
+ test('moveToElementTopLeft moves to correct positions', () async {
+ await driver.mouse.moveToElementTopLeft(button, xOffset: -5, yOffset: -5);
+ expect(await mouseOnButton(), false);
+ await driver.mouse.moveToElementTopLeft(button, xOffset: 15, yOffset: 15);
+ expect(await mouseOnButton(), true);
+ });
+
+ test('hide moves away from the current location', () async {
+ await driver.mouse.moveTo(element: button);
+ expect(await mouseOnButton(), true);
+ await driver.mouse.hide();
+ expect(await mouseOnButton(), false);
+ });
+
+ test('hide moves to given location in w3c.', () async {
+ if (driver.spec == WebDriverSpec.W3c) {
+ var pos = await button.location;
+ await driver.mouse.moveTo(element: button);
+ expect(await mouseOnButton(), true);
+ await driver.mouse.moveTo(xOffset: 0, yOffset: 0, absolute: true);
+ expect(await mouseOnButton(), false);
+ await driver.mouse.hide(w3cXOffset: pos.x + 5, w3cYOffset: pos.y + 5);
+ expect(await mouseOnButton(), true);
+ }
});
// TODO(DrMarcII): Better up/down tests
@@ -66,16 +114,14 @@
await driver.mouse.moveTo(element: button);
await driver.mouse.down();
await driver.mouse.up();
- var alert = await driver.switchTo.alert;
- await alert.dismiss();
+ expect(await hasAlert(), true);
});
// TODO(DrMarcII): Better double click test
test('doubleClick', () async {
await driver.mouse.moveTo(element: button);
await driver.mouse.doubleClick();
- var alert = await driver.switchTo.alert;
- await alert.dismiss();
+ expect(await hasAlert(), true);
});
}, timeout: const Timeout(Duration(minutes: 2)));
}
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/async_web_element_test.dart b/test/async_web_element_test.dart
index 4729a45..c378a1d 100644
--- a/test/async_web_element_test.dart
+++ b/test/async_web_element_test.dart
@@ -33,6 +33,7 @@
WebElement checkbox;
WebElement disabled;
WebElement invisible;
+ WebElement inner;
HttpServer server;
setUp(() async {
@@ -49,7 +50,8 @@
.findElement(const By.cssSelector('input[type=checkbox]'));
disabled = await driver
.findElement(const By.cssSelector('input[type=password]'));
- invisible = await driver.findElement(const By.tagName('div'));
+ invisible = await driver.findElement(const By.id('invisible-div'));
+ inner = await driver.findElement(const By.id('inner-div'));
});
tearDown(() async {
@@ -98,6 +100,7 @@
expect(await checkbox.displayed, isTrue);
expect(await disabled.displayed, isTrue);
expect(await invisible.displayed, isFalse);
+ expect(await inner.displayed, isFalse);
});
test('location -- table', () async {
@@ -124,7 +127,6 @@
test('size -- invisible', () async {
var size = await invisible.size;
expect(size, config.isRectangle);
- // TODO(DrMarcII): I thought these should be 0
expect(size.width, isNonNegative);
expect(size.height, isNonNegative);
});
diff --git a/test/configs/async_io_config.dart b/test/configs/async_io_config.dart
index 5eabdfd..9d0ed83 100644
--- a/test/configs/async_io_config.dart
+++ b/test/configs/async_io_config.dart
@@ -63,7 +63,7 @@
}
});
- await driver.get('http://localhost:${server.port}/test_page.html');
+ await driver.get('http://$testHostname:${server.port}/test_page.html');
return server;
}
diff --git a/test/configs/common_config.dart b/test/configs/common_config.dart
index da03925..0933320 100644
--- a/test/configs/common_config.dart
+++ b/test/configs/common_config.dart
@@ -29,6 +29,8 @@
Future<HttpServer> createLocalServer() =>
HttpServer.bind(InternetAddress.anyIPv4, 0);
+String get testHostname => '127.0.0.1';
+
String get testHomePath => path.absolute('test');
Uri getWebDriverUri(WebDriverSpec spec) {
diff --git a/test/configs/sync_io_config.dart b/test/configs/sync_io_config.dart
index 8ff3ac9..0795003 100644
--- a/test/configs/sync_io_config.dart
+++ b/test/configs/sync_io_config.dart
@@ -61,7 +61,7 @@
});
await driver.asyncDriver
- .get('http://localhost:${server.port}/test_page.html');
+ .get('http://$testHostname:${server.port}/test_page.html');
return server;
}
diff --git a/test/sync/command_event.dart b/test/sync/command_event.dart
index a92821c..ea6f1cf 100644
--- a/test/sync/command_event.dart
+++ b/test/sync/command_event.dart
@@ -15,6 +15,8 @@
@TestOn('vm')
library webdriver.command_event_test;
+import 'dart:io';
+
import 'package:stack_trace/stack_trace.dart';
import 'package:test/test.dart';
import 'package:webdriver/sync_core.dart';
@@ -24,19 +26,23 @@
void runTests({WebDriverSpec spec = WebDriverSpec.Auto}) {
group('CommandEvent', () {
WebDriver driver;
+ HttpServer server;
var events = <WebDriverCommandEvent>[];
- setUp(() {
+ setUp(() async {
driver = config.createTestDriver(spec: spec);
driver.addEventListener(events.add);
- driver.get(config.testPagePath);
+
+ server = await config.createTestServerAndGoToTestPage(driver);
});
- tearDown(() {
+ tearDown(() async {
driver.quit();
events.clear();
driver = null;
+
+ await server?.close(force: true);
});
test('handles exceptions', () {
@@ -44,22 +50,26 @@
driver.switchTo.alert.text;
fail('Expected exception on no alert');
} catch (NoSuchAlertException) {}
- expect(events[1].method, 'GET');
- expect(events[1].endPoint, contains('alert'));
- expect(events[1].exception, const isInstanceOf<WebDriverException>());
- expect(events[1].result, isNull);
- expect(events[1].startTime.isBefore(events[1].endTime), isTrue);
- expect(events[1].stackTrace, const isInstanceOf<Chain>());
+ // TODO(b/140553567): There should be two events.
+ expect(events, hasLength(1));
+ expect(events[0].method, 'GET');
+ expect(events[0].endPoint, contains('alert'));
+ expect(events[0].exception, const TypeMatcher<WebDriverException>());
+ expect(events[0].result, isNull);
+ expect(events[0].startTime.isBefore(events[0].endTime), isTrue);
+ expect(events[0].stackTrace, const TypeMatcher<Chain>());
});
test('handles normal operation', () {
driver.findElements(const By.cssSelector('nosuchelement')).toList();
- expect(events[1].method, 'POST');
- expect(events[1].endPoint, contains('elements'));
- expect(events[1].exception, isNull);
- expect(events[1].result, isNotNull);
- expect(events[1].startTime.isBefore(events[1].endTime), isTrue);
- expect(events[1].stackTrace, const TypeMatcher<Chain>());
+ // TODO(b/140553567): There should be two events.
+ expect(events, hasLength(1));
+ expect(events[0].method, 'POST');
+ expect(events[0].endPoint, contains('elements'));
+ expect(events[0].exception, isNull);
+ expect(events[0].result, isNotNull);
+ expect(events[0].startTime.isBefore(events[0].endTime), isTrue);
+ expect(events[0].stackTrace, const TypeMatcher<Chain>());
});
}, timeout: const Timeout(Duration(minutes: 2)));
}
diff --git a/test/sync/cookies.dart b/test/sync/cookies.dart
index 1bd1a67..c885342 100644
--- a/test/sync/cookies.dart
+++ b/test/sync/cookies.dart
@@ -20,6 +20,8 @@
import '../configs/sync_io_config.dart' as config;
+final _expiryDate = DateTime.now().add(const Duration(days: 180));
+
void runTests({WebDriverSpec spec = WebDriverSpec.Auto}) {
group('Cookies', () {
WebDriver driver;
@@ -44,9 +46,11 @@
});
test('add complex cookie and get', () {
- var date = DateTime.utc(2020);
driver.cookies.add(Cookie('mycookie', 'myvalue',
- path: '/', domain: '.google.com', secure: false, expiry: date));
+ path: '/',
+ domain: '.google.com',
+ secure: false,
+ expiry: _expiryDate));
final cookie = driver.cookies.getCookie('mycookie');
expect(cookie.value, 'myvalue');
@@ -55,9 +59,11 @@
test('get all cookies', () {
driver.cookies.add(Cookie('mycookie', 'myvalue'));
- var date = DateTime.utc(2020);
driver.cookies.add(Cookie('mycomplexcookie', 'mycomplexvalue',
- path: '/', domain: '.google.com', secure: false, expiry: date));
+ path: '/',
+ domain: '.google.com',
+ secure: false,
+ expiry: _expiryDate));
bool found = false;
for (var cookie in driver.cookies.all) {
@@ -101,9 +107,11 @@
// So instead, we plant two cookies and test that they are actually
// removed by [deleteAll].
driver.cookies.add(Cookie('mycookie', 'myvalue'));
- var date = DateTime.utc(2020);
driver.cookies.add(Cookie('mycomplexcookie', 'mycomplexvalue',
- path: '/', domain: '.google.com', secure: false, expiry: date));
+ path: '/',
+ domain: '.google.com',
+ secure: false,
+ expiry: _expiryDate));
driver.cookies.deleteAll();
diff --git a/test/sync/logs.dart b/test/sync/logs.dart
index 4689d52..fd30fb9 100644
--- a/test/sync/logs.dart
+++ b/test/sync/logs.dart
@@ -44,7 +44,12 @@
test('get logs', () {
List<LogEntry> logs = driver.logs.get(LogType.performance).toList();
- expect(logs.length, greaterThan(0));
+ if (driver.capabilities['browserName'] == 'firefox') {
+ expect(logs, isEmpty);
+ return;
+ }
+
+ expect(logs, isNotEmpty);
logs.forEach((entry) {
expect(entry.level, equals(LogLevel.info));
});
diff --git a/test/sync/mouse.dart b/test/sync/mouse.dart
index 4f3b3f8..fe95015 100644
--- a/test/sync/mouse.dart
+++ b/test/sync/mouse.dart
@@ -28,6 +28,20 @@
WebElement button;
HttpServer server;
+ bool hasAlert() {
+ try {
+ driver.switchTo.alert.dismiss();
+ return true;
+ } on NoSuchAlertException {
+ return false;
+ }
+ }
+
+ bool mouseOnButton() {
+ driver.mouse.click();
+ return hasAlert();
+ }
+
setUp(() async {
driver = config.createTestDriver(spec: spec);
server = await config.createTestServerAndGoToTestPage(driver);
@@ -41,30 +55,23 @@
test('moveTo element/click', () {
driver.mouse.moveTo(element: button);
- driver.mouse.click();
- var alert = driver.switchTo.alert;
- alert.dismiss();
+ expect(mouseOnButton(), true);
});
test('moveTo coordinates/click', () {
var pos = button.location;
driver.mouse.moveTo(xOffset: pos.x + 5, yOffset: pos.y + 5);
- driver.mouse.click();
- var alert = driver.switchTo.alert;
- alert.dismiss();
+ expect(mouseOnButton(), true);
});
test('moveTo absolute coordinates/click', () {
if (driver.spec == WebDriverSpec.W3c) {
var pos = button.location;
driver.mouse.moveTo(xOffset: pos.x + 200, yOffset: pos.y + 200);
- driver.mouse.click();
- // Should have no alert
+ expect(mouseOnButton(), false);
driver.mouse
.moveTo(xOffset: pos.x + 5, yOffset: pos.y + 5, absolute: true);
- driver.mouse.click();
- var alert = driver.switchTo.alert;
- alert.dismiss();
+ expect(mouseOnButton(), true);
}
});
@@ -80,10 +87,48 @@
});
test('moveTo element coordinates/click', () {
- driver.mouse.moveTo(element: button, xOffset: 5, yOffset: 5);
- driver.mouse.click();
- var alert = driver.switchTo.alert;
- alert.dismiss();
+ driver.mouse.moveTo(element: button, xOffset: 15, yOffset: 15);
+ // W3C uses center and JsonWire uses top left corner.
+ expect(mouseOnButton(), driver.spec == WebDriverSpec.JsonWire);
+ });
+
+ test('moveTo element coordinates outside of element/click', () {
+ driver.mouse.moveTo(element: button, xOffset: -5, yOffset: -5);
+ // W3C uses center and JsonWire uses top left corner.
+ expect(mouseOnButton(), driver.spec == WebDriverSpec.W3c);
+ });
+
+ test('moveToElementCenter moves to correct positions', () {
+ driver.mouse.moveToElementCenter(button, xOffset: -5, yOffset: -5);
+ expect(mouseOnButton(), true);
+ driver.mouse.moveToElementCenter(button, xOffset: 15, yOffset: 15);
+ expect(mouseOnButton(), false);
+ });
+
+ test('moveToElementTopLeft moves to correct positions', () {
+ driver.mouse.moveToElementTopLeft(button, xOffset: -5, yOffset: -5);
+ expect(mouseOnButton(), false);
+ driver.mouse.moveToElementTopLeft(button, xOffset: 15, yOffset: 15);
+ expect(mouseOnButton(), true);
+ });
+
+ test('hide moves away from the current location', () {
+ driver.mouse.moveTo(element: button);
+ expect(mouseOnButton(), true);
+ driver.mouse.hide();
+ expect(mouseOnButton(), false);
+ });
+
+ test('hide moves to given location in w3c.', () {
+ if (driver.spec == WebDriverSpec.W3c) {
+ var pos = button.location;
+ driver.mouse.moveTo(element: button);
+ expect(mouseOnButton(), true);
+ driver.mouse.moveTo(xOffset: 0, yOffset: 0, absolute: true);
+ expect(mouseOnButton(), false);
+ driver.mouse.hide(w3cXOffset: pos.x + 5, w3cYOffset: pos.y + 5);
+ expect(mouseOnButton(), true);
+ }
});
// TODO(DrMarcII): Better up/down tests
diff --git a/test/sync/navigation.dart b/test/sync/navigation.dart
index 4f16aa9..07c132c 100644
--- a/test/sync/navigation.dart
+++ b/test/sync/navigation.dart
@@ -15,6 +15,8 @@
@TestOn('vm')
library webdriver.navigation_test;
+import 'dart:io';
+
import 'package:test/test.dart';
import 'package:webdriver/sync_core.dart';
@@ -23,22 +25,25 @@
void runTests({WebDriverSpec spec = WebDriverSpec.Auto}) {
group('Navigation', () {
WebDriver driver;
+ HttpServer server;
- setUp(() {
+ setUp(() async {
driver = config.createTestDriver(spec: spec);
- driver.get(config.testPagePath);
+ server = await config.createTestServerAndGoToTestPage(driver);
});
- tearDown(() {
+ tearDown(() async {
if (driver != null) {
driver.quit();
}
driver = null;
+
+ await server?.close(force: true);
});
- test('refresh', () {
+ test('refresh', () async {
var element = driver.findElement(const By.tagName('button'));
- driver.refresh();
+ await driver.asyncDriver.refresh();
try {
element.name;
} on Exception {
diff --git a/test/sync/web_driver.dart b/test/sync/web_driver.dart
index 0e0010b..fab23d7 100644
--- a/test/sync/web_driver.dart
+++ b/test/sync/web_driver.dart
@@ -172,12 +172,26 @@
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));
diff --git a/test/sync/web_element.dart b/test/sync/web_element.dart
index ae8e99f..ab870bf 100644
--- a/test/sync/web_element.dart
+++ b/test/sync/web_element.dart
@@ -33,6 +33,7 @@
WebElement checkbox;
WebElement disabled;
WebElement invisible;
+ WebElement inner;
HttpServer server;
setUp(() async {
@@ -47,7 +48,8 @@
driver.findElement(const By.cssSelector('input[type=checkbox]'));
disabled =
driver.findElement(const By.cssSelector('input[type=password]'));
- invisible = driver.findElement(const By.tagName('div'));
+ invisible = await driver.findElement(const By.id('invisible-div'));
+ inner = await driver.findElement(const By.id('inner-div'));
});
tearDown(() async {
@@ -96,6 +98,7 @@
expect(checkbox.displayed, isTrue);
expect(disabled.displayed, isTrue);
expect(invisible.displayed, isFalse);
+ expect(inner.displayed, isFalse);
});
test('rect -- table', () {
@@ -112,13 +115,8 @@
expect(rect, config.isRectangle);
expect(rect.left, 0);
expect(rect.top, 0);
- if (driver.spec == WebDriverSpec.W3c) {
- expect(rect.width, 0);
- expect(rect.height, 0);
- } else {
- expect(rect.width, isNonNegative);
- expect(rect.height, isNonNegative);
- }
+ expect(rect.width, isNonNegative);
+ expect(rect.height, isNonNegative);
});
test('location -- table', () {
@@ -145,13 +143,8 @@
test('size -- invisible', () {
var size = invisible.size;
expect(size, config.isRectangle);
- if (driver.spec == WebDriverSpec.W3c) {
- expect(size.width, 0);
- expect(size.height, 0);
- } else {
- expect(size.width, isNonNegative);
- expect(size.height, isNonNegative);
- }
+ expect(size.width, isNonNegative);
+ expect(size.height, isNonNegative);
});
test('name', () {
diff --git a/test/test_page.html b/test/test_page.html
index fbf3123..29cf154 100644
--- a/test/test_page.html
+++ b/test/test_page.html
@@ -49,8 +49,11 @@
<input type='password' disabled/>
<input type='submit'/>
</form>
-<div id='div' style='display: none; background-color: red'>
+<div id='invisible-div' style='display: none; background-color: red'>
some not displayed text
+ <div id='inner-div'>
+ inner div should not be displayed either.
+ </div>
</div>
<a id='settable' href="test_page.html" target="_new">
Open copy in other window</a>