package com.ggasoftware.uitest.control.new_controls.base;
import com.ggasoftware.uitest.control.*;
import com.ggasoftware.uitest.control.base.annotations.Frame;
import com.ggasoftware.uitest.control.base.annotations.JFindBy;
import com.ggasoftware.uitest.control.base.annotations.JPage;
import com.ggasoftware.uitest.control.base.annotations.functions.Functions;
import com.ggasoftware.uitest.control.base.apiInteract.ContextType;
import com.ggasoftware.uitest.control.base.apiInteract.GetElementModule;
import com.ggasoftware.uitest.control.base.interfaces.IScenario;
import com.ggasoftware.uitest.control.base.interfaces.IScenarioWithResult;
import com.ggasoftware.uitest.control.base.logger.LogSettings;
import com.ggasoftware.uitest.control.base.map.MapArray;
import com.ggasoftware.uitest.control.base.pairs.Pairs;
import com.ggasoftware.uitest.control.interfaces.base.*;
import com.ggasoftware.uitest.control.interfaces.common.*;
import com.ggasoftware.uitest.control.interfaces.complex.*;
import com.ggasoftware.uitest.control.new_controls.common.*;
import com.ggasoftware.uitest.control.new_controls.complex.*;
import com.ggasoftware.uitest.control.new_controls.complex.table.Table;
import com.ggasoftware.uitest.control.new_controls.composite.Page;
import com.ggasoftware.uitest.utils.Timer;
import com.ggasoftware.uitest.utils.linqInterfaces.*;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.FindBy;
import java.lang.reflect.Field;
import static com.ggasoftware.uitest.control.base.annotations.AnnotationsUtil.*;
import static com.ggasoftware.uitest.control.base.annotations.functions.Functions.NONE;
import static com.ggasoftware.uitest.control.base.asserter.testNG.Assert.exception;
import static com.ggasoftware.uitest.control.base.logger.TestNGLog4JLogger.logger;
import static com.ggasoftware.uitest.utils.LinqUtils.foreach;
import static com.ggasoftware.uitest.utils.ReflectionUtils.*;
import static com.ggasoftware.uitest.utils.StringUtils.LineBreak;
import static com.ggasoftware.uitest.utils.TestBaseWebDriver.*;
import static com.ggasoftware.uitest.utils.Timer.*;
import static java.lang.String.format;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.apache.commons.lang.StringUtils.substring;
/**
* Created by Roman_Iovlev on 6/10/2015.
*/
public abstract class BaseElement<P> implements IBaseElement {
public static JActionTT<String, JActionT<String>> setValueRule = (text, action) -> {
if (text == null) return;
action.invoke(text);
};
public static JActionTT<String, JActionT<String>> setValueEmptyAction = (text, action) -> {
if (text == null || text.equals("")) return;
action.invoke(text.equals("#CLEAR#") ? "" : text);
};
public static IScenario invocationScenario = (element, actionName, jAction) -> {
sleep(100);
element.defaultLogAction(actionName);
alwaysDoneAction(jAction::invoke);
};
private static MapArray<Class, Class> map;
public Functions function = NONE;
/**
* Locator of the element if applicable
*/
protected String locator;
protected String name;
protected GetElementModule avatar;
/**
* Parent panel which contains current element
*/
protected P parent;
protected String parentTypeName;
public static IScenarioWithResult invocationScenarioWithResult = new IScenarioWithResult() {
@Override
public <TResult> TResult invoke(BaseElement element, String actionName, JFuncT<TResult> jAction, JFuncTT<TResult, String> logResult, LogSettings logSettings) {
sleep(100);
if (!simpleLogFormat)
element.defaultLogAction(actionName);
Timer timer = new Timer();
timer.timePassedInMSec();
TResult result = getResultAction(jAction::invoke);
String stringResult = (logResult == null)
? result.toString()
: logResult.invoke(result);
element.defaultLogResultAction(actionName, stringResult, logSettings);
return result;
}
};
public BaseElement() {
this(null);
}
public BaseElement(By byLocator) {
name = getTypeName();
avatar = new GetElementModule(byLocator, this);
}
public BaseElement(String name, String locator, P panel) {
this.name = name;
this.locator = locator;
this.parent = panel;
avatar = new GetElementModule(getByLocator(), this);
}
public BaseElement(String name, By byLocator) {
this.name = name;
avatar = new GetElementModule(byLocator, this);
this.locator = byLocator.toString();
}
public static <T> T InitElements(T parent) {
fillParentPage(parent);
foreach(getFields(parent, IBaseElement.class), f -> setElement(parent, f));
return parent;
}
public static void setElement(Object parent, Field field) throws RuntimeException {
try {
Class<?> type = field.getType();
BaseElement instance;
if (isClass(type, Page.class)) {
instance = (BaseElement) type.newInstance();
instance.fillPage(field, parent);
} else {
instance = createChildFromField(parent, field, type);
instance.function = getFunction(field);
}
instance.setName(getElementName(field));
instance.setParentName(parent.getClass().getSimpleName());
field.set(parent, instance);
if (isInterface(field, IComposite.class))
InitElements(instance);
} catch (Exception | AssertionError ex) {
throw exception(format("Error in setElement for field '%s' with parent '%s'", field.getName(), parent.getClass().getSimpleName()) + LineBreak + ex.getMessage());
}
}
public static BaseElement createChildFromField(Object parent, Field field, Class<?> type) {
BaseElement instance = (BaseElement) getFieldValue(field, parent);
if (instance == null)
try {
instance = getElementInstance(type, field.getName(), getNewLocator(field));
} catch (Exception | AssertionError ignore) {
throw exception(
format("Can't create child for parent '%s' with type '%s'",
parent.getClass().getSimpleName(), field.getType().getName()));
}
else if (instance.getLocator() == null)
instance.avatar.byLocator = getNewLocator(field);
instance.avatar.context = (isBaseElement(parent))
? ((BaseElement) parent).avatar.context.copy()
: new Pairs<>();
if (type != null) {
By frameBy = getFrame(type.getDeclaredAnnotation(Frame.class));
if (frameBy != null)
instance.avatar.context.add(ContextType.Frame, frameBy);
}
if (isBaseElement(parent)) {
By parentLocator = ((BaseElement) parent).getLocator();
if (parentLocator != null)
instance.avatar.context.add(ContextType.Locator, parentLocator);
}
return instance;
}
public static void fillParentPage(Object parent) {
Class<?> parentType = parent.getClass();
if (isClass(parentType, Page.class) &&
parentType.isAnnotationPresent(JPage.class))
fillPageFromAnnotaiton((Page) parent,
parentType.getAnnotation(JPage.class), null);
}
private static boolean isBaseElement(Object obj) {
return isClass(obj.getClass(), BaseElement.class);
}
private static BaseElement getElementInstance(Class<?> type, String fieldName, By newLocator) {
try {
if (!type.isInterface()) {
BaseElement instance = (BaseElement) type.newInstance();
instance.avatar.byLocator = newLocator;
return instance;
}
Class classType = getInterfacesMap().first(clType -> clType == type);
if (classType != null)
return (BaseElement) classType.getDeclaredConstructor(By.class).newInstance(newLocator);
throw exception("Unknown interface: " + type +
". Add relation interface -> class in VIElement.InterfaceTypeMap");
} catch (Exception | AssertionError ex) {
throw exception(format("Error in getElementInstance for field '%s' with type '%s'", fieldName, type.getName()) +
LineBreak + ex.getMessage());
}
}
private static By getNewLocator(Field field) {
try {
By byLocator = null;
String locatorGroup = applicationVersion;
if (locatorGroup != null) {
JFindBy jFindBy = field.getAnnotation(JFindBy.class);
if (jFindBy != null && locatorGroup.equals(jFindBy.group()))
byLocator = getFindByLocator(jFindBy);
}
return (byLocator != null)
? byLocator
: getFindByLocator(field.getAnnotation(FindBy.class));
} catch (Exception | AssertionError ex) {
throw exception(format("Error in get locator for type '%s'", field.getType().getName()) +
LineBreak + ex.getMessage());
}
}
public static void setValueRule(String text, JActionT<String> action) {
setValueRule.invoke(text, action);
}
private static MapArray<Class, Class> getInterfacesMap() {
try {
if (map == null)
map = new MapArray<>(new Object[][]{
{IElement.class, Element.class},
{IButton.class, Button.class},
{IClickable.class, Clickable.class},
{IClickableText.class, Button.class},
{IComboBox.class, ComboBox.class},
{ILink.class, Link.class},
{ISelector.class, Selector.class},
{IText.class, Text.class},
{ITextArea.class, TextArea.class},
{IInput.class, Input.class},
{ILabel.class, Label.class},
{IDropDown.class, Dropdown.class},
{IDropList.class, DropList.class},
{IGroup.class, ElementsGroup.class},
{ITable.class, Table.class},
{ICheckBox.class, CheckBox.class},
{IRadioButtons.class, RadioButton.class},
{ICheckList.class, CheckList.class},
{ITextList.class, TextList.class},
{ITabs.class, Tabs.class},
{IFileInput.class, FileInput.class},
{IDatePicker.class, DatePicker.class},
});
return map;
} catch (Exception | AssertionError ex) {
throw exception("Error in getInterfaceTypeMap" + LineBreak + ex.getMessage());
}
}
public String getName() {
return name != null ? name : getTypeName();
}
public void setName(String name) {
this.name = name;
}
public boolean haveLocator() {
return avatar.haveLocator();
}
public WebDriver getDriver() {
return avatar.getDriver();
}
public By getLocator() {
return avatar.byLocator;
}
public void setAvatar(By byLocator, GetElementModule avatar) {
this.avatar = new GetElementModule(byLocator, avatar.context, this);
this.avatar.localElementSearchCriteria = avatar.localElementSearchCriteria;
}
public GetElementModule getAvatar() {
return avatar;
}
public void setAvatar(GetElementModule avatar) {
this.avatar = avatar;
}
protected void setWaitTimeout(long mSeconds) {
logger.debug("Set wait timeout to " + mSeconds);
getDriver().manage().timeouts().implicitlyWait(mSeconds, MILLISECONDS);
}
/**
* Get Parent Class Name
*
* @return Parent Canonical Class Name
*/
protected String getParentClassName() {
if (parent == null) {
return "";
}
if (simpleClassName) {
return parent.getClass().getSimpleName();
}
return parent.getClass().getCanonicalName();
}
protected String getTypeName() {
return getClass().getSimpleName();
}
// Page Objects init
protected String getParentName() {
if (parentTypeName == null)
parentTypeName = (parent != null) ? parent.getClass().getSimpleName() : "No Parent";
return parentTypeName;
}
protected void setParentName(String parrentName) {
parentTypeName = parrentName;
}
protected JavascriptExecutor jsExecutor() {
return (JavascriptExecutor) getDriver();
}
@Override
public String toString() {
return (simpleLogFormat)
? format("%s %s.%s", getTypeName(), getParentName(), getName())
: format("Name: '%s', Type: '%s' In: '%s', %s",
getName(), getTypeName(), getParentName(), avatar);
}
public void defaultLogAction(String actionName) {
logger.info(format((simpleLogFormat)
? "%s at %s"
: "Perform action '%s' with element (%s)",
actionName, this.toString()));
}
public void defaultLogResultAction(String actionName, String stringResult, LogSettings logSettings) {
if (simpleLogFormat)
logger.info(format("%s at %s %s.%s, result = '%s'", actionName, getTypeName(), getParentName(), getName(), substring(stringResult, 0, 255)));
else
logger.toLog(stringResult, logSettings);
}
protected final <TResult> TResult doJActionResult(String actionName, JFuncT<TResult> viAction) {
return doJActionResult(actionName, viAction, null, new LogSettings());
}
protected final <TResult> TResult doJActionResult(String actionName, JFuncT<TResult> viAction, JFuncTT<TResult, String> logResult) {
return doJActionResult(actionName, viAction, logResult, new LogSettings());
}
protected final <TResult> TResult doJActionResult(String actionName, JFuncT<TResult> viAction, LogSettings logSettings) {
return doJActionResult(actionName, viAction, null, logSettings);
}
protected final <TResult> TResult doJActionResult(String actionName, JFuncT<TResult> viAction,
JFuncTT<TResult, String> logResult, LogSettings logSettings) {
try {
processDemoMode();
return invocationScenarioWithResult.invoke(this, actionName, viAction, logResult, logSettings);
} catch (Exception | AssertionError ex) {
throw exception(format("Failed to do '%s' action. Exception: %s", actionName, ex));
}
}
protected final void doJAction(String actionName, JAction viAction) {
try {
processDemoMode();
invocationScenario.invoke(this, actionName, viAction);
} catch (Exception | AssertionError ex) {
throw exception(format("Failed to do '%s' action. Exception: %s", actionName, ex));
}
}
private void processDemoMode() {
}
public void fillPage(Field field, Object parent) {
if (field.isAnnotationPresent(JPage.class))
fillPageFromAnnotaiton((Page) this, field.getAnnotation(JPage.class), parent);
}
/**
* Gets element's By locator
*
* @return By Locator of the element
*/
public By getByLocator() {
String locator_body = locator.replaceAll("[\\w\\s]*=(.*)", "$1").trim();
String type = locator.replaceAll("([\\w\\s]*)=.*", "$1").trim();
switch (type) {
case "css":
return By.cssSelector(locator_body);
case "id":
return By.id(locator_body);
case "link":
return By.linkText(locator_body);
case "xpath":
return By.xpath(locator_body);
case "text":
return By.xpath(format("//*[contains(text(), '%s')]", locator_body));
case "name":
return By.name(locator_body);
default:
return By.xpath(locator);
}
}
}