From 82bebf2e6b318ce907b2872c0313693d029c8f78 Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Thu, 13 Feb 2025 19:15:34 -0600 Subject: [PATCH 1/5] Replace usages of dart:math geometry types with custom types --- CHANGELOG.md | 5 ++ lib/async_core.dart | 1 + lib/src/async/web_element.dart | 11 ++- lib/src/async/window.dart | 20 ++--- lib/src/common/geometry.dart | 114 +++++++++++++++++++++++++ lib/src/common/webdriver_handler.dart | 20 ++--- lib/src/handler/json_wire/element.dart | 24 +++--- lib/src/handler/json_wire/window.dart | 50 +++++------ lib/src/handler/w3c/element.dart | 21 +++-- lib/src/handler/w3c/window.dart | 34 ++++---- lib/src/sync/web_element.dart | 11 ++- lib/src/sync/window.dart | 27 +++--- lib/sync_core.dart | 1 + pubspec.yaml | 2 +- test/async_window_test.dart | 9 +- test/configs/common_config.dart | 5 +- test/sync/window.dart | 5 +- 17 files changed, 236 insertions(+), 124 deletions(-) create mode 100644 lib/src/common/geometry.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 7450f99..a9d96f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 4.0.0-wip + +* Replace usages of `Point` and `Rectangle` from `dart:math` with + custom `Location`, `Rect`, and `Size` types. + ## 3.1.0 * Add a `reason` argument to `Clock.waitFor`. diff --git a/lib/async_core.dart b/lib/async_core.dart index d4a0d09..f9d40a1 100644 --- a/lib/async_core.dart +++ b/lib/async_core.dart @@ -37,6 +37,7 @@ export 'package:webdriver/src/common/capabilities.dart'; export 'package:webdriver/src/common/command_event.dart'; export 'package:webdriver/src/common/cookie.dart'; export 'package:webdriver/src/common/exception.dart'; +export 'package:webdriver/src/common/geometry.dart'; export 'package:webdriver/src/common/log.dart'; export 'package:webdriver/src/common/mouse.dart'; export 'package:webdriver/src/common/spec.dart'; diff --git a/lib/src/async/web_element.dart b/lib/src/async/web_element.dart index 9ff9798..b868cf8 100644 --- a/lib/src/async/web_element.dart +++ b/lib/src/async/web_element.dart @@ -13,9 +13,9 @@ // limitations under the License. import 'dart:async'; -import 'dart:math'; import '../common/by.dart'; +import '../common/geometry.dart'; import '../common/request_client.dart'; import '../common/web_element.dart' as common; import '../common/webdriver_handler.dart'; @@ -75,20 +75,19 @@ class WebElement extends common.WebElement implements SearchContext { _handler.element.parseDisplayedResponse); /// The location within the document of this element. - Future> get location => _client.send( + Future get location => _client.send( _handler.element.buildLocationRequest(id), _handler.element.parseLocationResponse); /// The size of this element. - Future> get size => _client.send( - _handler.element.buildSizeRequest(id), + Future get size => _client.send(_handler.element.buildSizeRequest(id), _handler.element.parseSizeResponse); /// The bounds of this element. - Future> get rect async { + Future get rect async { final location = await this.location; final size = await this.size; - return Rectangle(location.x, location.y, size.width, size.height); + return Rect.from(topLeft: location, size: size); } /// The tag name for this element. diff --git a/lib/src/async/window.dart b/lib/src/async/window.dart index 8e2ee43..ab26ffc 100644 --- a/lib/src/async/window.dart +++ b/lib/src/async/window.dart @@ -13,8 +13,8 @@ // limitations under the License. import 'dart:async'; -import 'dart:math'; +import '../common/geometry.dart'; import '../common/request_client.dart'; import '../common/webdriver_handler.dart'; @@ -31,21 +31,21 @@ class Window { _handler.window.parseSetActiveResponse); /// The location of the window. - Future> get location => _client.send( + Future get location => _client.send( _handler.window.buildLocationRequest(), _handler.window.parseLocationResponse); /// The outer size of the window. - Future> get size => _client.send( + Future get size => _client.send( _handler.window.buildSizeRequest(), _handler.window.parseSizeResponse); /// The inner size of the window. - Future> get innerSize => _client.send( + Future get innerSize => _client.send( _handler.window.buildInnerSizeRequest(), _handler.window.parseInnerSizeResponse); /// The location and size of the window. - Future> get rect async { + Future get rect async { try { return await _client.send(_handler.window.buildRectRequest(), _handler.window.parseRectResponse); @@ -54,22 +54,22 @@ class Window { // Delegate to other methods. final location = await this.location; final size = await this.size; - return Rectangle(location.x, location.y, size.width, size.height); + return Rect.from(topLeft: location, size: size); } } /// Sets the window location. - Future setLocation(Point point) => _client.send( + Future setLocation(Position point) => _client.send( _handler.window.buildSetLocationRequest(point), _handler.window.parseSetLocationResponse); /// Sets the window size. - Future setSize(Rectangle size) => _client.send( + Future setSize(Size size) => _client.send( _handler.window.buildSetSizeRequest(size), _handler.window.parseSetSizeResponse); /// The location and size of the window. - Future setRect(Rectangle rect) async { + Future setRect(Rect rect) async { try { await _client.send(_handler.window.buildSetRectRequest(rect), _handler.window.parseSetRectResponse); @@ -78,7 +78,7 @@ class Window { // JsonWire cannot implement this API in one call. // Delegate to other methods. await setLocation(rect.topLeft); - await setSize(Rectangle(0, 0, rect.width, rect.height)); + await setSize(rect.size); } } diff --git a/lib/src/common/geometry.dart b/lib/src/common/geometry.dart new file mode 100644 index 0000000..087df03 --- /dev/null +++ b/lib/src/common/geometry.dart @@ -0,0 +1,114 @@ +// Copyright 2025 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// A two-dimensional location represented by [x] and [y] coordinates on +/// a 2D-coordinate system where the origin `(0, 0)` is in the top-left corner. +final class Position { + /// The x-coordinate of this position. + final int x; + + /// The y-coordinate of this position. + final int y; + + /// Create a location at the specified [x] and [y] coordinates. + const Position({required this.x, required this.y}); +} + +/// A rectangle, which is a quadrilateral with four right angles, represented on +/// a 2D-coordinate system where the origin `(0, 0)` is in the top-left corner. +final class Rect { + final int _left; + final int _top; + final int _width; + final int _height; + + /// Create a rectangle with its upper-left corner at `(left, top)` + /// and its bottom right corner at `(left + width, top + height)`. + /// + /// [width] and [height] should both be non-negative. + /// If they aren't, they are clamped to zero. + const Rect({ + required int left, + required int top, + required int width, + required int height, + }) : assert(width >= 0, height >= 0), + _top = top, + _left = left, + _width = (width < 0) ? 0 : width, + _height = (height < 0) ? 0 : height; + + /// Create a rectangle with its upper-left corner at `(topLeft.x, topLeft.y)` + /// and its bottom right corner at `(topLeft.x + width, topLeft.y + height)`. + /// + /// The `width` and `height` of [Size] should both be non-negative. + factory Rect.from({required Position topLeft, required Size size}) => Rect( + left: topLeft.x, + top: topLeft.y, + width: size.width, + height: size.height, + ); + + /// The width of this rectangle. + int get width => _width; + + /// The height of this rectangle. + int get height => _height; + + /// The size of this rectangle. + Size get size => Size(width: _width, height: _height); + + /// The x-coordinate of the left edge of this rectangle. + int get left => _left; + + /// The y-coordinate of the top edge of this rectangle. + int get top => _top; + + /// The x-coordinate of the right edge of this rectangle. + int get right => _left + _width; + + /// The x-coordinate of the bottom edge of this rectangle. + int get bottom => _top + _height; + + /// The location of the top-left corner of this rectangle. + Position get topLeft => Position(x: left, y: top); + + /// The location of the top-right corner of this rectangle. + Position get topRight => Position(x: right, y: top); + + /// The location of the bottom-right corner of this rectangle. + Position get bottomRight => Position(x: right, y: bottom); + + /// The location of the bottom-left corner of this rectangle. + Position get bottomLeft => Position(x: left, y: bottom); +} + +/// The width and height dimensions of a 2D object. +final class Size { + /// The width dimension. + final int width; + + /// The height dimension. + final int height; + + /// Create a size that represents the + /// specified [width] and [height] dimensions. + /// + /// [width] and [height] should both be non-negative. + /// If they aren't, they are clamped to zero. + const Size({required int width, required int height}) + : assert(width >= 0, height >= 0), + width = (width < 0) ? 0 : width, + height = (height < 0) ? 0 : height; +} diff --git a/lib/src/common/webdriver_handler.dart b/lib/src/common/webdriver_handler.dart index ce1a25f..6f85a19 100644 --- a/lib/src/common/webdriver_handler.dart +++ b/lib/src/common/webdriver_handler.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import '../../async_core.dart'; import 'request.dart'; import 'session.dart'; @@ -157,7 +155,7 @@ abstract class ElementHandler { WebDriverRequest buildLocationRequest(String elementId); /// Parses response for 'Element Location'. - Point parseLocationResponse(WebDriverResponse response); + Position parseLocationResponse(WebDriverResponse response); /// Builds request for 'Element Size'. WebDriverRequest buildSizeRequest(String elementId); @@ -165,7 +163,7 @@ abstract class ElementHandler { /// Parses response for 'Element Size'. /// /// This will be the rectangle moved to (0, 0). - Rectangle parseSizeResponse(WebDriverResponse response); + Size parseSizeResponse(WebDriverResponse response); /// Builds request for 'Element Name'. WebDriverRequest buildNameRequest(String elementId); @@ -363,7 +361,7 @@ abstract class WindowHandler { WebDriverRequest buildLocationRequest(); /// Parses response for 'Window Location'. - Point parseLocationResponse(WebDriverResponse response); + Position parseLocationResponse(WebDriverResponse response); /// Builds request for 'Window Size'. WebDriverRequest buildSizeRequest(); @@ -371,28 +369,28 @@ abstract class WindowHandler { /// Parses response for 'Window Size'. /// /// This will be the rectangle moved to (0, 0). - Rectangle parseSizeResponse(WebDriverResponse response); + Size parseSizeResponse(WebDriverResponse response); /// Builds request for 'Window Rect'. WebDriverRequest buildRectRequest(); /// Parses response for 'Window Rect'. - Rectangle parseRectResponse(WebDriverResponse response); + Rect parseRectResponse(WebDriverResponse response); /// Builds request for 'Set Window Location'. - WebDriverRequest buildSetLocationRequest(Point location); + WebDriverRequest buildSetLocationRequest(Position location); /// Parses response for 'Set Window Location'. void parseSetLocationResponse(WebDriverResponse response); /// Builds request for 'Set Window Size'. - WebDriverRequest buildSetSizeRequest(Rectangle size); + WebDriverRequest buildSetSizeRequest(Size size); /// Parses response for 'Set Window Size'. void parseSetSizeResponse(WebDriverResponse response); /// Builds request for 'Set Window Rect'. - WebDriverRequest buildSetRectRequest(Rectangle rect); + WebDriverRequest buildSetRectRequest(Rect rect); /// Parses response for 'Set Window Rect'. void parseSetRectResponse(WebDriverResponse response); @@ -423,7 +421,7 @@ abstract class WindowHandler { WebDriverRequest buildInnerSizeRequest(); /// Parses response for 'Inner Size'. - Rectangle parseInnerSizeResponse(WebDriverResponse response); + Size parseInnerSizeResponse(WebDriverResponse response); } abstract class FrameHandler { diff --git a/lib/src/handler/json_wire/element.dart b/lib/src/handler/json_wire/element.dart index b8defa5..1ade9af 100644 --- a/lib/src/handler/json_wire/element.dart +++ b/lib/src/handler/json_wire/element.dart @@ -1,5 +1,4 @@ -import 'dart:math'; - +import '../../common/geometry.dart'; import '../../common/request.dart'; import '../../common/webdriver_handler.dart'; import 'utils.dart'; @@ -63,9 +62,12 @@ class JsonWireElementHandler extends ElementHandler { WebDriverRequest.getRequest('${elementPrefix(elementId)}location'); @override - Point parseLocationResponse(WebDriverResponse response) { - final point = parseJsonWireResponse(response) as Map; - return Point((point['x'] as num).toInt(), (point['y'] as num).toInt()); + Position parseLocationResponse(WebDriverResponse response) { + final point = parseJsonWireResponse(response) as Map; + return Position( + x: (point['x'] as num).toInt(), + y: (point['y'] as num).toInt(), + ); } @override @@ -73,13 +75,11 @@ class JsonWireElementHandler extends ElementHandler { WebDriverRequest.getRequest('${elementPrefix(elementId)}size'); @override - Rectangle parseSizeResponse(WebDriverResponse response) { - final size = parseJsonWireResponse(response) as Map; - return Rectangle( - 0, - 0, - (size['width'] as num).toInt(), - (size['height'] as num).toInt(), + Size parseSizeResponse(WebDriverResponse response) { + final size = parseJsonWireResponse(response) as Map; + return Size( + width: (size['width'] as num).toInt(), + height: (size['height'] as num).toInt(), ); } diff --git a/lib/src/handler/json_wire/window.dart b/lib/src/handler/json_wire/window.dart index 05ef108..eec8e0d 100644 --- a/lib/src/handler/json_wire/window.dart +++ b/lib/src/handler/json_wire/window.dart @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'dart:math'; - +import '../../common/geometry.dart'; import '../../common/request.dart'; import '../../common/webdriver_handler.dart'; import 'utils.dart'; @@ -49,11 +48,11 @@ class JsonWireWindowHandler extends WindowHandler { WebDriverRequest.getRequest('window/current/position'); @override - Point parseLocationResponse(WebDriverResponse response) { - final point = parseJsonWireResponse(response) as Map; - return Point( - (point['x'] as num).toInt(), - (point['y'] as num).toInt(), + Position parseLocationResponse(WebDriverResponse response) { + final point = parseJsonWireResponse(response) as Map; + return Position( + x: (point['x'] as num).toInt(), + y: (point['y'] as num).toInt(), ); } @@ -62,13 +61,11 @@ class JsonWireWindowHandler extends WindowHandler { WebDriverRequest.getRequest('window/current/size'); @override - Rectangle parseSizeResponse(WebDriverResponse response) { - final size = parseJsonWireResponse(response) as Map; - return Rectangle( - 0, - 0, - (size['width'] as num).toInt(), - (size['height'] as num).toInt(), + Size parseSizeResponse(WebDriverResponse response) { + final size = parseJsonWireResponse(response) as Map; + return Size( + width: (size['width'] as num).toInt(), + height: (size['height'] as num).toInt(), ); } @@ -78,14 +75,14 @@ class JsonWireWindowHandler extends WindowHandler { } @override - Rectangle parseRectResponse(WebDriverResponse response) { + Rect parseRectResponse(WebDriverResponse response) { throw UnsupportedError('Get Window Rect is not supported in JsonWire.'); } @override - WebDriverRequest buildSetLocationRequest(Point location) => - WebDriverRequest.postRequest('window/current/position', - {'x': location.x.toInt(), 'y': location.y.toInt()}); + WebDriverRequest buildSetLocationRequest(Position location) => + WebDriverRequest.postRequest( + 'window/current/position', {'x': location.x, 'y': location.y}); @override void parseSetLocationResponse(WebDriverResponse response) { @@ -93,9 +90,9 @@ class JsonWireWindowHandler extends WindowHandler { } @override - WebDriverRequest buildSetSizeRequest(Rectangle size) => - WebDriverRequest.postRequest('window/current/size', - {'width': size.width.toInt(), 'height': size.height.toInt()}); + WebDriverRequest buildSetSizeRequest(Size size) => + WebDriverRequest.postRequest( + 'window/current/size', {'width': size.width, 'height': size.height}); @override void parseSetSizeResponse(WebDriverResponse response) { @@ -103,7 +100,7 @@ class JsonWireWindowHandler extends WindowHandler { } @override - WebDriverRequest buildSetRectRequest(Rectangle rect) { + WebDriverRequest buildSetRectRequest(Rect rect) { throw UnsupportedError('Set Window Rect is not supported in JsonWire.'); } @@ -146,8 +143,11 @@ class JsonWireWindowHandler extends WindowHandler { }); @override - Rectangle parseInnerSizeResponse(WebDriverResponse response) { - final size = parseJsonWireResponse(response) as Map; - return Rectangle(0, 0, size['width'] as int, size['height'] as int); + Size parseInnerSizeResponse(WebDriverResponse response) { + final size = parseJsonWireResponse(response) as Map; + return Size( + width: (size['width'] as num).toInt(), + height: (size['height'] as num).toInt(), + ); } } diff --git a/lib/src/handler/w3c/element.dart b/lib/src/handler/w3c/element.dart index 3366de9..a9ca3b5 100644 --- a/lib/src/handler/w3c/element.dart +++ b/lib/src/handler/w3c/element.dart @@ -1,5 +1,4 @@ -import 'dart:math'; - +import '../../common/geometry.dart'; import '../../common/request.dart'; import '../../common/webdriver_handler.dart'; import 'utils.dart'; @@ -64,7 +63,7 @@ class W3cElementHandler extends ElementHandler { _buildRectRequest(elementId); @override - Point parseLocationResponse(WebDriverResponse response) => + Position parseLocationResponse(WebDriverResponse response) => _parseRectResponse(response).topLeft; @override @@ -72,21 +71,21 @@ class W3cElementHandler extends ElementHandler { _buildRectRequest(elementId); @override - Rectangle parseSizeResponse(WebDriverResponse response) { + Size parseSizeResponse(WebDriverResponse response) { final rect = _parseRectResponse(response); - return Rectangle(0, 0, rect.width, rect.height); + return rect.size; } WebDriverRequest _buildRectRequest(String elementId) => WebDriverRequest.getRequest('${elementPrefix(elementId)}rect'); - Rectangle _parseRectResponse(WebDriverResponse response) { + Rect _parseRectResponse(WebDriverResponse response) { final rect = parseW3cResponse(response); - return Rectangle( - (rect['x'] as num).toInt(), - (rect['y'] as num).toInt(), - (rect['width'] as num).toInt(), - (rect['height'] as num).toInt(), + return Rect( + left: (rect['x'] as num).toInt(), + top: (rect['y'] as num).toInt(), + width: (rect['width'] as num).toInt(), + height: (rect['height'] as num).toInt(), ); } diff --git a/lib/src/handler/w3c/window.dart b/lib/src/handler/w3c/window.dart index f4802e6..1c9caab 100644 --- a/lib/src/handler/w3c/window.dart +++ b/lib/src/handler/w3c/window.dart @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'dart:math'; - +import '../../common/geometry.dart'; import '../../common/request.dart'; import '../../common/webdriver_handler.dart'; import 'utils.dart'; @@ -48,16 +47,16 @@ class W3cWindowHandler extends WindowHandler { WebDriverRequest buildLocationRequest() => buildRectRequest(); @override - Point parseLocationResponse(WebDriverResponse response) => + Position parseLocationResponse(WebDriverResponse response) => parseRectResponse(response).topLeft; @override WebDriverRequest buildSizeRequest() => buildRectRequest(); @override - Rectangle parseSizeResponse(WebDriverResponse response) { + Size parseSizeResponse(WebDriverResponse response) { final rect = parseRectResponse(response); - return Rectangle(0, 0, rect.width, rect.height); + return rect.size; } @override @@ -65,18 +64,18 @@ class W3cWindowHandler extends WindowHandler { WebDriverRequest.getRequest('window/rect'); @override - Rectangle parseRectResponse(WebDriverResponse response) { + Rect parseRectResponse(WebDriverResponse response) { final rect = parseW3cResponse(response); - return Rectangle( - (rect['x'] as num).toInt(), - (rect['y'] as num).toInt(), - (rect['width'] as num).toInt(), - (rect['height'] as num).toInt(), + return Rect( + left: (rect['x'] as num).toInt(), + top: (rect['y'] as num).toInt(), + width: (rect['width'] as num).toInt(), + height: (rect['height'] as num).toInt(), ); } @override - WebDriverRequest buildSetLocationRequest(Point location) => + WebDriverRequest buildSetLocationRequest(Position location) => WebDriverRequest.postRequest('window/rect', { 'x': location.x, 'y': location.y, @@ -88,7 +87,7 @@ class W3cWindowHandler extends WindowHandler { } @override - WebDriverRequest buildSetSizeRequest(Rectangle size) => + WebDriverRequest buildSetSizeRequest(Size size) => WebDriverRequest.postRequest( 'window/rect', {'width': size.width, 'height': size.height}); @@ -98,7 +97,7 @@ class W3cWindowHandler extends WindowHandler { } @override - WebDriverRequest buildSetRectRequest(Rectangle rect) => + WebDriverRequest buildSetRectRequest(Rect rect) => WebDriverRequest.postRequest('window/rect', { 'x': rect.left, 'y': rect.top, @@ -147,8 +146,11 @@ class W3cWindowHandler extends WindowHandler { }); @override - Rectangle parseInnerSizeResponse(WebDriverResponse response) { + Size parseInnerSizeResponse(WebDriverResponse response) { final size = parseW3cResponse(response); - return Rectangle(0, 0, size['width'] as int, size['height'] as int); + return Size( + width: (size['width'] as num).toInt(), + height: (size['height'] as num).toInt(), + ); } } diff --git a/lib/src/sync/web_element.dart b/lib/src/sync/web_element.dart index d28f57f..58d4e74 100644 --- a/lib/src/sync/web_element.dart +++ b/lib/src/sync/web_element.dart @@ -12,10 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'dart:math' show Point, Rectangle; - import '../../async_core.dart' as async_core; import '../common/by.dart'; +import '../common/geometry.dart'; import '../common/request_client.dart'; import '../common/web_element.dart' as common; import '../common/webdriver_handler.dart'; @@ -144,19 +143,19 @@ class WebElement extends common.WebElement implements SearchContext { /// /// This is assumed to be the upper left corner of the element, but its /// implementation is not well defined in the JSON spec. - Point get location => _client.send( + Position get location => _client.send( _handler.element.buildLocationRequest(id), _handler.element.parseLocationResponse); /// The size of this element. - Rectangle get size => _client.send(_handler.element.buildSizeRequest(id), + Size get size => _client.send(_handler.element.buildSizeRequest(id), _handler.element.parseSizeResponse); /// The bounds of this element. - Rectangle get rect { + Rect get rect { final location = this.location; final size = this.size; - return Rectangle(location.x, location.y, size.width, size.height); + return Rect.from(topLeft: location, size: size); } /// The tag name for this element. diff --git a/lib/src/sync/window.dart b/lib/src/sync/window.dart index 5b4067d..fc86e87 100644 --- a/lib/src/sync/window.dart +++ b/lib/src/sync/window.dart @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'dart:math' show Point, Rectangle; - +import '../common/geometry.dart'; import '../common/request_client.dart'; import '../common/webdriver_handler.dart'; @@ -34,21 +33,19 @@ class Window { } /// The location of the window. - Point get location => _client.send( - _handler.window.buildLocationRequest(), + Position get location => _client.send(_handler.window.buildLocationRequest(), _handler.window.parseLocationResponse); /// The outer size of the window. - Rectangle get size => _client.send( + Size get size => _client.send( _handler.window.buildSizeRequest(), _handler.window.parseSizeResponse); /// The inner size of the window. - Rectangle get innerSize => _client.send( - _handler.window.buildInnerSizeRequest(), + Size get innerSize => _client.send(_handler.window.buildInnerSizeRequest(), _handler.window.parseInnerSizeResponse); /// The location and size of the window. - Rectangle get rect { + Rect get rect { try { return _client.send(_handler.window.buildRectRequest(), _handler.window.parseRectResponse); @@ -57,19 +54,19 @@ class Window { // Delegate to other methods. final location = this.location; final size = this.size; - return Rectangle(location.x, location.y, size.width, size.height); + return Rect.from(topLeft: location, size: size); } } /// Sets the window location. /// /// TODO(jingbian): Remove this, prefer setter. - void setLocation(Point point) { + void setLocation(Position point) { location = point; } /// Sets the window location. - set location(Point value) { + set location(Position value) { _client.send(_handler.window.buildSetLocationRequest(value), _handler.window.parseSetLocationResponse); } @@ -77,18 +74,18 @@ class Window { /// Sets the window size. /// /// TODO(jingbian): Remove this, prefer setter. - void setSize(Rectangle size) { + void setSize(Size size) { this.size = size; } /// Sets the window size. - set size(Rectangle value) { + set size(Size value) { _client.send(_handler.window.buildSetSizeRequest(value), _handler.window.parseSetSizeResponse); } /// The location and size of the window. - set rect(Rectangle value) { + set rect(Rect value) { try { _client.send(_handler.window.buildSetRectRequest(value), _handler.window.parseSetRectResponse); @@ -97,7 +94,7 @@ class Window { // JsonWire cannot implement this API in one call. // Delegate to other methods. location = value.topLeft; - size = Rectangle(0, 0, value.width, value.height); + size = value.size; } } diff --git a/lib/sync_core.dart b/lib/sync_core.dart index 3c9d7f6..5e0a3e9 100644 --- a/lib/sync_core.dart +++ b/lib/sync_core.dart @@ -25,6 +25,7 @@ export 'package:webdriver/src/common/capabilities.dart'; export 'package:webdriver/src/common/command_event.dart'; export 'package:webdriver/src/common/cookie.dart'; export 'package:webdriver/src/common/exception.dart'; +export 'package:webdriver/src/common/geometry.dart'; export 'package:webdriver/src/common/log.dart'; export 'package:webdriver/src/common/mouse.dart'; export 'package:webdriver/src/common/spec.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 776a516..8298fcc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: webdriver -version: 3.1.0 +version: 4.0.0-wip description: >- Provides WebDriver bindings for Dart. Supports WebDriver JSON interface and W3C spec. Requires the use of WebDriver remote server. diff --git a/test/async_window_test.dart b/test/async_window_test.dart index 6ea476e..e1432cb 100644 --- a/test/async_window_test.dart +++ b/test/async_window_test.dart @@ -16,7 +16,6 @@ library webdriver.window_test; import 'dart:async'; -import 'dart:math' show Point, Rectangle; import 'package:test/test.dart'; import 'package:webdriver/async_core.dart'; @@ -34,7 +33,7 @@ void main() { test('size', () async { final window = await driver.window; - const size = Rectangle(0, 0, 600, 400); + const size = Size(width: 600, height: 400); // Firefox may take a bit longer to do the resize. await Future.delayed(const Duration(seconds: 1)); @@ -44,7 +43,7 @@ void main() { test('location', () async { final window = await driver.window; - const position = Point(100, 200); + const position = Position(x: 100, y: 200); await window.setLocation(position); expect(await window.location, position); }); @@ -52,8 +51,8 @@ void main() { // May not work on some OS/browser combinations (notably Mac OS X). test('maximize', () async { final window = await driver.window; - await window.setSize(const Rectangle(0, 0, 300, 200)); - await window.setLocation(const Point(100, 200)); + await window.setSize(const Size(width: 300, height: 200)); + await window.setLocation(const Position(x: 100, y: 200)); await window.maximize(); // maximizing can take some time diff --git a/test/configs/common_config.dart b/test/configs/common_config.dart index dd1778d..21105de 100644 --- a/test/configs/common_config.dart +++ b/test/configs/common_config.dart @@ -14,7 +14,6 @@ import 'dart:async'; import 'dart:io' show HttpServer, InternetAddress, Platform; -import 'dart:math' show Point, Rectangle; import 'package:matcher/matcher.dart' show Matcher, TypeMatcher; import 'package:path/path.dart' as path; @@ -25,8 +24,8 @@ final Uri _defaultFirefoxUri = Uri.parse('http://127.0.0.1:4445/'); const WebDriverSpec defaultSpec = WebDriverSpec.JsonWire; -const Matcher isRectangle = TypeMatcher>(); -const Matcher isPoint = TypeMatcher>(); +const Matcher isRectangle = TypeMatcher(); +const Matcher isPoint = TypeMatcher(); Future createLocalServer() => HttpServer.bind(InternetAddress.anyIPv4, 0); diff --git a/test/sync/window.dart b/test/sync/window.dart index 830613e..84b66b3 100644 --- a/test/sync/window.dart +++ b/test/sync/window.dart @@ -16,7 +16,6 @@ library webdriver.window_test; import 'dart:io'; -import 'dart:math' show Rectangle; import 'package:test/test.dart'; import 'package:webdriver/sync_core.dart'; @@ -33,7 +32,7 @@ void runTests({WebDriverSpec spec = WebDriverSpec.Auto}) { test('size', () { final window = driver.window; - const windowRect = Rectangle(0, 0, 600, 400); + const windowRect = Rect(left: 0, top: 0, width: 600, height: 400); window.rect = windowRect; // Firefox may take a bit longer to do the resize. @@ -51,7 +50,7 @@ void runTests({WebDriverSpec spec = WebDriverSpec.Auto}) { // May not work on some OS/browser combinations (notably Mac OS X). test('maximize', () { final window = driver.window; - const windowRect = Rectangle(100, 200, 300, 300); + const windowRect = Rect(left: 100, top: 200, width: 300, height: 300); window.rect = windowRect; window.maximize(); From f185eebeb46408d74db720939149323e8beb6f2e Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Fri, 14 Feb 2025 13:44:20 -0600 Subject: [PATCH 2/5] Update CI to test with Dart 3.4 --- .github/workflows/ci.yaml | 4 ++-- CHANGELOG.md | 1 + pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bca1119..9ef730c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -40,7 +40,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - sdk: [3.1, stable, dev] + sdk: [3.4, stable, dev] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 @@ -66,7 +66,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - sdk: [3.1, stable, dev] + sdk: [3.4, stable, dev] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 diff --git a/CHANGELOG.md b/CHANGELOG.md index a9d96f5..819c3db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## 4.0.0-wip +* Require Dart 3.4. * Replace usages of `Point` and `Rectangle` from `dart:math` with custom `Location`, `Rect`, and `Size` types. diff --git a/pubspec.yaml b/pubspec.yaml index 8298fcc..ceb545c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: >- repository: https://github.com/google/webdriver.dart environment: - sdk: ^3.1.0 + sdk: ^3.4.0 dependencies: matcher: ^0.12.10 From d14c5906bce3344065c52bc9db0ab2b77b6c1c73 Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Fri, 28 Feb 2025 14:21:30 -0600 Subject: [PATCH 3/5] Resolve left over merge conflict --- lib/src/handler/w3c/window.dart | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/src/handler/w3c/window.dart b/lib/src/handler/w3c/window.dart index f44685b..d04003e 100644 --- a/lib/src/handler/w3c/window.dart +++ b/lib/src/handler/w3c/window.dart @@ -146,17 +146,11 @@ class W3cWindowHandler extends WindowHandler { }); @override -<<<<<<< HEAD Size parseInnerSizeResponse(WebDriverResponse response) { - final size = parseW3cResponse(response); + final size = parseW3cResponse(response) as Map; return Size( width: (size['width'] as num).toInt(), height: (size['height'] as num).toInt(), ); -======= - Rectangle parseInnerSizeResponse(WebDriverResponse response) { - final size = parseW3cResponse(response) as Map; - return Rectangle(0, 0, size['width'] as int, size['height'] as int); ->>>>>>> master } } From fdae17854ca603824355d919a3801f5ea6e59024 Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Thu, 13 Mar 2025 15:52:34 -0500 Subject: [PATCH 4/5] Implement equals and hashCode for new types --- lib/src/common/geometry.dart | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/lib/src/common/geometry.dart b/lib/src/common/geometry.dart index 087df03..1bcb6cd 100644 --- a/lib/src/common/geometry.dart +++ b/lib/src/common/geometry.dart @@ -23,6 +23,17 @@ final class Position { /// Create a location at the specified [x] and [y] coordinates. const Position({required this.x, required this.y}); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Position && x == other.x && y == other.y; + + @override + int get hashCode => Object.hash(x, y); + + @override + String toString() => 'Position(x: $x, y: $y)'; } /// A rectangle, which is a quadrilateral with four right angles, represented on @@ -92,6 +103,22 @@ final class Rect { /// The location of the bottom-left corner of this rectangle. Position get bottomLeft => Position(x: left, y: bottom); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Rect && + _left == other._left && + _top == other._top && + _width == other._width && + _height == other._height; + + @override + int get hashCode => Object.hash(_left, _top, _width, _height); + + @override + String toString() => + 'Rect(left: $_left, top: $_top, width: $_width, height: $_height)'; } /// The width and height dimensions of a 2D object. @@ -111,4 +138,15 @@ final class Size { : assert(width >= 0, height >= 0), width = (width < 0) ? 0 : width, height = (height < 0) ? 0 : height; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Size && width == other.width && height == other.height; + + @override + int get hashCode => Object.hash(width, height); + + @override + String toString() => 'Size(width: $width, height: $height)'; } From d19f8e06681dd14931c2d7d6db75d5b5a09c5120 Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Thu, 13 Mar 2025 15:53:39 -0500 Subject: [PATCH 5/5] Remove unnecessary type tests --- test/async_web_element_test.dart | 4 ---- test/configs/common_config.dart | 4 ---- test/sync/web_element.dart | 6 ------ 3 files changed, 14 deletions(-) diff --git a/test/async_web_element_test.dart b/test/async_web_element_test.dart index d7c3cec..376922b 100644 --- a/test/async_web_element_test.dart +++ b/test/async_web_element_test.dart @@ -97,28 +97,24 @@ void main() { test('location -- table', () async { final location = await table.location; - expect(location, config.isPoint); expect(location.x, isNonNegative); expect(location.y, isNonNegative); }); test('location -- invisible', () async { final location = await invisible.location; - expect(location, config.isPoint); expect(location.x, 0); expect(location.y, 0); }); test('size -- table', () async { final size = await table.size; - expect(size, config.isRectangle); expect(size.width, isNonNegative); expect(size.height, isNonNegative); }); test('size -- invisible', () async { final size = await invisible.size; - expect(size, config.isRectangle); expect(size.width, isNonNegative); expect(size.height, isNonNegative); }); diff --git a/test/configs/common_config.dart b/test/configs/common_config.dart index c92ba1a..1e5afb7 100644 --- a/test/configs/common_config.dart +++ b/test/configs/common_config.dart @@ -15,7 +15,6 @@ import 'dart:async'; import 'dart:io' show HttpServer, InternetAddress, Platform; -import 'package:matcher/matcher.dart' show Matcher, TypeMatcher; import 'package:path/path.dart' as path; import 'package:webdriver/async_core.dart'; @@ -24,9 +23,6 @@ final Uri _defaultFirefoxUri = Uri.parse('http://127.0.0.1:4445/'); const WebDriverSpec defaultSpec = WebDriverSpec.JsonWire; -const Matcher isRectangle = TypeMatcher(); -const Matcher isPoint = TypeMatcher(); - Future createLocalServer() => HttpServer.bind(InternetAddress.anyIPv4, 0); diff --git a/test/sync/web_element.dart b/test/sync/web_element.dart index 0243840..633b597 100644 --- a/test/sync/web_element.dart +++ b/test/sync/web_element.dart @@ -96,7 +96,6 @@ void runTests({WebDriverSpec spec = WebDriverSpec.Auto}) { test('rect -- table', () { final rect = table.rect; - expect(rect, config.isRectangle); expect(rect.left, isNonNegative); expect(rect.top, isNonNegative); expect(rect.width, isNonNegative); @@ -105,7 +104,6 @@ void runTests({WebDriverSpec spec = WebDriverSpec.Auto}) { test('rect -- invisible', () { final rect = invisible.rect; - expect(rect, config.isRectangle); expect(rect.left, 0); expect(rect.top, 0); expect(rect.width, isNonNegative); @@ -114,28 +112,24 @@ void runTests({WebDriverSpec spec = WebDriverSpec.Auto}) { test('location -- table', () { final location = table.location; - expect(location, config.isPoint); expect(location.x, isNonNegative); expect(location.y, isNonNegative); }); test('location -- invisible', () { final location = invisible.location; - expect(location, config.isPoint); expect(location.x, 0); expect(location.y, 0); }); test('size -- table', () { final size = table.size; - expect(size, config.isRectangle); expect(size.width, isNonNegative); expect(size.height, isNonNegative); }); test('size -- invisible', () { final size = invisible.size; - expect(size, config.isRectangle); expect(size.width, isNonNegative); expect(size.height, isNonNegative); });