+ * Displaying a welcome message is the smaller part of that job. The main reason is that the IDE needs a project context + * to work with and that context does not exist with a fresh installation. That is also why the welcome screen contains + * the means of opening, importing or creating projects in a sub dialog. + *
+ */ +@DefaultXpath(by = "FlatWelcomeFrame type", xpath = "//div[@class='FlatWelcomeFrame']") +@FixtureName(name = "Welcome Frame") +public class WelcomeFrameFixture extends CommonContainerFixture { + public WelcomeFrameFixture(@NotNull RemoteRobot remoteRobot, @NotNull RemoteComponent remoteComponent) { + super(remoteRobot, remoteComponent); + } + + public JButtonFixture createNewProjectLink() { + // The button style changes from an icon to a text button if a project already exists. To make things worse, + // In case of the icon the button is followed by a label that has the same text on it as the link-style button. + // We need a bit of XPath complexity, to pick either of the clickable items. + return find(JButtonFixture.class, byXpath("(//div[@defaulticon='createNewProjectTab.svg']" + + "|//div[@visible_text='New Project'])[1]")); + } +} \ No newline at end of file diff --git a/src/test/java/org/itallcode/openfasttrace/intelijplugin/wait/RobotServerReadyWaitStrategy.java b/src/test/java/org/itallcode/openfasttrace/intelijplugin/wait/RobotServerReadyWaitStrategy.java new file mode 100644 index 0000000..112078a --- /dev/null +++ b/src/test/java/org/itallcode/openfasttrace/intelijplugin/wait/RobotServerReadyWaitStrategy.java @@ -0,0 +1,70 @@ +package org.itallcode.openfasttrace.intelijplugin.wait; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; +import java.time.Duration; +import java.time.Instant; +import java.util.concurrent.TimeoutException; + +import static org.itallcode.openfasttrace.intelijplugin.remoterobot.RemoteRobotProperties.*; + +/** + * This strategy waits for the Remote Robot server to become available. + */ +public class RobotServerReadyWaitStrategy { + private static final long RETRY_DELAY_MILLIS = 1000; + private final Duration timeout; + + /** + * Wait for the Remote Robot server to become available. + * + * @param timeout maximum time to wait for the server to become available + * @throws TimeoutException if the given timeout is reached without being able to connect to the robot server + */ + public static void wait(final Duration timeout) throws TimeoutException { + final RobotServerReadyWaitStrategy strategy = new RobotServerReadyWaitStrategy(timeout); + strategy.waitUntilReady(); + } + + private RobotServerReadyWaitStrategy(final Duration timeout) { + this.timeout = timeout; + } + + private void waitUntilReady() throws TimeoutException { + final OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(timeout) + .retryOnConnectionFailure(true) + .build(); + poll(client, ROBOT_BASE_URL); + client.dispatcher().executorService().shutdown(); + } + + private void poll(final OkHttpClient client, final String url) throws TimeoutException { + final Request request = new Request.Builder().url(url).build(); + final Instant until = Instant.now().plus(this.timeout); + do { + try (final Response response = client.newCall(request).execute()) { + if (response.isSuccessful()) { + return; + } + } catch (IOException exception) { + // keep trying. + try { + delayPollingRetry(); + } catch (InterruptedException interruptedException) { + Thread.currentThread().interrupt(); + throw new RuntimeException(interruptedException); + } + } + } while (Instant.now().isBefore(until)); + throw new TimeoutException("Timed out waiting for Remote Robot server to become available"); + } + + @SuppressWarnings("java:S2925") + private static void delayPollingRetry() throws InterruptedException { + Thread.sleep(RETRY_DELAY_MILLIS); + } +}