com.epam.healenium.service.HealingService Maven / Gradle / Ivy
The newest version!
package com.epam.healenium.service;
import com.epam.healenium.SelectorComponent;
import com.epam.healenium.model.Context;
import com.epam.healenium.model.HealedElement;
import com.epam.healenium.model.HealingCandidateDto;
import com.epam.healenium.model.HealingResult;
import com.epam.healenium.treecomparing.HeuristicNodeDistance;
import com.epam.healenium.treecomparing.LCSPathDistance;
import com.epam.healenium.treecomparing.Node;
import com.epam.healenium.treecomparing.Path;
import com.epam.healenium.treecomparing.PathFinder;
import com.epam.healenium.treecomparing.Scored;
import com.typesafe.config.Config;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebElement;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j(topic = "healenium")
public class HealingService {
private final int recoveryTries;
private final double scoreCap;
private final List> selectorDetailLevels;
protected final WebDriver driver;
private final static List> TEMP = new ArrayList>() {{
add(EnumSet.of(SelectorComponent.TAG, SelectorComponent.ID));
add(EnumSet.of(SelectorComponent.TAG, SelectorComponent.CLASS));
add(EnumSet.of(SelectorComponent.PARENT, SelectorComponent.TAG, SelectorComponent.ID, SelectorComponent.CLASS));
add(EnumSet.of(SelectorComponent.PARENT, SelectorComponent.TAG, SelectorComponent.CLASS, SelectorComponent.POSITION));
add(EnumSet.of(SelectorComponent.PARENT, SelectorComponent.TAG, SelectorComponent.ID, SelectorComponent.CLASS, SelectorComponent.ATTRIBUTES));
add(EnumSet.of(SelectorComponent.PATH));
}};
public HealingService(Config finalizedConfig, WebDriver driver) {
this.recoveryTries = finalizedConfig.getInt("recovery-tries");
this.scoreCap = finalizedConfig.getDouble("score-cap");
this.selectorDetailLevels = Collections.unmodifiableList(TEMP);
this.driver = driver;
}
/**
* @param destination the new HTML page source on which we should search for the element
* @param paths source path to locator
* @param context context data for healing
*/
public void findNewLocations(List paths, Node destination, Context context) {
PathFinder pathFinder = new PathFinder(new LCSPathDistance(), new HeuristicNodeDistance());
AbstractMap.SimpleImmutableEntry>>> scoresToNodes =
pathFinder.findScoresToNodes(new Path(paths.toArray(new Node[0])), destination);
List> scoreds = pathFinder.getSortedNodes(scoresToNodes.getValue(), recoveryTries, scoreCap);
List healedElements = scoreds.stream()
.map(node -> toLocator(node, context))
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (!healedElements.isEmpty()) {
HealingResult healingResult = new HealingResult()
.setPaths(paths)
.setTargetNodes(scoreds)
.setAllHealingCandidates(getAllHealingCandidates(scoresToNodes))
.setHealedElements(healedElements);
context.getHealingResults().add(healingResult);
}
}
/**
* @param node convert source node to locator
* @param context chain context
* @return healedElement
*/
protected HealedElement toLocator(Scored node, Context context) {
for (Set detailLevel : selectorDetailLevels) {
By locator = construct(node.getValue(), detailLevel);
List elements = driver.findElements(locator);
if (elements.size() == 1 && !context.getElementIds().contains(((RemoteWebElement) elements.get(0)).getId())) {
Scored byScored = new Scored<>(node.getScore(), locator);
context.getElementIds().add(((RemoteWebElement) elements.get(0)).getId());
HealedElement healedElement = new HealedElement();
healedElement.setElement(elements.get(0)).setScored(byScored);
return healedElement;
}
}
return null;
}
/**
* @param curPathHeightToScores - all PathToNode candidate collection
* @return list healingCandidateDto for metrics
*/
private List getAllHealingCandidates(AbstractMap.SimpleImmutableEntry>>> curPathHeightToScores) {
Integer curPathHeight = curPathHeightToScores.getKey();
Map>> scoresToNodes = curPathHeightToScores.getValue();
return scoresToNodes.keySet().stream()
.sorted(Comparator.reverseOrder())
.flatMap(score -> scoresToNodes.get(score).stream()
.map(it -> new HealingCandidateDto(score, it.getValue(), curPathHeight, it.getKey())))
.limit(10)
.collect(Collectors.toList());
}
/**
* construct cssSelector by Node
*
* @param node - target node
* @param detailLevel - final detail Level collection
* @return target user selector
*/
protected By construct(Node node, Set detailLevel) {
return By.cssSelector(detailLevel.stream()
.map(component -> component.createComponent(node))
.collect(Collectors.joining()));
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy