All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.xlrit.gears.runner.runnertarget.SelenideRunnerTarget Maven / Gradle / Ivy
package com.xlrit.gears.runner.runnertarget;
import com.codeborne.selenide.Configuration;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.WebDriverRunner;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.xlrit.gears.runner.run.Config;
import com.xlrit.gears.runner.graphql.GraphQLClient;
import com.xlrit.gears.runner.graphql.Operation;
import com.xlrit.gears.runner.utils.GraphQLUtils;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
import java.util.Objects;
import java.util.Optional;
import java.util.logging.Logger;
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 class SelenideRunnerTarget implements RunnerTarget {
private final Logger logger = Logger.getLogger(SelenideRunnerTarget.class.getName());
private final GraphQLClient client;
private final int waitMillis;
private boolean loggedIn = false;
private String currentUser = "";
public SelenideRunnerTarget(Config config, boolean constructorLogin) {
this.client = new GraphQLClient(config.endpoint, new ObjectMapper());
this.waitMillis = config.waitMillis;
// setup Selenide configuration
Configuration.timeout = config.timeoutMillis;
Configuration.baseUrl = "http://localhost:8080";
Configuration.reportsFolder = "target/reports";
Configuration.headless = config.headless;
// TODO: is there a way to get authorization token when logging in through web interface?
if (constructorLogin) graphqlClientLogin();
}
private void graphqlClientLogin() {
JsonNode login = client.invoke(Operation.login("demo", "demo"));
client.setToken(login.get("login").asText());
loggedIn = true;
}
@Override
public void loadData(String srcDir, String pattern) {
JsonNode jsonResponse = client.invoke(Operation.loadData(srcDir, pattern));
logger.info(String.format("Load data: %s", jsonResponse));
if (!loggedIn) graphqlClientLogin();
}
@Override
public void dataAssertion(String key, String grql) {}
@Override
public void processCompleted(String processKey) {}
@Override
public void setDateTime(String value) {}
@Override
public void scenarioStart(String scenario) {}
@Override
public void scenarioFinish() {}
@Override
public void finish() {}
@Override
public void login(String identifier) {
if (currentUser.equals(identifier)) return;
if (!currentUser.equals("")) logout();
logger.info(String.format("Logging in as %s", identifier));
open("/#/login");
$(byName("username")).setValue(identifier);
$(byName("password")).setValue(identifier);
$("#login-submit-button").click();
$(byName("username")).should(disappear);
$(byName("password")).should(disappear);
currentUser = identifier;
}
private void logout() {
logger.info("Logging out");
$("#account-button").click();
$(byTextCaseInsensitive("logout")).click();
}
@Override
public void startProcess(String key, JsonNode values) {
logger.info(String.format("Starting process %s%n", cssId(key)));
open("/#/gears/processes/start");
$(cssId(key)).click();
if (values != null) submitFormAndWait(values);
}
@Override
public void claimTask(String key, TaskExpression taskExpression) {
// TODO: use parameters
waitFor(waitMillis);
if (urlMatch(".*/#/gears/tasks/.*")) return;
open("/#/gears/tasks/group");
$("#row_0").click();
}
private void waitFor(int milliseconds) {
try {
new WebDriverWait(WebDriverRunner.getWebDriver(), Duration.ofMillis(milliseconds)).until(arg -> false);
} catch (TimeoutException ignored) {
}
}
@Override
public void basedOn(String value) {
$(byText(value)).should(appear);
}
@Override
public void submitTask(String processKey, TaskExpression taskExpression, JsonNode values) {
waitFor(waitMillis);
if (!urlMatch(".*/#/gears/tasks/.*")) {
open("/#/gears/tasks/group");
$("#row_0").click();
}
submitFormAndWait(values);
}
private void submitFormAndWait(JsonNode input) {
String url = WebDriverRunner.url();
submitForm(input);
new WebDriverWait(WebDriverRunner.getWebDriver(), Duration.ofMillis(1000))
.until(ExpectedConditions.not(ExpectedConditions.urlToBe(url)));
waitFor(waitMillis);
}
private void submitForm(JsonNode input) {
logger.info(String.format("Entering input from %s", input));
input.fields().forEachRemaining(kvp -> {
logger.info(String.format("For %s providing value %s", kvp.getKey(), kvp.getValue()));
provideInput(kvp.getKey(), kvp.getValue());
});
$("#submit-form-button").click();
}
private void provideInput(String id, JsonNode value) {
if (value.getNodeType() == JsonNodeType.ARRAY) {
if (isMultipleTable($(cssId(id)).should(exist))) {
provideMultipleTableInput(id, (ArrayNode)value);
} else {
provideMultipleInput(id, (ArrayNode)value);
}
} else {
provideSingleInput(id, new InputValue(value));
}
}
private void provideMultipleTableInput(String id, ArrayNode values) {
int index = 0;
SelenideElement table = $(cssId(id));
for (var ite = values.elements(); ite.hasNext();) {
if (!hasRow(table, index)) {
table.find(String.format("#row-%d-add-button", index - 1)).click();
}
JsonNode currentRow = ite.next();
int finalIndex = index;
currentRow.fields().forEachRemaining(kvp -> {
String inputId = String.format("%s[%d].%s", id, finalIndex, kvp.getKey());
provideInput(inputId, kvp.getValue());
});
index++;
}
}
private void provideSingleInput(String id, InputValue value) {
SelenideElement element = $(cssId(id));
if (value.text.equals(element.getAttribute("value")) || value.text.equals("")) return;
if (isTextInput(element)) {
element.setValue(value.text);
} else if (isCombobox(element)) {
String label = value.isLabel ? value.text : valueToLabel(value.text, id);
if (label.equals(element.getAttribute("value"))) return;
element.setValue(label);
$$(withTextCaseInsensitive(label)).findBy(attribute("role", "option")).click();
} else if (isDatePicker(element)) {
element.setValue(dateTimeToInput(value.text, Objects.requireNonNull(element.getAttribute("placeholder"))));
} else if (isTextArea(element)) {
element.sendKeys(value.text);
} else if (isFileInput(element)) {
SelenideElement fileInput = element.find("[type='file']");
fileInput.uploadFromClasspath("poetie.jpg");
} else {
provideRadioInput(element, value);
}
}
private void provideMultipleInput(String id, ArrayNode values) {
SelenideElement input = $(cssId(id));
if (isCombobox(input)) {
for (var ite = values.elements(); ite.hasNext();) {
InputValue value = new InputValue(ite.next());
String label = value.isLabel ? value.text : valueToLabel(value.text, id);
if ($(withTextCaseInsensitive(label)).exists()) continue; // don't need to do anything if input is pre-filled
input.setValue(label);
$$(withTextCaseInsensitive(label)).findBy(attribute("role", "option")).click();
$(withTextCaseInsensitive(label)).should(exist);
}
input.pressEscape();
} else {
for (var ite = values.elements(); ite.hasNext();) {
provideRadioInput(input, new InputValue(ite.next()));
}
}
}
private void provideRadioInput(SelenideElement input, InputValue value) {
WebElement button = value.isLabel ?
input.findElement(withTextCaseInsensitive(value.text)) :
input.findElement(byAttribute("value", value.text));
if (button.getDomAttribute("checked") == null) button.click();
}
private 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") == null) {
throw new RuntimeException(String.format("Value %s not found for input %s", value, fieldId));
}
return result.get("choice").get("label").asText();
}
private static class InputValue {
public final String text;
public final boolean isLabel;
public InputValue(JsonNode value) {
if (value.getNodeType() == JsonNodeType.OBJECT) {
JsonNode labelTry = value.get("label");
if (labelTry != null) {
text = labelTry.asText();
isLabel = true;
} else {
JsonNode valueTry = value.get("value");
if (valueTry != null) {
text = valueTry.asText();
isLabel = false;
} else {
throw new RuntimeException(String.format("Input is neither a label nor a value: %s", value));
}
}
} else {
text = value.asText();
isLabel = false;
}
}
}
}