/*
* Copyright 2004-2016 EPAM Systems
*
* This file is part of JDI project.
*
* JDI is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JDI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JDI. If not, see <http://www.gnu.org/licenses/>.
*/
package com.epam.jdi.uitests.web.selenium.elements.apiInteract;
import com.epam.commons.LinqUtils;
import com.epam.commons.Timer;
import com.epam.commons.pairs.Pair;
import com.epam.commons.pairs.Pairs;
import com.epam.jdi.uitests.core.interfaces.base.IBaseElement;
import com.epam.jdi.uitests.web.selenium.driver.WebDriverByUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import static com.epam.commons.LinqUtils.where;
import static com.epam.commons.PrintUtils.print;
import static com.epam.jdi.uitests.core.settings.JDISettings.*;
import static com.epam.jdi.uitests.web.WebSettings.getDriverFactory;
import static java.lang.String.format;
/**
* Created by Roman_Iovlev on 7/3/2015.
*/
public class GetElementModule {
private static final String failedToFindElementMessage = "Can't find Element '%s' during %s seconds";
private static final String findToMuchElementsMessage = "Find %s elements instead of one for Element '%s' during %s seconds";
public By byLocator;
public Pairs<ContextType, By> context = new Pairs<>();
public Function<WebElement, Boolean> localElementSearchCriteria = null;
public WebElement rootElement;
private String driverName = "";
private IBaseElement element;
public GetElementModule(IBaseElement element) {
this.element = element;
driverName = driverFactory.currentDriverName();
}
public GetElementModule(By byLocator, IBaseElement element) {
this(element);
this.byLocator = byLocator;
}
public GetElementModule(By byLocator, Pairs<ContextType, By> context, IBaseElement element) {
this(element);
this.byLocator = byLocator;
this.context = context;
}
public GetElementModule(By byLocator, WebElement rootElement, IBaseElement element) {
this(element);
this.byLocator = byLocator;
this.rootElement = rootElement;
}
public boolean hasLocator() {
return byLocator != null;
}
public String printContext() {
return context.toString();
}
public WebDriver getDriver() {
return (WebDriver) driverFactory.getDriver(driverName);
}
public String getDriverName() {
return driverName;
}
public void setDriverName(String driverName) { this.driverName = driverName; }
public WebElement getElement() {
logger.debug("Get Web Element: " + element);
WebElement element = timer().getResultByCondition(this::getElementAction, el -> el != null);
logger.debug("One Element found");
return element;
}
public List<WebElement> getElements() {
logger.debug("Get Web elements: " + element);
List<WebElement> elements = getElementsAction();
logger.debug("Found %s elements", elements.size());
return elements;
}
public Timer timer() {
return new Timer(timeouts.currentTimeoutSec * 1000);
}
private List<WebElement> getElementsAction() {
List<WebElement> result = timer().getResultByCondition(
this::searchElements,
els -> where(els, getSearchCriteria()::apply).size() > 0);
timeouts.dropTimeouts();
if (result == null)
throw exception("Can't get Web Elements");
return where(result, getSearchCriteria()::apply);
}
private Function<WebElement, Boolean> getSearchCriteria() {
return localElementSearchCriteria != null ? localElementSearchCriteria : getDriverFactory().elementSearchCriteria;
}
public GetElementModule searchAll() {
localElementSearchCriteria = el -> el != null;
return this;
}
private WebElement getElementAction() {
int timeout = timeouts.currentTimeoutSec;
List<WebElement> result = getElementsAction();
switch (result.size()) {
case 0:
throw exception(failedToFindElementMessage, element, timeout);
case 1:
return result.get(0);
default:
throw exception(findToMuchElementsMessage, result.size(), element, timeout);
}
}
private List<WebElement> searchElements() {
if (this.context == null || this.context.isEmpty())
return getDriver().findElements(byLocator);
SearchContext context = (rootElement != null)
? rootElement
: getSearchContext(correctXPaths(this.context));
return context.findElements(correctXPaths(byLocator));
}
private SearchContext getSearchContext(Pairs<ContextType, By> context) {
SearchContext searchContext = getDriver().switchTo().defaultContent();
for (Pair<ContextType, By> locator : context) {
WebElement element = searchContext.findElement(locator.value);
if (locator.key == ContextType.Locator)
searchContext = element;
else {
getDriver().switchTo().frame(element);
searchContext = getDriver();
}
}
return searchContext;
}
private Pairs<ContextType, By> correctXPaths(Pairs<ContextType, By> context) {
if (context.size() == 1) return context;
for (Pair<ContextType, By> pair : context.subList(1)) {
By byValue = pair.value;
if (byValue.toString().contains("By.xpath: //"))
pair.value = WebDriverByUtils.getByFunc(byValue).apply(WebDriverByUtils.getByLocator(byValue)
.replaceFirst("/", "./"));
}
return context;
}
private By correctXPaths(By byValue) {
return (byValue.toString().contains("By.xpath: //"))
? WebDriverByUtils.getByFunc(byValue).apply(WebDriverByUtils.getByLocator(byValue)
.replaceFirst("/", "./"))
: byValue;
}
public void clearCookies() {
getDriver().manage().deleteAllCookies();
}
@Override
public String toString() {
return shortLogMessagesFormat
? printFullLocator()
: format("Locator: '%s'", byLocator) +
((context.size() > 0)
? format(", Context: '%s'", context)
: "");
}
private String printFullLocator() {
if (byLocator == null)
return "No Locators";
List<String> result = new ArrayList<>();
if (context.size() != 0)
result = LinqUtils.select(context, el -> printShortBy(el.value));
result.add(printShortBy(byLocator));
return print(result);
}
private String printShortBy(By by) {
return String.format("%s='%s'", WebDriverByUtils.getByName(by), WebDriverByUtils.getByLocator(by));
}
}