Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 15 additions & 20 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.epam.healenium</groupId>
<artifactId>healenium-web</artifactId>
<version>3.5.6</version>
<version>3.5.7</version>
<packaging>jar</packaging>
<name>healenium-web</name>
<description>healenium web client</description>
Expand All @@ -36,13 +36,10 @@
</scm>

<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
<id>central</id>
<name>Central Repository</name>
<url>https://central.sonatype.com</url>
</repository>
</distributionManagement>

Expand All @@ -54,7 +51,7 @@
<treecomparing.version>0.4.14</treecomparing.version>
<selenium.version>4.25.0</selenium.version>
<jacksondatabind.version>2.15.2</jacksondatabind.version>
<commonslang3.version>3.17.0</commonslang3.version>
<commonslang3.version>3.18.0</commonslang3.version>
<commonscodec.version>1.15</commonscodec.version>
<annotations.version>23.0.0</annotations.version>
<mapstruct.version>1.4.2.Final</mapstruct.version>
Expand Down Expand Up @@ -84,7 +81,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<version>3.0.1</version>
<configuration>
<passphrase>${gpg.passphrase}</passphrase>
<gpgArguments>
Expand All @@ -101,6 +98,10 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
Expand Down Expand Up @@ -150,19 +151,13 @@
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.13</version>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.8.0</version>
<extensions>true</extensions>
<executions>
<execution>
<phase>deploy</phase>
</execution>
</executions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
</configuration>
</plugin>
<plugin>
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/epam/healenium/driver/InitDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public static SelfHealingDriver getDriver(){
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
options.addArguments("--user-data-dir=/tmp/unique-chrome-profile-" + System.currentTimeMillis());
WebDriver delegate = new ChromeDriver(options);
return SelfHealingDriver.createTestDriver(delegate);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,29 @@
import com.epam.healenium.treecomparing.Node;
import org.apache.commons.lang3.StringUtils;

import java.util.Optional;
import java.util.regex.Pattern;

public class IdElementCreator implements ElementCreator {

private static final Pattern SAFE_HASH_ID = Pattern.compile("^-?[A-Za-z_][A-Za-z0-9_-]*$");

@Override
public String create(Node node) {
return Optional.ofNullable(node.getId())
.map(String::trim)
.filter(StringUtils::isNotBlank)
.map("#"::concat)
.orElse("");
String id = StringUtils.trimToNull(node.getId());
if (id == null) {
return "";
}
if (isHashSafe(id)) {
return "#" + id;
}
return "[id=\"" + escapeAttrValue(id) + "\"]";
}

private static boolean isHashSafe(String id) {
return SAFE_HASH_ID.matcher(id).matches();
}

private static String escapeAttrValue(String s) {
return s.replace("\\", "\\\\").replace("\"", "\\\"");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void execute() {
log.warn("Failed to find an elements using locator {}", context.getBy().toString());
log.warn("Trying to heal...");
}
nodesToHeal.forEach(nodes -> healingService.findNewLocations(nodes, destination, context));
nodesToHeal.forEach(nodes -> healingService.findNewLocations(nodes, destination, context, engine));
}

private void splitDbNodes(List<List<Node>> nodesFromDb) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void execute() {

log.warn("Trying to heal...");
for (List<Node> nodes : context.getReferenceElementsDto().getPaths()) {
healingService.findNewLocations(nodes, destination, context);
healingService.findNewLocations(nodes, destination, context, engine);
}
}

Expand Down
30 changes: 20 additions & 10 deletions src/main/java/com/epam/healenium/service/HealingService.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
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.SelfHealingEngine;
import com.epam.healenium.model.*;
import com.epam.healenium.treecomparing.HeuristicNodeDistance;
import com.epam.healenium.treecomparing.LCSPathDistance;
import com.epam.healenium.treecomparing.Node;
Expand Down Expand Up @@ -54,19 +52,21 @@ public HealingService(Config finalizedConfig, WebDriver driver) {
}

/**
* @param destination the new HTML page source on which we should search for the element
* @param paths source path to locator
* @param destination the new HTML page source on which we should search for the element
* @param context context data for healing
* @param engine
*/
public void findNewLocations(List<Node> paths, Node destination, Context context) {
public void findNewLocations(List<Node> paths, Node destination, Context context, SelfHealingEngine engine) {
PathFinder pathFinder = new PathFinder(new LCSPathDistance(), new HeuristicNodeDistance());
AbstractMap.SimpleImmutableEntry<Integer, Map<Double, List<AbstractMap.SimpleImmutableEntry<Node, Integer>>>> scoresToNodes =
pathFinder.findScoresToNodes(new Path(paths.toArray(new Node[0])), destination);
List<Scored<Node>> scoreds = pathFinder.getSortedNodes(scoresToNodes.getValue(), recoveryTries, scoreCap);
List<Scored<Node>> scoreds = pathFinder.getSortedNodes(scoresToNodes.getValue(), 1000, scoreCap);

List<HealedElement> healedElements = scoreds.stream()
.map(node -> toLocator(node, context))
.map(node -> toLocator(node, context, engine))
.filter(Objects::nonNull)
.limit(recoveryTries)
.collect(Collectors.toList());
if (!healedElements.isEmpty()) {
HealingResult healingResult = new HealingResult()
Expand All @@ -81,13 +81,17 @@ public void findNewLocations(List<Node> paths, Node destination, Context context
/**
* @param node convert source node to locator
* @param context chain context
* @param engine
* @return healedElement
*/
protected HealedElement toLocator(Scored<Node> node, Context context) {
protected HealedElement toLocator(Scored<Node> node, Context context, SelfHealingEngine engine) {
for (Set<SelectorComponent> detailLevel : selectorDetailLevels) {
By locator = construct(node.getValue(), detailLevel);
if (isUnsuccessLocator(locator, context, engine)) {
return null;
}
List<WebElement> elements = driver.findElements(locator);
if (elements.size() == 1 && !context.getElementIds().contains(((RemoteWebElement) elements.get(0)).getId())) {
if (elements.size() == 1 && !context.getElementIds().contains(((RemoteWebElement) elements.get(0)).getId()) ) {
Scored<By> byScored = new Scored<>(node.getScore(), locator);
context.getElementIds().add(((RemoteWebElement) elements.get(0)).getId());
HealedElement healedElement = new HealedElement();
Expand All @@ -98,6 +102,12 @@ protected HealedElement toLocator(Scored<Node> node, Context context) {
return null;
}

private boolean isUnsuccessLocator(By locator, Context context, SelfHealingEngine engine) {
Locator convertLocator = engine.getClient().getMapper().byToLocator(locator);
List<Locator> unsuccessfulLocators = context.getUnsuccessfulLocators();
return unsuccessfulLocators != null && unsuccessfulLocators.contains(convertLocator);
}

/**
* @param curPathHeightToScores - all PathToNode candidate collection
* @return list healingCandidateDto for metrics
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/epam/healenium/utils/StackUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public Predicate<StackTraceElement> redundantPackages() {
return value -> {
Stream<String> skippingPackageStream = Stream.of("java.base", "sun.reflect", "java.lang", "org.gradle",
"org.junit", "java.util", "com.sun", "com.google", "jdk.internal", "org.openqa", "com.codeborne",
"ru.yandex", "jdk.proxy2", "io.appium");
"ru.yandex", "jdk.proxy2", "io.appium", "jdk.proxy1");
return skippingPackageStream.noneMatch(s -> value.getClassName().startsWith(s));
};
}
Expand Down
Loading