Skip to content
This repository was archived by the owner on Mar 27, 2026. It is now read-only.
Open
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
13 changes: 8 additions & 5 deletions src/main/java/io/qameta/htmlelements/annotation/FindBy.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
@HandleWith(FindBy.Extension.class)
public @interface FindBy {

String value();
String value() default "";
String xpath() default "";
String css() default "";
String id() default "";

class Extension implements MethodHandler<Object> {

Expand All @@ -39,22 +42,22 @@ public Object handle(Context context, Object proxy, Method method, Object[] args

// html element proxy (recurse)
if (method.isAnnotationPresent(FindBy.class) && WebElement.class.isAssignableFrom(proxyClass)) {
String selector = ReflectionUtils.getSelector(method, args);
By selector = ReflectionUtils.getSelector(method, args);

Context childContext = context.newChildContext(method, method.getReturnType());
childContext.getRegistry().getExtensions(ContextEnricher.class)
.forEach(enricher -> enricher.enrich(childContext, method, args));
return createProxy(
method.getReturnType(),
childContext,
() -> ((SearchContext) proxy).findElement(By.xpath(selector)),
() -> ((SearchContext) proxy).findElement(selector),
WebElement.class, Locatable.class
);
}

// html element list proxy (recurse)
if (method.isAnnotationPresent(FindBy.class) && List.class.isAssignableFrom(method.getReturnType())) {
String selector = ReflectionUtils.getSelector(method, args);
By selector = ReflectionUtils.getSelector(method, args);

Context childContext = context.newChildContext(method, method.getReturnType());
childContext.getRegistry().getExtensions(ContextEnricher.class)
Expand All @@ -63,7 +66,7 @@ public Object handle(Context context, Object proxy, Method method, Object[] args
method.getReturnType(),
childContext,
() -> {
List<WebElement> originalElements = ((SearchContext) proxy).findElements(By.xpath(selector));
List<WebElement> originalElements = ((SearchContext) proxy).findElements(selector);
Type methodReturnType = ((ParameterizedType) method
.getGenericReturnType()).getActualTypeArguments()[0];
return (List) originalElements.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import io.qameta.htmlelements.annotation.FindBy;
import io.qameta.htmlelements.context.Context;
import io.qameta.htmlelements.util.ReflectionUtils;
import org.openqa.selenium.By;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
Expand All @@ -22,8 +24,8 @@ class Extension implements ContextEnricher, MethodHandler<String> {

@Override
public void enrich(Context context, Method method, Object[] args) {
String selector = method.getAnnotation(FindBy.class).value();
context.getStore().put(SELECTOR_KEY, selector);
By selector = ReflectionUtils.getSelector(method, args);
context.getStore().put(SELECTOR_KEY, selector.toString());
}

@Override
Expand Down
57 changes: 50 additions & 7 deletions src/main/java/io/qameta/htmlelements/util/ReflectionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,25 @@
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.openqa.selenium.By;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Arrays.stream;

public class ReflectionUtils {

private static final int UNIQ_LOCATOR_COUNT = 1;


public static <T> T newInstance(Class<T> clazz) {
try {
return ConstructorUtils.invokeConstructor(clazz);
Expand Down Expand Up @@ -70,21 +75,59 @@ public static String getDescription(Class<?> clazz) {
return splitCamelCase(clazz.getSimpleName());
}

public static String getSelector(Method method, Object[] args) {
Map<String, String> parameters = getParameters(method, args);
String selector = method.getAnnotation(FindBy.class).value();
for (String key : parameters.keySet()) {
selector = selector.replaceAll("\\{\\{ " + key + " \\}\\}", parameters.get(key));
public static By getSelector(Method method, Object[] args) {
Function<String,String> replaceParam= locator->{
Map<String, String> parameters = getParameters(method, args);
for (String key : parameters.keySet()) {
locator = locator.replaceAll("\\{\\{" + key + "\\}\\}", parameters.get(key));
}
return locator;

};
By by= null;
String locator;
FindBy findBy=method.getAnnotation(FindBy.class);
List<String> locators = new ArrayList<>();
//default xpath
if(!findBy.value().isEmpty()) {
locator=replaceParam.apply(findBy.value());
by = By.xpath(locator);
locators.add(locator);
}

//xpath
if(!findBy.xpath().isEmpty()) {
locator=replaceParam.apply(findBy.xpath());
by = By.xpath(locator);
locators.add(locator);
}
//css
if(!findBy.css().isEmpty()) {
locator=replaceParam.apply(findBy.css());
by = By.cssSelector(locator);
locators.add(locator);
}
//id
if(!findBy.id().isEmpty()) {
locator=replaceParam.apply(findBy.id());
by = By.id(locator);
locators.add(locator);
}

if (locators.size() != UNIQ_LOCATOR_COUNT) {
throw new IllegalArgumentException(
String.format("You must specify at most one location strategy. Number found: %d (%s)",
locators.size(), locators.toString()));
}
return selector;
return by;
}

public static String getDescription(Method method, Object[] args) {
if (method.isAnnotationPresent(Description.class)) {
Map<String, String> parameters = getParameters(method, args);
String name = method.getAnnotation(Description.class).value();
for (String key : parameters.keySet()) {
name = name.replaceAll("\\{\\{ " + key + " \\}\\}", parameters.get(key));
name = name.replaceAll("\\{\\{" + key + "\\}\\}", parameters.get(key));
}
return name;
} else {
Expand Down