|
23 | 23 | import org.openqa.selenium.By.Remotable; |
24 | 24 | import org.openqa.selenium.SearchContext; |
25 | 25 | import org.openqa.selenium.WebElement; |
| 26 | +import org.openqa.selenium.json.Json; |
26 | 27 |
|
27 | 28 | import java.io.Serializable; |
| 29 | +import java.util.HashMap; |
28 | 30 | import java.util.List; |
| 31 | +import java.util.Map; |
29 | 32 |
|
30 | 33 | import static com.google.common.base.Strings.isNullOrEmpty; |
31 | 34 |
|
@@ -250,6 +253,57 @@ public static FlutterBy flutterSemanticsLabel(final String semanticsLabel) { |
250 | 253 | return new ByFlutterSemanticsLabel(semanticsLabel); |
251 | 254 | } |
252 | 255 |
|
| 256 | + /** |
| 257 | + * This locator strategy is available in FlutterIntegration Driver mode since version 1.4.0. |
| 258 | + * |
| 259 | + * @param of represents the parent widget locator |
| 260 | + * @param matching represents the descendant widget locator to match |
| 261 | + * @param matchRoot determines whether to include the root widget in the search |
| 262 | + * @param skipOffstage determines whether to skip offstage widgets |
| 263 | + * @return an instance of {@link AppiumBy.ByFlutterDescendant} |
| 264 | + */ |
| 265 | + public static FlutterBy flutterDescendant( |
| 266 | + final FlutterBy of, |
| 267 | + final FlutterBy matching, |
| 268 | + boolean matchRoot, |
| 269 | + boolean skipOffstage) { |
| 270 | + return new ByFlutterDescendant(of, matching, matchRoot, skipOffstage); |
| 271 | + } |
| 272 | + |
| 273 | + /** |
| 274 | + * This locator strategy is available in FlutterIntegration Driver mode since version 1.4.0. |
| 275 | + * |
| 276 | + * @param of represents the parent widget locator |
| 277 | + * @param matching represents the descendant widget locator to match |
| 278 | + * @return an instance of {@link AppiumBy.ByFlutterDescendant} |
| 279 | + */ |
| 280 | + public static FlutterBy flutterDescendant(final FlutterBy of, final FlutterBy matching) { |
| 281 | + return flutterDescendant(of, matching, false, true); |
| 282 | + } |
| 283 | + |
| 284 | + /** |
| 285 | + * This locator strategy is available in FlutterIntegration Driver mode since version 1.4.0. |
| 286 | + * |
| 287 | + * @param of represents the child widget locator |
| 288 | + * @param matching represents the ancestor widget locator to match |
| 289 | + * @param matchRoot determines whether to include the root widget in the search |
| 290 | + * @return an instance of {@link AppiumBy.ByFlutterAncestor} |
| 291 | + */ |
| 292 | + public static FlutterBy flutterAncestor(final FlutterBy of, final FlutterBy matching, boolean matchRoot) { |
| 293 | + return new ByFlutterAncestor(of, matching, matchRoot); |
| 294 | + } |
| 295 | + |
| 296 | + /** |
| 297 | + * This locator strategy is available in FlutterIntegration Driver mode since version 1.4.0. |
| 298 | + * |
| 299 | + * @param of represents the child widget locator |
| 300 | + * @param matching represents the ancestor widget locator to match |
| 301 | + * @return an instance of {@link AppiumBy.ByFlutterAncestor} |
| 302 | + */ |
| 303 | + public static FlutterBy flutterAncestor(final FlutterBy of, final FlutterBy matching) { |
| 304 | + return flutterAncestor(of, matching, false); |
| 305 | + } |
| 306 | + |
253 | 307 | public static class ByAccessibilityId extends AppiumBy implements Serializable { |
254 | 308 | public ByAccessibilityId(String accessibilityId) { |
255 | 309 | super("accessibility id", accessibilityId, "accessibilityId"); |
@@ -328,6 +382,32 @@ protected FlutterBy(String selector, String locatorString, String locatorName) { |
328 | 382 | } |
329 | 383 | } |
330 | 384 |
|
| 385 | + public abstract static class FlutterByHierarchy extends FlutterBy { |
| 386 | + private static final Json JSON = new Json(); |
| 387 | + |
| 388 | + protected FlutterByHierarchy( |
| 389 | + String selector, |
| 390 | + FlutterBy of, |
| 391 | + FlutterBy matching, |
| 392 | + Map<String, Object> properties, |
| 393 | + String locatorName) { |
| 394 | + super(selector, formatLocator(of, matching, properties), locatorName); |
| 395 | + } |
| 396 | + |
| 397 | + static Map<String, Object> parseFlutterLocator(FlutterBy by) { |
| 398 | + Parameters params = by.getRemoteParameters(); |
| 399 | + return Map.of("using", params.using(), "value", params.value()); |
| 400 | + } |
| 401 | + |
| 402 | + static String formatLocator(FlutterBy of, FlutterBy matching, Map<String, Object> properties) { |
| 403 | + Map<String, Object> locator = new HashMap<>(); |
| 404 | + locator.put("of", parseFlutterLocator(of)); |
| 405 | + locator.put("matching", parseFlutterLocator(matching)); |
| 406 | + locator.put("parameters", properties); |
| 407 | + return JSON.toJson(locator); |
| 408 | + } |
| 409 | + } |
| 410 | + |
331 | 411 | public static class ByFlutterType extends FlutterBy implements Serializable { |
332 | 412 | protected ByFlutterType(String locatorString) { |
333 | 413 | super("-flutter type", locatorString, "flutterType"); |
@@ -358,4 +438,23 @@ protected ByFlutterTextContaining(String locatorString) { |
358 | 438 | } |
359 | 439 | } |
360 | 440 |
|
| 441 | + public static class ByFlutterDescendant extends FlutterByHierarchy implements Serializable { |
| 442 | + protected ByFlutterDescendant(FlutterBy of, FlutterBy matching, boolean matchRoot, boolean skipOffstage) { |
| 443 | + super( |
| 444 | + "-flutter descendant", |
| 445 | + of, |
| 446 | + matching, |
| 447 | + Map.of("matchRoot", matchRoot, "skipOffstage", skipOffstage), "flutterDescendant"); |
| 448 | + } |
| 449 | + } |
| 450 | + |
| 451 | + public static class ByFlutterAncestor extends FlutterByHierarchy implements Serializable { |
| 452 | + protected ByFlutterAncestor(FlutterBy of, FlutterBy matching, boolean matchRoot) { |
| 453 | + super( |
| 454 | + "-flutter ancestor", |
| 455 | + of, |
| 456 | + matching, |
| 457 | + Map.of("matchRoot", matchRoot), "flutterAncestor"); |
| 458 | + } |
| 459 | + } |
361 | 460 | } |
0 commit comments