Skip to content

Commit

Permalink
[plugin-mobile-app] Adjust vertical element position after swiping to…
Browse files Browse the repository at this point in the history
… it (#1267)
  • Loading branch information
uarlouski authored Dec 24, 2020
1 parent 67e6638 commit 4772861
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 20 deletions.
4 changes: 2 additions & 2 deletions docs/modules/plugins/pages/plugin-mobile-app.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ When I clear field located `accessibilityId(username)`

==== *_Info_*

Swipes to an element in either UP or DOWN direction with the specified duration
Swipes to an element in either UP or DOWN direction with the specified swipe duration

==== *_Wording_*

Expand All @@ -411,7 +411,7 @@ When I swipe $direction to element located `$locator` with duration $swipeDurati

. `$direction` - direction to swipe, either UP or DOWN
. `$locator` - <<_locator>>
. `$duration` - swipe duration in {iso-date-format-link} format
. `$swipeDuration` - swipe duration in {iso-date-format-link} format

==== *_Usage_*

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,30 @@
import org.vividus.bdd.steps.ui.validation.IBaseValidations;
import org.vividus.mobileapp.action.KeyboardActions;
import org.vividus.mobileapp.action.TouchActions;
import org.vividus.selenium.manager.GenericWebDriverManager;
import org.vividus.ui.action.ISearchActions;
import org.vividus.ui.action.search.Locator;

@TakeScreenshotOnFailure
public class TouchSteps
{
private static final float VISIBILITY_TOP_INDENT_COEFFICIENT = 0.15f;
private static final float VISIBILITY_BOTTOM_INDENT_COEFFICIENT = 0.25f;

private final TouchActions touchActions;
private final KeyboardActions keyboardActions;
private final IBaseValidations baseValidations;
private final ISearchActions searchActions;
private final GenericWebDriverManager genericWebDriverManager;

public TouchSteps(TouchActions touchActions, KeyboardActions keyboardActions, IBaseValidations baseValidations,
ISearchActions searchActions)
ISearchActions searchActions, GenericWebDriverManager genericWebDriverManager)
{
this.touchActions = touchActions;
this.keyboardActions = keyboardActions;
this.baseValidations = baseValidations;
this.searchActions = searchActions;
this.genericWebDriverManager = genericWebDriverManager;
}

/**
Expand Down Expand Up @@ -122,25 +128,51 @@ public void clearTextInField(Locator locator)
* Swipes to element in <b>direction</b> direction with duration <b>duration</b>
* @param direction direction to swipe, either <b>UP</b> or <b>DOWN</b>
* @param locator locator to find an element
* @param duration swipe duration in <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a> format
* @param swipeDuration swipe duration in <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a> format
*/
@When("I swipe $direction to element located `$locator` with duration $swipeDuration")
public void swipeToElement(SwipeDirection direction, Locator locator, Duration duration)
public void swipeToElement(SwipeDirection direction, Locator locator, Duration swipeDuration)
{
locator.getSearchParameters().setWaitForElement(false);

List<WebElement> elements = new ArrayList<>(searchActions.findElements(locator));
if (elements.isEmpty())
{
touchActions.swipeUntil(direction, duration, () ->
touchActions.swipeUntil(direction, swipeDuration, () ->
{
elements.addAll(searchActions.findElements(locator));
return !elements.isEmpty();
});
}

baseValidations.assertElementsNumber(String.format("The element by locator %s exists", locator), elements,
ComparisonRule.EQUAL_TO, 1);
if (baseValidations.assertElementsNumber(String.format("The element by locator %s exists", locator), elements,
ComparisonRule.EQUAL_TO, 1))
{
adjustVerticalPosition(elements.get(0), swipeDuration);
}
}

private void adjustVerticalPosition(WebElement element, Duration swipeDuration)
{
int windowSizeHeight = genericWebDriverManager.getSize().getHeight();
int windowCenterY = windowSizeHeight / 2;
int elementTopCoordinateY = element.getLocation().getY();

int bottomVisibilityIndent = (int) (VISIBILITY_BOTTOM_INDENT_COEFFICIENT * windowSizeHeight);
int visibilityY = windowSizeHeight - bottomVisibilityIndent;
if (elementTopCoordinateY > visibilityY)
{
touchActions.performVerticalSwipe(windowCenterY, windowCenterY - (elementTopCoordinateY - visibilityY),
swipeDuration);
return;
}

int topVisibilityIndent = (int) (VISIBILITY_TOP_INDENT_COEFFICIENT * windowSizeHeight);
if (elementTopCoordinateY < topVisibilityIndent)
{
touchActions.performVerticalSwipe(windowCenterY,
windowCenterY + topVisibilityIndent - elementTopCoordinateY, swipeDuration);
}
}

private Optional<WebElement> findElementToTap(Locator locator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public void swipeUntil(SwipeDirection direction, Duration swipeDuration, Boolean
BufferedImage previousFrame = null;
for (int count = 0; count <= swipeLimit; count++)
{
swipe(direction, swipeDuration);
swipe(direction.calculateCoordinates(genericWebDriverManager.getSize()), swipeDuration);
Sleeper.sleep(stabilizationDuration);
if (stopCondition.getAsBoolean())
{
Expand All @@ -154,6 +154,18 @@ public void swipeUntil(SwipeDirection direction, Duration swipeDuration, Boolean
}
}

/**
* Performs vertical swipe from <b>startY</b> to <b>endY</b> with <b>swipeDuration</b>
*
* @param startY start Y coordinate
* @param endY end Y coordinate
* @param swipeDuration swipe duration in <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a> format
*/
public void performVerticalSwipe(int startY, int endY, Duration swipeDuration)
{
swipe(new SwipeCoordinates(1, startY, 1, endY), swipeDuration);
}

private BufferedImage takeScreenshot()
{
try
Expand All @@ -166,11 +178,10 @@ private BufferedImage takeScreenshot()
}
}

private void swipe(SwipeDirection direction, Duration duration)
private void swipe(SwipeCoordinates coordinates, Duration swipeDuration)
{
SwipeCoordinates coordinates = direction.calculateCoordinates(genericWebDriverManager.getSize());
performAction(b -> b.press(point(coordinates.getStart()))
.waitAction(waitOptions(duration))
.waitAction(waitOptions(swipeDuration))
.moveTo(point(coordinates.getEnd()))
.release());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,13 @@ void shouldWrapIOException() throws IOException
verifyConfiguration();
}

@Test
void shouldPerformVerticalSwipe()
{
touchActions.performVerticalSwipe(640, 160, DURATION);
verifySwipe(1);
}

private void verifySwipe(int times)
{
verify(performsTouchActions, times(times))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

Expand All @@ -33,15 +34,20 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;
import org.vividus.bdd.mobileapp.model.SwipeDirection;
import org.vividus.bdd.steps.ComparisonRule;
import org.vividus.bdd.steps.ui.validation.IBaseValidations;
import org.vividus.mobileapp.action.KeyboardActions;
import org.vividus.mobileapp.action.TouchActions;
import org.vividus.selenium.manager.GenericWebDriverManager;
import org.vividus.ui.action.ISearchActions;
import org.vividus.ui.action.search.Locator;
import org.vividus.ui.action.search.SearchParameters;
Expand All @@ -58,6 +64,7 @@ class TouchStepsTests
@Mock private KeyboardActions keyboardActions;
@Mock private ISearchActions searchActions;
@Mock private Locator locator;
@Mock private GenericWebDriverManager genericWebDriverManager;
@InjectMocks private TouchSteps touchSteps;

@AfterEach
Expand Down Expand Up @@ -123,11 +130,18 @@ void shouldClearTextInField()
verify(keyboardActions).clearText(element);
}

@Test
void shouldSwipeToElement()
@ParameterizedTest
@CsvSource({
"138, 631",
"1154, 326"
})
void shouldSwipeToElement(int elementY, int endY)
{
SearchParameters parameters = initSwipeMocks();
mockScreenSize();
WebElement element = mock(WebElement.class);
mockAssertElementsNumber(List.of(element), true);
when(element.getLocation()).thenReturn(new Point(-1, elementY));
SearchParameters parameters = initSwipeMocks();

when(searchActions.findElements(locator)).thenReturn(new ArrayList<>())
.thenReturn(List.of())
Expand All @@ -144,21 +158,42 @@ void shouldSwipeToElement()
touchSteps.swipeToElement(SwipeDirection.UP, locator, Duration.ZERO);

verifyNoMoreInteractions(parameters);
verifyFoundElements(element);
verify(touchActions).performVerticalSwipe(592, endY, Duration.ZERO);
}

@Test
void shouldSwipeToElementToTryToFindItButThatDoesntExist()
{
mockAssertElementsNumber(List.of(), false);
initSwipeMocks();
when(searchActions.findElements(locator)).thenReturn(List.of());
doAnswer(a ->
{
BooleanSupplier condition = a.getArgument(2, BooleanSupplier.class);
condition.getAsBoolean();
return null;
}).when(touchActions).swipeUntil(eq(SwipeDirection.UP), eq(Duration.ZERO),
any(BooleanSupplier.class));

touchSteps.swipeToElement(SwipeDirection.UP, locator, Duration.ZERO);

verifyNoInteractions(genericWebDriverManager);
}

@Test
void shouldNotSwipeToElementIfItAlreadyExists()
{
mockScreenSize();
SearchParameters parameters = initSwipeMocks();
WebElement element = mock(WebElement.class);
when(element.getLocation()).thenReturn(new Point(-1, 500));
mockAssertElementsNumber(List.of(element), true);

when(searchActions.findElements(locator)).thenReturn(List.of(element));

touchSteps.swipeToElement(SwipeDirection.UP, locator, Duration.ZERO);

verifyNoMoreInteractions(parameters);
verifyFoundElements(element);
}

private SearchParameters initSwipeMocks()
Expand All @@ -169,9 +204,16 @@ private SearchParameters initSwipeMocks()
return parameters;
}

private void verifyFoundElements(WebElement element)
private void mockAssertElementsNumber(List<WebElement> elements, boolean result)
{
when(baseValidations.assertElementsNumber(String.format("The element by locator %s exists", locator),
elements, ComparisonRule.EQUAL_TO, 1)).thenReturn(result);
}

private void mockScreenSize()
{
verify(baseValidations).assertElementsNumber(String.format("The element by locator %s exists", locator),
List.of(element), ComparisonRule.EQUAL_TO, 1);
Dimension dimension = mock(Dimension.class);
when(dimension.getHeight()).thenReturn(1184);
when(genericWebDriverManager.getSize()).thenReturn(dimension);
}
}

0 comments on commit 4772861

Please sign in to comment.