com.xlrit.gears.runner.runnertarget.selenide.AbstractSelenideFacade Maven / Gradle / Ivy
The newest version!
package com.xlrit.gears.runner.runnertarget.selenide;
import java.io.File;
import java.time.Duration;
import com.codeborne.selenide.Configuration;
import com.codeborne.selenide.Driver;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.WebDriverRunner;
import com.fasterxml.jackson.databind.JsonNode;
import com.xlrit.gears.runner.graphql.GraphQLClient;
import com.xlrit.gears.runner.graphql.Operation;
import com.xlrit.gears.runner.driver.RunConfig;
import com.xlrit.gears.runner.runnertarget.RunnerContext;
import com.xlrit.gears.runner.runnertarget.TaskExpression;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.codeborne.selenide.Condition.*;
import static com.codeborne.selenide.Selectors.*;
import static com.codeborne.selenide.Selenide.*;
import static com.xlrit.gears.runner.utils.SelenideUtils.*;
public abstract class AbstractSelenideFacade implements SelenideFacade {
private static final Logger LOG = LoggerFactory.getLogger(AbstractSelenideFacade.class);
protected final RunnerContext context;
protected final GraphQLClient client;
private final FormSubmitter formSubmitter = new FormSubmitter(this);
private final int waitMillis;
private final int timeoutMillis;
private final boolean submitScreenshots;
private ProcessIcons processIcons = ProcessIcons.UNKNOWN;
public AbstractSelenideFacade(RunConfig config, RunnerContext context, GraphQLClient client) {
this.context = context;
this.waitMillis = config.waitMillis;
this.timeoutMillis = config.timeoutMillis;
this.submitScreenshots = config.submitScreenshots;
this.client = client;
}
@Override
public void login(String username) {
open("/#/login");
type(username, $(byName("username")));
type(username, $(byName("password")));
pressButton($("#login-submit-button"));
$(byName("username")).should(disappear);
$(byName("password")).should(disappear);
}
@Override
public void logout() {
LOG.debug("Logging out");
pressButton($("#account-button"));
// TODO: this should have a sensible id
pressButton($(byAttribute("data-testid", "LogoutIcon")));
}
@Override
public void startProcess(String key, JsonNode values) {
open("/#/gears/processes/start");
if (processIcons == ProcessIcons.UNKNOWN) detectProcessIcons();
SelenideElement processButton = switch (processIcons) {
case YES -> $(byAttribute("gears-id", key));
case NO -> $(cssId(key));
case UNKNOWN -> throw new IllegalStateException("Unknown process icon");
};
pressButton(processButton);
if (values != null) submitForm(values);
}
@Override
public void claimTask(String key, TaskExpression taskExpression) {
waitFor(waitMillis);
if (urlMatch(".*/#/gears/tasks/.*")) return;
open("/#/gears/tasks/group");
pressButton($("#row_0"));
}
@Override
public void submitTask(String processKey, TaskExpression taskExpression, JsonNode values) {
waitFor(waitMillis);
if (!urlMatch(".*/#/gears/tasks/.*")) {
open("/#/gears/tasks/assigned");
$("#row_0").click();
}
submitForm(values);
}
@Override
public String valueToLabel(String value, String fieldId) {
String choicesId = getFormId();
JsonNode result = client.invoke(Operation.choiceByValue(choicesId, fieldId, value, urlMatch(".*/#/gears/tasks/.*")));
if (result.get("choice").isNull()) {
throw new RuntimeException(String.format("Value %s not found for input %s", value, fieldId));
}
return result.get("choice").get("label").asText();
}
private void submitForm(JsonNode input) {
String url = WebDriverRunner.url();
LOG.debug(String.format("Entering input from %s", input));
formSubmitter.enterFields(input);
if (submitScreenshots) fullsizeScreenshot();
formSubmitter.submit();
new WebDriverWait(WebDriverRunner.getWebDriver(), Duration.ofMillis(timeoutMillis))
.until(ExpectedConditions.not(ExpectedConditions.urlToBe(url)));
new WebDriverWait(WebDriverRunner.getWebDriver(), Duration.ofMillis(timeoutMillis))
.until(ExpectedConditions.not(ExpectedConditions.urlMatches(".*/#/gears/status/.*")));
waitFor(waitMillis);
}
protected void waitFor(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
LOG.error("Wait was interrupted: {}", e.getMessage());
throw new RuntimeException(e);
}
}
private void fullsizeScreenshot() {
String title = String.format("%s-%03d", context.scenario, context.lineNumber);
File screenshotFile = new File(String.format("%s/%s.png", Configuration.reportsFolder, title));
if (screenshotFile.exists() && !screenshotFile.delete()) {
throw new RuntimeException("Failed to delete already existing screenshot file: " + screenshotFile.getAbsolutePath());
}
Driver driver = webdriver().driver();
long width = driver.executeJavaScript("return window.outerWidth");
long height = driver.executeJavaScript(JS_GET_HEIGHT);
driver.getWebDriver().manage().window().setSize(new Dimension((int)width, (int)height + 200));
String fileName = screenshot(title);
LOG.debug("Saved before-submit screenshot to {}", fileName);
var size = Configuration.browserSize.split("x");
int orgWidth = Integer.parseInt(size[0]);
int orgHeight = Integer.parseInt(size[1]);
driver.getWebDriver().manage().window().setSize(new Dimension(orgWidth, orgHeight));
}
private void detectProcessIcons() {
waitFor(waitMillis);
SelenideElement tilesButton = $(byValue("table"));
if (tilesButton.exists()) {
processIcons = ProcessIcons.YES;
if (tilesButton.has(attribute("aria-pressed", "false"))) pressButton(tilesButton);
SelenideElement groupButton = $(byValue("none")).should(exist);
if (groupButton.has(attribute("aria-pressed", "false"))) pressButton(groupButton);
} else {
processIcons = ProcessIcons.NO;
}
}
private enum ProcessIcons {
UNKNOWN,
YES,
NO
}
}