Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Add more nice functional stuff into pagefactory helpers #1584

Merged
merged 2 commits into from
Nov 5, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class DefaultElementByBuilder extends AppiumByBuilder {

private static final String PRIORITY = "priority";
private static final String VALUE = "value";
private static final Class[] ANNOTATION_ARGUMENTS = new Class[]{};
private static final Class<?>[] ANNOTATION_ARGUMENTS = new Class[]{};
private static final Object[] ANNOTATION_PARAMETERS = new Object[]{};

public DefaultElementByBuilder(String platform, String automation) {
Expand Down Expand Up @@ -155,7 +155,7 @@ private By[] getBys(Class<? extends Annotation> singleLocator, Class<? extends A
}
}

return result.toArray(new By[result.size()]);
return result.toArray(new By[0]);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,5 @@
package io.appium.java_client.pagefactory.bys;

public enum ContentType {
HTML_OR_DEFAULT,
NATIVE_MOBILE_SPECIFIC;
HTML_OR_DEFAULT, NATIVE_MOBILE_SPECIFIC
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.openqa.selenium.By;
import org.openqa.selenium.support.pagefactory.AbstractAnnotations;

import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
Expand All @@ -33,6 +34,7 @@
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
Expand All @@ -42,18 +44,19 @@
* - https://code.google.com/p/selenium/wiki/PageFactory
*/
public abstract class AppiumByBuilder extends AbstractAnnotations {
protected static final Class<?>[] DEFAULT_ANNOTATION_METHOD_ARGUMENTS = new Class<?>[] {};
protected static final Class<?>[] DEFAULT_ANNOTATION_METHOD_ARGUMENTS = new Class<?>[]{};

private static final List<String> METHODS_TO_BE_EXCLUDED_WHEN_ANNOTATION_IS_READ =
new ArrayList<String>() {
private static final long serialVersionUID = 1L; {
Stream.of(Object.class, Annotation.class, Proxy.class)
private static final List<String> METHODS_TO_BE_EXCLUDED_WHEN_ANNOTATION_IS_READ = new ArrayList<String>() {
private static final long serialVersionUID = 1L;

{
Stream.of(Object.class, Annotation.class, Proxy.class)
.map(Class::getDeclaredMethods)
.map(AppiumByBuilder::getMethodNames)
.flatMap(List::stream)
.forEach(this::add);
}
};
}
};
protected final AnnotatedElementContainer annotatedElementContainer;
protected final String platform;
protected final String automation;
Expand All @@ -65,79 +68,68 @@ protected AppiumByBuilder(String platform, String automation) {
}

private static List<String> getMethodNames(Method[] methods) {
List<String> names = new ArrayList<>();
for (Method m : methods) {
names.add(m.getName());
}
return names;
return Stream.of(methods).map(Method::getName).collect(Collectors.toList());
}

private static Method[] prepareAnnotationMethods(Class<? extends Annotation> annotation) {
List<String> targetAnnotationMethodNamesList =
getMethodNames(annotation.getDeclaredMethods());
List<String> targetAnnotationMethodNamesList = getMethodNames(annotation.getDeclaredMethods());
targetAnnotationMethodNamesList.removeAll(METHODS_TO_BE_EXCLUDED_WHEN_ANNOTATION_IS_READ);
Method[] result = new Method[targetAnnotationMethodNamesList.size()];
for (String methodName : targetAnnotationMethodNamesList) {
try {
result[targetAnnotationMethodNamesList.indexOf(methodName)] =
annotation.getMethod(methodName, DEFAULT_ANNOTATION_METHOD_ARGUMENTS);
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException(e);
}
}
return result;
return targetAnnotationMethodNamesList.stream()
.map((methodName) -> {
try {
return annotation.getMethod(methodName, DEFAULT_ANNOTATION_METHOD_ARGUMENTS);
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException(e);
}
}).toArray(Method[]::new);
}

private static String getFilledValue(Annotation mobileBy) {
Method[] values = prepareAnnotationMethods(mobileBy.getClass());
for (Method value : values) {
if (!String.class.equals(value.getReturnType())) {
continue;
}

try {
String strategyParameter = value.invoke(mobileBy).toString();
if (!strategyParameter.isEmpty()) {
return value.getName();
}
} catch (IllegalAccessException
| IllegalArgumentException
| InvocationTargetException e) {
throw new RuntimeException(e);
}
}
throw new IllegalArgumentException(
"@" + mobileBy.getClass().getSimpleName() + ": one of " + Strategies.strategiesNames()
.toString() + " should be filled");
return Stream.of(prepareAnnotationMethods(mobileBy.getClass()))
.filter((method) -> String.class == method.getReturnType())
.filter((method) -> {
try {
Object strategyParameter = method.invoke(mobileBy);
return strategyParameter != null && !String.valueOf(strategyParameter).isEmpty();
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new RuntimeException(e);
}
})
.findFirst()
.map(Method::getName)
.orElseThrow(() -> new IllegalArgumentException(
String.format("@%s: one of %s should be filled",
mobileBy.getClass().getSimpleName(), Strategies.strategiesNames())
));
}

private static By getMobileBy(Annotation annotation, String valueName) {
Strategies[] strategies = Strategies.values();
for (Strategies strategy : strategies) {
if (strategy.returnValueName().equals(valueName)) {
return strategy.getBy(annotation);
}
}
throw new IllegalArgumentException(
"@" + annotation.getClass().getSimpleName() + ": There is an unknown strategy "
+ valueName);
return Stream.of(Strategies.values())
.filter((strategy) -> strategy.returnValueName().equals(valueName))
.findFirst()
.map((strategy) -> strategy.getBy(annotation))
.orElseThrow(() -> new IllegalArgumentException(
String.format("@%s: There is an unknown strategy %s",
annotation.getClass().getSimpleName(), valueName)
));
}

private static <T extends By> T getComplexMobileBy(Annotation[] annotations,
Class<T> requiredByClass) {
By[] byArray = new By[annotations.length];
for (int i = 0; i < annotations.length; i++) {
byArray[i] = getMobileBy(annotations[i], getFilledValue(annotations[i]));
}
private static <T extends By> T getComplexMobileBy(Annotation[] annotations, Class<T> requiredByClass) {
By[] byArray = Stream.of(annotations)
.map((annotation) -> getMobileBy(annotation, getFilledValue(annotation)))
.toArray(By[]::new);
try {
Constructor<T> c = requiredByClass.getConstructor(By[].class);
Object[] values = new Object[] {byArray};
Object[] values = new Object[]{byArray};
return c.newInstance(values);
} catch (Exception e) {
} catch (InvocationTargetException | NoSuchMethodException | InstantiationException
| IllegalAccessException e) {
throw new RuntimeException(e);
}
}

@Nullable
protected static By createBy(Annotation[] annotations, HowToUseSelectors howToUseLocators) {
if (annotations == null || annotations.length == 0) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public class ByChained extends org.openqa.selenium.support.pagefactory.ByChained
private static AppiumFunction<SearchContext, WebElement> getSearchingFunction(By by) {
return input -> {
try {
if (input == null) {
return null;
}
return input.findElement(by);
} catch (NoSuchElementException e) {
return null;
Expand Down Expand Up @@ -71,7 +74,7 @@ public WebElement findElement(SearchContext context) {
checkNotNull(searchingFunction);
return waiting.until(searchingFunction);
} catch (TimeoutException e) {
throw new NoSuchElementException("Cannot locate an element using " + toString());
throw new NoSuchElementException("Cannot locate an element using " + this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,5 @@
package io.appium.java_client.pagefactory.bys.builder;

public enum HowToUseSelectors {
USE_ONE,
BUILD_CHAINED,
USE_ANY;
USE_ONE, BUILD_CHAINED, USE_ANY
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.openqa.selenium.By;

Expand Down Expand Up @@ -127,12 +128,7 @@ enum Strategies {
}

static List<String> strategiesNames() {
Strategies[] strategies = values();
List<String> result = new ArrayList<>();
for (Strategies strategy : strategies) {
result.add(strategy.valueName);
}
return result;
return Stream.of(values()).map((s) -> s.valueName).collect(Collectors.toList());
}

private static String getValue(Annotation annotation, Strategies strategy) {
Expand Down