protected FxRobot clickOn(Node node) {
   moveTo(node);
   FxRobot fxRobot;
   try {
     fxRobot = robot.moveTo(node).clickOn(node);
   } catch (BoundsLocatorException e) {
     fxRobot = robot.moveTo(node).clickOn(node);
   }
   baseFXRobot.waitForIdle();
   return fxRobot;
 }
 protected FxRobot moveTo(Node node) {
   baseFXRobot.waitForIdle();
   double x;
   double y;
   do {
     try {
       Thread.sleep(100);
     } catch (InterruptedException ignored) {
     }
     Point2D position = robot.point(node).getPosition();
     x = position.getX();
     y = position.getY();
     robot.moveTo(node);
     try {
       Thread.sleep(100);
     } catch (InterruptedException ignored) {
     }
     baseFXRobot.waitForIdle();
   } while (hasMoved(node, x, y));
   return robot.moveTo(node);
 }
 protected FxRobot clickOn(String query) {
   try {
     fakeClick(query);
     return robot;
   } catch (Exception ignored) {
     System.err.println("failed to fake click on '" + query + "', falling back to real click");
   }
   for (int i = 0; i < 10; i++) {
     try {
       baseFXRobot.waitForIdle();
       Node node = waitForNode(query);
       moveTo(node);
       return clickOn(waitForNode(query));
     } catch (NullPointerException retry) {
     }
   }
   throw new IllegalStateException(
       "failed to click on " + query + ", it vanished 10 times in a row");
 }
  protected void fakeClick(String query) {
    baseFXRobot.waitForIdle();
    Node node = waitForNode(query);
    Point2D pos = robot.point(node).getPosition();
    baseFXRobot.mouseMove((int) pos.getX(), (int) pos.getY());
    Point2D screenPos = node.localToScreen(pos.getX(), pos.getY());
    Point2D scenePos = node.localToScene(pos.getX(), pos.getY());

    if (node instanceof Region && !(node instanceof Control)) {
      throw new IllegalArgumentException("cannot fake clicks on random regions");
    }

    runLaterAndWait(() -> waitForNode(query).requestFocus());
    if (focusSufficesClick(node)) {
      return;
    }

    MouseEvent event =
        new MouseEvent(
            MouseEvent.MOUSE_CLICKED,
            pos.getX(),
            pos.getY(),
            screenPos.getX(),
            screenPos.getY(),
            MouseButton.PRIMARY,
            1,
            false,
            false,
            false,
            false,
            false,
            false,
            false,
            true,
            false,
            false,
            new PickResult(node, scenePos.getX(), scenePos.getY()));

    EventHandler<? super MouseEvent> pressedHandler = node.getOnMousePressed();
    EventHandler<? super MouseEvent> clickedHandler = node.getOnMouseClicked();
    EventHandler<? super MouseEvent> releasedHandler = node.getOnMouseReleased();

    Platform.runLater(
        () -> {
          if (pressedHandler != null) {
            pressedHandler.handle(event);
          }
          if (clickedHandler != null) {
            clickedHandler.handle(event);
          }
          if (releasedHandler != null) {
            releasedHandler.handle(event);
          }
          if (pressedHandler == null && clickedHandler == null && releasedHandler == null) {
            node.buildEventDispatchChain(new EventDispatchChainImpl()).dispatchEvent(event);
          }
        });

    if (fireSufficesClick(node)) {
      Platform.runLater(((ButtonBase) node)::fire);
      return;
    }
  }
 protected FxRobot rightClickOn(String query) {
   baseFXRobot.waitForIdle();
   Node node = waitForNode(query);
   moveTo(node);
   return robot.rightClickOn(node);
 }