package org.fluentlenium.core.search;
import org.fluentlenium.core.components.ComponentInstantiator;
import org.fluentlenium.core.domain.FluentList;
import org.fluentlenium.core.domain.FluentWebElement;
import org.fluentlenium.core.inject.FluentInjectControl;
import org.fluentlenium.core.proxy.LocatorProxies;
import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.pagefactory.ElementLocator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Perform element searchs in a given context.
*/
public class Search implements SearchControl<FluentWebElement> {
private final SearchContext searchContext;
private final Object container;
private final ComponentInstantiator instantiator;
private final FluentInjectControl injectControl;
/**
* Creates a new search object.
*
* @param context search context
* @param container container
* @param instantiator component instantiator
* @param injectControl inject control
*/
public Search(SearchContext context, Object container, ComponentInstantiator instantiator,
FluentInjectControl injectControl) {
searchContext = context;
this.container = container;
this.instantiator = instantiator;
this.injectControl = injectControl;
}
/**
* Central methods to find elements on the page. Can provide some filters. Able to use css1, css2, css3, see WebDriver
* restrictions
*
* @param selector elements name to find
* @param filters filters set
* @return fluent list of fluent web elements
*/
@Override
public FluentList<FluentWebElement> find(String selector, SearchFilter... filters) {
StringBuilder stringBuilder = new StringBuilder(selector);
List<SearchFilter> postFilterSelector = new ArrayList<>();
if (filters != null && filters.length > 0) {
for (SearchFilter filter : filters) {
if (filter.isCssFilterSupported()) {
stringBuilder.append(filter.getCssFilter());
} else {
postFilterSelector.add(filter);
}
}
}
List<WebElement> select = selectList(stringBuilder.toString());
FluentList fluentList = instantiator.asFluentList(select);
injectControl.injectComponent(fluentList, container, searchContext);
if (postFilterSelector.isEmpty()) {
return fluentList;
}
List<WebElement> postFilteredElements = LocatorProxies
.createWebElementList(new AbstractSearchSupplier(postFilterSelector, select) {
@Override
public List<WebElement> get() {
Collection<FluentWebElement> postFiltered = fluentList;
for (SearchFilter filter : postFilterSelector) {
postFiltered = filter.applyFilter(postFiltered);
}
ArrayList<WebElement> webElements = new ArrayList<>();
for (FluentWebElement element : postFiltered) {
webElements.add(element.getElement());
}
return webElements;
}
});
FluentList<FluentWebElement> postFilteredList = instantiator.asFluentList(postFilteredElements);
injectControl.injectComponent(postFilteredList, container, searchContext);
return postFilteredList;
}
private ElementLocator locator(By by) {
return new ElementLocator() {
@Override
public WebElement findElement() {
return searchContext.findElement(by);
}
@Override
public List<WebElement> findElements() {
return searchContext.findElements(by);
}
@Override
public String toString() {
return by.toString();
}
};
}
private List<WebElement> selectList(String cssSelector) {
return selectList(By.cssSelector(cssSelector));
}
private List<WebElement> selectList(By locator) {
return LocatorProxies.createWebElementList(locator(locator));
}
/**
* Central methods to find elements on the page with filters.
*
* @param filters filters set
* @return fluent list of fluent web elements
*/
@Override
public FluentList<FluentWebElement> find(SearchFilter... filters) {
if (filters == null || filters.length == 0) {
throw new IllegalArgumentException("cssSelector or filter is required");
}
return find("*", filters);
}
@Override
public FluentList<FluentWebElement> find(By locator, SearchFilter... filters) {
List<WebElement> select = selectList(locator);
FluentList fluentList = instantiator.asFluentList(select);
if (filters.length == 0) {
return fluentList;
}
List<WebElement> postFilteredElements = LocatorProxies
.createWebElementList(new AbstractSearchSupplier(Arrays.asList(filters), select) {
@Override
public List<WebElement> get() {
Collection<FluentWebElement> postFiltered = fluentList;
for (SearchFilter filter : filters) {
postFiltered = filter.applyFilter(postFiltered);
}
List<WebElement> webElements = new ArrayList<>();
for (FluentWebElement element : postFiltered) {
webElements.add(element.getElement());
}
return webElements;
}
});
return instantiator.asFluentList(postFilteredElements);
}
@Override
public FluentList<FluentWebElement> find(List<WebElement> rawElements) {
FluentList<FluentWebElement> postFilteredList = instantiator.asFluentList(rawElements);
injectControl.injectComponent(postFilteredList, container, searchContext);
return postFilteredList;
}
@Override
public FluentList<FluentWebElement> $(String selector, SearchFilter... filters) {
return find(selector, filters);
}
@Override
public FluentWebElement el(String selector, SearchFilter... filters) {
return find(selector, filters).first();
}
@Override
public FluentList<FluentWebElement> $(SearchFilter... filters) {
return find(filters);
}
@Override
public FluentWebElement el(SearchFilter... filters) {
return find(filters).first();
}
@Override
public FluentList<FluentWebElement> $(By locator, SearchFilter... filters) {
return find(locator, filters);
}
@Override
public FluentWebElement el(By locator, SearchFilter... filters) {
return find(locator, filters).first();
}
@Override
public FluentWebElement el(WebElement rawElement) {
return find(Arrays.asList(rawElement)).first();
}
@Override
public FluentList<FluentWebElement> $(List<WebElement> rawElements) {
return find(rawElements);
}
}