Skip to content

Commit

Permalink
[extension-selenium] Add ability to handle exceptions for locator fil…
Browse files Browse the repository at this point in the history
…ters (#2196)
  • Loading branch information
web-flow committed Dec 29, 2021
1 parent e05821c commit 638161c
Show file tree
Hide file tree
Showing 16 changed files with 116 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;

import javax.inject.Inject;
Expand All @@ -28,10 +27,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vividus.ui.action.search.ElementActionService;
import org.vividus.ui.action.search.IElementFilterAction;
import org.vividus.ui.action.search.IElementSearchAction;
import org.vividus.ui.action.search.Locator;
import org.vividus.ui.action.search.LocatorType;
import org.vividus.ui.action.search.SearchParameters;
import org.vividus.ui.context.IUiContext;

Expand All @@ -47,29 +44,8 @@ public List<WebElement> findElements(SearchContext searchContext, Locator locato
{
SearchParameters searchParameters = locator.getSearchParameters();
IElementSearchAction searchAction = elementActionService.find(locator.getLocatorType());
List<WebElement> foundElements = searchAction.search(searchContext, searchParameters);
for (Entry<LocatorType, List<String>> entry : locator.getFilterAttributes().entrySet())
{
IElementFilterAction filterAction = elementActionService.find(entry.getKey());
for (String filterValue : entry.getValue())
{
int size = foundElements.size();
if (size == 0)
{
break;
}

List<WebElement> filteredElements = filterAction.filter(foundElements, filterValue);

LOGGER.atInfo().addArgument(() -> size - filteredElements.size())
.addArgument(size)
.addArgument(entry::getKey)
.addArgument(filterValue)
.log("{} of {} elements were filtered out by {} filter with '{}' value");

foundElements = filteredElements;
}
}
List<WebElement> foundElements = searchAction.search(searchContext, searchParameters,
locator.getFilterAttributes());
List<Locator> childLocators = locator.getChildLocators();
for (Locator attributes : childLocators)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.inject.Inject;
Expand All @@ -39,6 +40,7 @@ public abstract class AbstractElementAction implements IElementAction
private IWaitActions waitActions;
@Inject private IExpectedConditions<By> expectedConditions;
@Inject private ElementActions elementActions;
@Inject private ElementActionService elementActionService;
private Duration waitForElementTimeout;
private boolean retrySearchIfStale;

Expand All @@ -55,18 +57,19 @@ public LocatorType getType()
return type;
}

protected List<WebElement> findElements(SearchContext searchContext, By locator, SearchParameters parameters)
protected List<WebElement> findElements(SearchContext searchContext, By locator, SearchParameters parameters,
Map<LocatorType, List<String>> filters)
{
if (searchContext != null)
{
return findElements(searchContext, locator, parameters, false);
return findElements(searchContext, locator, parameters, filters, false);
}
LOGGER.error(IElementAction.NOT_SET_CONTEXT);
return List.of();
}

private List<WebElement> findElements(SearchContext searchContext, By locator, SearchParameters parameters,
boolean retry)
Map<LocatorType, List<String>> filters, boolean retry)
{
List<WebElement> elements = parameters.isWaitForElement()
? waitForElement(searchContext, locator)
Expand All @@ -77,16 +80,16 @@ private List<WebElement> findElements(SearchContext searchContext, By locator, S
.log("Total number of elements found {} is {}");
if (elementsFound)
{
Visibility visibility = parameters.getVisibility();
try
{
return Visibility.ALL == visibility
? elements
: filterElementsByVisibility(elements, visibility, retry);
List<WebElement> filteredElements = filterElementsByTypes(elements, filters);
Visibility visibility = parameters.getVisibility();
return Visibility.ALL == visibility ? filteredElements
: filterElementsByVisibility(filteredElements, visibility, retry);
}
catch (StaleElementReferenceException e)
{
return findElements(searchContext, locator, parameters, true);
return findElements(searchContext, locator, parameters, filters, true);
}
}
return List.of();
Expand Down Expand Up @@ -119,6 +122,41 @@ protected List<WebElement> filterElementsByVisibility(List<WebElement> elements,
}));
}

private List<WebElement> filterElementsByTypes(List<WebElement> foundElements,
Map<LocatorType, List<String>> filters)
{
List<WebElement> filteredElements = foundElements;
for (Map.Entry<LocatorType, List<String>> entry : filters.entrySet())
{
IElementFilterAction filterAction = elementActionService.find(entry.getKey());
for (String filterValue : entry.getValue())
{
int size = filteredElements.size();
if (size == 0)
{
break;
}
try {
filteredElements = filterAction.filter(filteredElements, filterValue);
}
catch (StaleElementReferenceException e)
{
if (retrySearchIfStale)
{
throw e;
}
LOGGER.warn(e.getMessage(), e);
}

int filteredElementsCount = size - filteredElements.size();
LOGGER.atInfo().addArgument(filteredElementsCount).addArgument(size)
.addArgument(entry::getKey).addArgument(filterValue)
.log("{} of {} elements were filtered out by {} filter with '{}' value");
}
}
return filteredElements;
}

private List<WebElement> waitForElement(SearchContext searchContext, By locator)
{
return waitActions.wait(searchContext, waitForElementTimeout,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.vividus.ui.action.search;

import java.util.List;
import java.util.Map;

import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
Expand All @@ -29,8 +30,9 @@ public ByLocatorSearch(LocatorType type)
}

@Override
public List<WebElement> search(SearchContext searchContext, SearchParameters parameters)
public List<WebElement> search(SearchContext searchContext, SearchParameters parameters,
Map<LocatorType, List<String>> filters)
{
return findElements(searchContext, getType().buildBy(parameters.getValue()), parameters);
return findElements(searchContext, getType().buildBy(parameters.getValue()), parameters, filters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
package org.vividus.ui.action.search;

import java.util.List;
import java.util.Map;

import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;

public interface IElementSearchAction extends IElementAction
{
List<WebElement> search(SearchContext searchContext, SearchParameters parameters);
List<WebElement> search(SearchContext searchContext, SearchParameters parameters,
Map<LocatorType, List<String>> filters);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.vividus.testdouble;

import java.util.List;
import java.util.Map;

import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
Expand All @@ -27,7 +28,8 @@
public class TestElementSearch implements IElementSearchAction
{
@Override
public List<WebElement> search(SearchContext searchContext, SearchParameters parameters)
public List<WebElement> search(SearchContext searchContext, SearchParameters parameters,
Map<LocatorType, List<String>> filters)
{
return List.of();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,16 @@

package org.vividus.ui.action;

import static com.github.valfirst.slf4jtest.LoggingEvent.info;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
Expand All @@ -51,7 +49,6 @@
import org.vividus.testdouble.TestElementSearch;
import org.vividus.testdouble.TestLocatorType;
import org.vividus.ui.action.search.ElementActionService;
import org.vividus.ui.action.search.IElementFilterAction;
import org.vividus.ui.action.search.Locator;
import org.vividus.ui.action.search.SearchParameters;
import org.vividus.ui.context.IUiContext;
Expand Down Expand Up @@ -84,7 +81,7 @@ void init()
@Test
void testFindElementsByLocatorSingleAttribute()
{
when(testSearch.search(eq(searchContext), any(SearchParameters.class)))
when(testSearch.search(eq(searchContext), any(SearchParameters.class), anyMap()))
.thenReturn(List.of(webElement));
Locator locator = new Locator(TestLocatorType.SEARCH, VALUE);
List<WebElement> foundElements = searchActions.findElements(searchContext, locator);
Expand All @@ -95,7 +92,7 @@ void testFindElementsByLocatorSingleAttribute()
@Test
void shouldFindElementsUsingLocatorAndUiContext()
{
when(testSearch.search(eq(searchContext), any(SearchParameters.class)))
when(testSearch.search(eq(searchContext), any(SearchParameters.class), anyMap()))
.thenReturn(List.of(webElement));
when(uiContext.getSearchContext()).thenReturn(searchContext);
Locator locator = new Locator(TestLocatorType.SEARCH, VALUE);
Expand All @@ -107,7 +104,7 @@ void shouldFindElementsUsingLocatorAndUiContext()
@Test
void shouldReturnEmptyOptionalIfNoElementFound()
{
when(testSearch.search(eq(searchContext), any(SearchParameters.class))).thenReturn(List.of());
when(testSearch.search(eq(searchContext), any(SearchParameters.class), anyMap())).thenReturn(List.of());
when(uiContext.getSearchContext()).thenReturn(searchContext);
Locator locator = new Locator(TestLocatorType.SEARCH, VALUE);
assertEquals(Optional.empty(), searchActions.findElement(locator));
Expand All @@ -119,7 +116,7 @@ void shouldReturnFirstElementIfFewFound()
{
WebElement element1 = mock(WebElement.class);
WebElement element2 = mock(WebElement.class);
when(testSearch.search(eq(searchContext), any(SearchParameters.class)))
when(testSearch.search(eq(searchContext), any(SearchParameters.class), anyMap()))
.thenReturn(List.of(element1, element2));
when(uiContext.getSearchContext()).thenReturn(searchContext);
Locator locator = new Locator(TestLocatorType.SEARCH, VALUE);
Expand All @@ -133,89 +130,14 @@ void shouldFindElementInSearchContext()
WebDriver webDriver = mock(WebDriver.class);
WebElement element = mock(WebElement.class);

when(testSearch.search(eq(webDriver), any(SearchParameters.class))).thenReturn(List.of(element));
when(testSearch.search(eq(webDriver), any(SearchParameters.class), anyMap())).thenReturn(List.of(element));

Locator locator = new Locator(TestLocatorType.SEARCH, VALUE);
assertEquals(Optional.of(element), searchActions.findElement(webDriver, locator));
verifyNoInteractions(uiContext, searchContext);
assertThat(logger.getLoggingEvents(), is(empty()));
}

@Test
void testFindElementsByLocatorSeveralAttributes()
{
List<WebElement> list = List.of(webElement);
when(testSearch.search(eq(searchContext), any(SearchParameters.class)))
.thenReturn(List.of(webElement));
when(((IElementFilterAction) testFilter).filter(List.of(webElement), VALUE)).thenReturn(list);
Locator locator = new Locator(TestLocatorType.SEARCH, VALUE)
.addFilter(TestLocatorType.FILTER, VALUE);
List<WebElement> foundElements = searchActions.findElements(searchContext, locator);
assertEquals(list, foundElements);
assertThat(logger.getLoggingEvents(),
equalTo(List.of(info(FILTER_MESSAGE, 0, 1, TestLocatorType.FILTER, VALUE))));
}

@Test
void shouldFindElementsAndFilter()
{
Locator locator = new Locator(TestLocatorType.SEARCH, VALUE);
String filterOne = "filter-one";
locator.addFilter(TestLocatorType.FILTER, filterOne);
String filterTwo = "filter-two";
locator.addFilter(TestLocatorType.FILTER, filterTwo);
String filterThree = "filter-three";
locator.addFilter(TestLocatorType.ADDITIONAL_FILTER, filterThree);
locator.addFilter(TestLocatorType.ADDITIONAL_FILTER, "filter-four");

WebElement element = mock(WebElement.class);
TestElementFilter additionalFilter = mock(TestElementFilter.class);

when(elementActionService.find(TestLocatorType.SEARCH)).thenReturn(testSearch);
when(elementActionService.find(TestLocatorType.FILTER)).thenReturn(testFilter);
when(elementActionService.find(TestLocatorType.ADDITIONAL_FILTER)).thenReturn(additionalFilter);
when(testSearch.search(searchContext, locator.getSearchParameters()))
.thenReturn(List.of(element, element, element));
when(testFilter.filter(List.of(element, element, element), filterOne))
.thenReturn(List.of(element, element, element));
when(testFilter.filter(List.of(element, element, element), filterTwo))
.thenReturn(List.of(element, element));
when(additionalFilter.filter(List.of(element, element), filterThree)).thenReturn(List.of());

assertEquals(List.of(), searchActions.findElements(searchContext, locator));

assertThat(logger.getLoggingEvents(), equalTo(List.of(
info(FILTER_MESSAGE, 0, 3, TestLocatorType.FILTER, filterOne),
info(FILTER_MESSAGE, 1, 3, TestLocatorType.FILTER, filterTwo),
info(FILTER_MESSAGE, 2, 2, TestLocatorType.ADDITIONAL_FILTER, filterThree)
)));
verifyNoMoreInteractions(testFilter, additionalFilter);
}

@Test
void testFindElementsWithChildrenSearchAndFilter()
{
TestElementSearch additionalTestSearch = mock(TestElementSearch.class);
when(elementActionService.find(TestLocatorType.ADDITIONAL_SEARCH))
.thenReturn(additionalTestSearch);
List<WebElement> webElements = new ArrayList<>();
webElements.add(webElement);
Locator locator = new Locator(TestLocatorType.SEARCH, VALUE);
Locator childAttributes = new Locator(TestLocatorType.ADDITIONAL_SEARCH,
VALUE);
childAttributes.addFilter(TestLocatorType.FILTER, VALUE);
locator.addChildLocator(childAttributes);
WebElement wrongElement = mock(WebElement.class);
webElements.add(wrongElement);
List<WebElement> list = List.of(webElement);
when(testSearch.search(eq(searchContext), any(SearchParameters.class))).thenReturn(webElements);
when(additionalTestSearch.search(eq(webElement), any(SearchParameters.class))).thenReturn(list);
when(((IElementFilterAction) testFilter).filter(list, VALUE)).thenReturn(list);
List<WebElement> foundElements = searchActions.findElements(searchContext, locator);
webElements.remove(wrongElement);
assertEquals(webElements, foundElements);
}

@Test
void testFindElementsWithChildrenEmptyResults()
{
Expand All @@ -228,8 +150,8 @@ void testFindElementsWithChildrenEmptyResults()
Locator childAttributes = new Locator(TestLocatorType.ADDITIONAL_SEARCH,
VALUE);
locator.addChildLocator(childAttributes);
when(testSearch.search(eq(searchContext), any(SearchParameters.class))).thenReturn(webElements);
when(additionalTestSearch.search(eq(webElement), any(SearchParameters.class))).thenReturn(List.of());
when(testSearch.search(eq(searchContext), any(SearchParameters.class), anyMap())).thenReturn(webElements);
when(additionalTestSearch.search(eq(webElement), any(SearchParameters.class), anyMap())).thenReturn(List.of());
List<WebElement> foundElements = searchActions.findElements(searchContext, locator);
assertEquals(List.of(), foundElements);
assertThat(logger.getLoggingEvents(), is(empty()));
Expand Down
Loading

0 comments on commit 638161c

Please sign in to comment.